Skip to content

Commit 25d3b8f

Browse files
committed
Copies from austinpray/kizuna and pkg for pypi
0 parents  commit 25d3b8f

File tree

9 files changed

+309
-0
lines changed

9 files changed

+309
-0
lines changed

.gitignore

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
### Python template
2+
# Byte-compiled / optimized / DLL files
3+
__pycache__/
4+
*.py[cod]
5+
*$py.class
6+
7+
# C extensions
8+
*.so
9+
10+
# Distribution / packaging
11+
.Python
12+
build/
13+
develop-eggs/
14+
dist/
15+
downloads/
16+
eggs/
17+
.eggs/
18+
lib/
19+
lib64/
20+
parts/
21+
sdist/
22+
var/
23+
wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.coverage
43+
.coverage.*
44+
.cache
45+
nosetests.xml
46+
coverage.xml
47+
*.cover
48+
.hypothesis/
49+
.pytest_cache/
50+
51+
# Translations
52+
*.mo
53+
*.pot
54+
55+
# Django stuff:
56+
*.log
57+
local_settings.py
58+
db.sqlite3
59+
60+
# Flask stuff:
61+
instance/
62+
.webassets-cache
63+
64+
# Scrapy stuff:
65+
.scrapy
66+
67+
# Sphinx documentation
68+
docs/_build/
69+
70+
# PyBuilder
71+
target/
72+
73+
# Jupyter Notebook
74+
.ipynb_checkpoints
75+
76+
# pyenv
77+
.python-version
78+
79+
# celery beat schedule file
80+
celerybeat-schedule
81+
82+
# SageMath parsed files
83+
*.sage.py
84+
85+
# Environments
86+
.env
87+
.venv
88+
env/
89+
venv/
90+
ENV/
91+
env.bak/
92+
venv.bak/
93+
94+
# Spyder project settings
95+
.spyderproject
96+
.spyproject
97+
98+
# Rope project settings
99+
.ropeproject
100+
101+
# mkdocs documentation
102+
/site
103+
104+
# mypy
105+
.mypy_cache/
106+

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 Austin Pray
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.PHONY: build publish
2+
3+
build:
4+
python setup.py sdist bdist_wheel
5+
6+
publish:
7+
twine upload dist/*

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# python-slacktools
2+
3+
A toolbelt for working with the [Slack][] APIs in python.
4+
5+
[Slack]: https://api.slack.com/

setup.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# -*- coding: utf-8 -*-
2+
from setuptools import setup, find_packages
3+
import io
4+
import os
5+
import re
6+
7+
8+
def read(*names, **kwargs):
9+
with io.open(
10+
os.path.join(os.path.dirname(__file__), *names),
11+
encoding=kwargs.get("encoding", "utf8")
12+
) as fp:
13+
return fp.read()
14+
15+
16+
long_description = read('README.md')
17+
18+
19+
def find_version(*file_paths):
20+
version_file = read(*file_paths)
21+
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M)
22+
if version_match:
23+
return version_match.group(1)
24+
raise RuntimeError("Unable to find version string.")
25+
26+
27+
setup(name='slacktools',
28+
version=find_version('slacktools', 'version.py'),
29+
description='Toolbelt for Slack API clients for Web API and RTM API',
30+
long_description=long_description,
31+
long_description_content_type="text/markdown",
32+
url='https://github.com/austinpray/python-slacktools',
33+
author='Austin Pray',
34+
author_email='[email protected]',
35+
license='MIT',
36+
classifiers=[
37+
#'Development Status :: 5 - Production/Stable',
38+
'Development Status :: 2 - Pre-Alpha',
39+
'Intended Audience :: Developers',
40+
'Topic :: Communications :: Chat',
41+
'Topic :: System :: Networking',
42+
'Topic :: Office/Business',
43+
'License :: OSI Approved :: MIT License',
44+
'Programming Language :: Python :: 3.6',
45+
'Programming Language :: Python :: 3.7',
46+
],
47+
keywords='slack slack-web slack-rtm slacktools chat chatbots bots chatops',
48+
packages=find_packages(exclude=['docs', 'tests']),
49+
install_requires=[
50+
# ayy
51+
])

slacktools/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .verify import verify_request

slacktools/slack.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import re
2+
from argparse import ArgumentParser
3+
from functools import partial
4+
5+
from kizuna.models import User
6+
7+
8+
def format_slack_mention(slack_id: str):
9+
return f"<@{slack_id}>"
10+
11+
12+
user_id_regex = '^<@(U[A-Za-z0-9]{8,})>$'
13+
14+
15+
def extract_mentions(text):
16+
return set(re.findall(r"<@(\S+)>", text, re.DOTALL))
17+
18+
19+
def get_user_id_from_mention(m: str):
20+
match = re.match(user_id_regex, m)
21+
if not match:
22+
return None
23+
24+
return match.group(1)
25+
26+
27+
def is_user_mention(s: str) -> bool:
28+
"""user mentions should be in format <@UXXXXXXXX>"""
29+
30+
if not s or not re.match(user_id_regex, s):
31+
return False
32+
33+
return True
34+
35+
36+
def send(slack_client, channel, text):
37+
return slack_client.api_call("chat.postMessage",
38+
channel=channel,
39+
text=text,
40+
as_user=True)
41+
42+
43+
def reply(slack_client, message, text):
44+
return slack_client.api_call("chat.postMessage",
45+
channel=message['channel'],
46+
text=f"{format_slack_mention(message['user'])} {text}",
47+
as_user=True)
48+
49+
50+
def send_factory(slack_client, channel):
51+
return partial(send, slack_client, channel)
52+
53+
54+
def send_ephemeral(slack_client, channel, user, text):
55+
if isinstance(user, User):
56+
user = user.slack_id
57+
58+
return slack_client.api_call("chat.postEphemeral",
59+
channel=channel,
60+
user=user,
61+
text=text,
62+
as_user=True)
63+
64+
65+
def send_ephemeral_factory(slack_client, channel, user):
66+
return partial(send_ephemeral, slack_client, channel, user)
67+
68+
69+
class SlackArgumentParserException(Exception):
70+
pass
71+
72+
73+
class SlackArgumentParser(ArgumentParser):
74+
def error(self, message):
75+
raise SlackArgumentParserException(message)
76+
77+
78+
def slack_link(text, url):
79+
return '<{}|{}>'.format(url, text)

slacktools/verify.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from time import time
2+
import hmac
3+
from hashlib import sha256
4+
5+
class SignatureVersionException(ValueError): pass
6+
7+
def verify_request(slack_signing_secret: str, timestamp: int, body: str, slack_signature: str):
8+
"""https://api.slack.com/docs/verifying-requests-from-slack"""
9+
10+
if not slack_signing_secret:
11+
raise ValueError('slack_signing_secret not provided')
12+
if not timestamp or not isinstance(timestamp, int):
13+
raise ValueError('timestamp is not good int')
14+
if not body:
15+
raise ValueError('body not provided')
16+
if not slack_signature:
17+
raise ValueError('signature not provided')
18+
if not slack_signature.startswith('v0'):
19+
raise SignatureVersionException(f"expected the signature to be version 'v0' but got '{slack_signature[:2]}'")
20+
21+
if abs(time() - timestamp) > 60 * 5:
22+
# The request timestamp is more than five minutes from local time.
23+
# It could be a replay attack, so let's ignore it.
24+
return False
25+
26+
sig_basestring = f"v0:{timestamp}:{body}"
27+
28+
my_signature = 'v0=' + hmac.new(
29+
slack_signing_secret.encode(),
30+
sig_basestring.encode(),
31+
sha256
32+
).hexdigest()
33+
34+
print(slack_signature)
35+
print(my_signature)
36+
37+
return hmac.compare_digest(my_signature, slack_signature)

slacktools/version.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# see: http://legacy.python.org/dev/peps/pep-0440/#public-version-identifiers
2+
__version__ = '0.0.2'

0 commit comments

Comments
 (0)