Initial commit
This commit is contained in:
commit
bcb5faa2be
|
@ -0,0 +1,8 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
insert_final_newline = false
|
|
@ -0,0 +1,142 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# Project specific
|
||||||
|
credentials.json
|
||||||
|
store/*
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"python.pythonPath": "/home/odie/.virtualenvs/matrix-bot-fiY9M2m2/bin/python",
|
||||||
|
"python.linting.flake8Enabled": true,
|
||||||
|
"python.linting.enabled": true,
|
||||||
|
"python.linting.pylintEnabled": false,
|
||||||
|
"python.formatting.provider": "yapf",
|
||||||
|
"python.formatting.blackArgs": ["-l 79"]
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
[[source]]
|
||||||
|
name = "pypi"
|
||||||
|
url = "https://pypi.org/simple"
|
||||||
|
verify_ssl = true
|
||||||
|
|
||||||
|
[dev-packages]
|
||||||
|
flake8 = "*"
|
||||||
|
flake8-quotes = "*"
|
||||||
|
flake8-annotations = "*"
|
||||||
|
black = "*"
|
||||||
|
yapf = "*"
|
||||||
|
|
||||||
|
[packages]
|
||||||
|
matrix-bot = {editable = true, path = "."}
|
||||||
|
|
||||||
|
[requires]
|
||||||
|
python_version = "3.8"
|
||||||
|
|
||||||
|
[pipenv]
|
||||||
|
allow_prereleases = true
|
|
@ -0,0 +1,486 @@
|
||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"hash": {
|
||||||
|
"sha256": "b572da4f2fb6963d3f61a7a2234f625fd8c09274e429df366367fb4b359510a0"
|
||||||
|
},
|
||||||
|
"pipfile-spec": 6,
|
||||||
|
"requires": {
|
||||||
|
"python_version": "3.8"
|
||||||
|
},
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"name": "pypi",
|
||||||
|
"url": "https://pypi.org/simple",
|
||||||
|
"verify_ssl": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"aiofiles": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:021ea0ba314a86027c166ecc4b4c07f2d40fc0f4b3a950d1868a0f2571c2bbee",
|
||||||
|
"sha256:1e644c2573f953664368de28d2aa4c89dfd64550429d0c27c4680ccd3aa4985d"
|
||||||
|
],
|
||||||
|
"version": "==0.4.0"
|
||||||
|
},
|
||||||
|
"aiohttp": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1e984191d1ec186881ffaed4581092ba04f7c61582a177b187d3a2f07ed9719e",
|
||||||
|
"sha256:259ab809ff0727d0e834ac5e8a283dc5e3e0ecc30c4d80b3cd17a4139ce1f326",
|
||||||
|
"sha256:2f4d1a4fdce595c947162333353d4a44952a724fba9ca3205a3df99a33d1307a",
|
||||||
|
"sha256:32e5f3b7e511aa850829fbe5aa32eb455e5534eaa4b1ce93231d00e2f76e5654",
|
||||||
|
"sha256:344c780466b73095a72c616fac5ea9c4665add7fc129f285fbdbca3cccf4612a",
|
||||||
|
"sha256:460bd4237d2dbecc3b5ed57e122992f60188afe46e7319116da5eb8a9dfedba4",
|
||||||
|
"sha256:4c6efd824d44ae697814a2a85604d8e992b875462c6655da161ff18fd4f29f17",
|
||||||
|
"sha256:50aaad128e6ac62e7bf7bd1f0c0a24bc968a0c0590a726d5a955af193544bcec",
|
||||||
|
"sha256:6206a135d072f88da3e71cc501c59d5abffa9d0bb43269a6dcd28d66bfafdbdd",
|
||||||
|
"sha256:65f31b622af739a802ca6fd1a3076fd0ae523f8485c52924a89561ba10c49b48",
|
||||||
|
"sha256:ae55bac364c405caa23a4f2d6cfecc6a0daada500274ffca4a9230e7129eac59",
|
||||||
|
"sha256:b778ce0c909a2653741cb4b1ac7015b5c130ab9c897611df43ae6a58523cb965"
|
||||||
|
],
|
||||||
|
"markers": "python_full_version >= '3.5.3'",
|
||||||
|
"version": "==3.6.2"
|
||||||
|
},
|
||||||
|
"async-timeout": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
||||||
|
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
||||||
|
],
|
||||||
|
"markers": "python_full_version >= '3.5.3'",
|
||||||
|
"version": "==3.0.1"
|
||||||
|
},
|
||||||
|
"atomicwrites": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197",
|
||||||
|
"sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"
|
||||||
|
],
|
||||||
|
"version": "==1.4.0"
|
||||||
|
},
|
||||||
|
"attrs": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
|
||||||
|
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==19.3.0"
|
||||||
|
},
|
||||||
|
"cachetools": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:513d4ff98dd27f85743a8dc0e92f55ddb1b49e060c2d5961512855cda2c01a98",
|
||||||
|
"sha256:bbaa39c3dede00175df2dc2b03d0cf18dd2d32a7de7beb68072d13043c9edb20"
|
||||||
|
],
|
||||||
|
"version": "==4.1.1"
|
||||||
|
},
|
||||||
|
"cffi": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:267adcf6e68d77ba154334a3e4fc921b8e63cbb38ca00d33d40655d4228502bc",
|
||||||
|
"sha256:26f33e8f6a70c255767e3c3f957ccafc7f1f706b966e110b855bfe944511f1f9",
|
||||||
|
"sha256:3cd2c044517f38d1b577f05927fb9729d3396f1d44d0c659a445599e79519792",
|
||||||
|
"sha256:4a03416915b82b81af5502459a8a9dd62a3c299b295dcdf470877cb948d655f2",
|
||||||
|
"sha256:4ce1e995aeecf7cc32380bc11598bfdfa017d592259d5da00fc7ded11e61d022",
|
||||||
|
"sha256:4f53e4128c81ca3212ff4cf097c797ab44646a40b42ec02a891155cd7a2ba4d8",
|
||||||
|
"sha256:4fa72a52a906425416f41738728268072d5acfd48cbe7796af07a923236bcf96",
|
||||||
|
"sha256:66dd45eb9530e3dde8f7c009f84568bc7cac489b93d04ac86e3111fb46e470c2",
|
||||||
|
"sha256:6923d077d9ae9e8bacbdb1c07ae78405a9306c8fd1af13bfa06ca891095eb995",
|
||||||
|
"sha256:833401b15de1bb92791d7b6fb353d4af60dc688eaa521bd97203dcd2d124a7c1",
|
||||||
|
"sha256:8416ed88ddc057bab0526d4e4e9f3660f614ac2394b5e019a628cdfff3733849",
|
||||||
|
"sha256:892daa86384994fdf4856cb43c93f40cbe80f7f95bb5da94971b39c7f54b3a9c",
|
||||||
|
"sha256:98be759efdb5e5fa161e46d404f4e0ce388e72fbf7d9baf010aff16689e22abe",
|
||||||
|
"sha256:a6d28e7f14ecf3b2ad67c4f106841218c8ab12a0683b1528534a6c87d2307af3",
|
||||||
|
"sha256:b1d6ebc891607e71fd9da71688fcf332a6630b7f5b7f5549e6e631821c0e5d90",
|
||||||
|
"sha256:b2a2b0d276a136146e012154baefaea2758ef1f56ae9f4e01c612b0831e0bd2f",
|
||||||
|
"sha256:b87dfa9f10a470eee7f24234a37d1d5f51e5f5fa9eeffda7c282e2b8f5162eb1",
|
||||||
|
"sha256:bac0d6f7728a9cc3c1e06d4fcbac12aaa70e9379b3025b27ec1226f0e2d404cf",
|
||||||
|
"sha256:c991112622baee0ae4d55c008380c32ecfd0ad417bcd0417ba432e6ba7328caa",
|
||||||
|
"sha256:cda422d54ee7905bfc53ee6915ab68fe7b230cacf581110df4272ee10462aadc",
|
||||||
|
"sha256:d3148b6ba3923c5850ea197a91a42683f946dba7e8eb82dfa211ab7e708de939",
|
||||||
|
"sha256:d6033b4ffa34ef70f0b8086fd4c3df4bf801fee485a8a7d4519399818351aa8e",
|
||||||
|
"sha256:ddff0b2bd7edcc8c82d1adde6dbbf5e60d57ce985402541cd2985c27f7bec2a0",
|
||||||
|
"sha256:e23cb7f1d8e0f93addf0cae3c5b6f00324cccb4a7949ee558d7b6ca973ab8ae9",
|
||||||
|
"sha256:effd2ba52cee4ceff1a77f20d2a9f9bf8d50353c854a282b8760ac15b9833168",
|
||||||
|
"sha256:f90c2267101010de42f7273c94a1f026e56cbc043f9330acd8a80e64300aba33",
|
||||||
|
"sha256:f960375e9823ae6a07072ff7f8a85954e5a6434f97869f50d0e41649a1c8144f",
|
||||||
|
"sha256:fcf32bf76dc25e30ed793145a57426064520890d7c02866eb93d3e4abe516948"
|
||||||
|
],
|
||||||
|
"version": "==1.14.1"
|
||||||
|
},
|
||||||
|
"chardet": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||||
|
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||||
|
],
|
||||||
|
"version": "==3.0.4"
|
||||||
|
},
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||||
|
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
|
"version": "==7.1.2"
|
||||||
|
},
|
||||||
|
"future": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==0.18.2"
|
||||||
|
},
|
||||||
|
"h11": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:33d4bca7be0fa039f4e84d50ab00531047e53d6ee8ffbc83501ea602c169cae1",
|
||||||
|
"sha256:4bc6d6a1238b7615b266ada57e0618568066f57dd6fa967d1290ec9309b2f2f1"
|
||||||
|
],
|
||||||
|
"version": "==0.9.0"
|
||||||
|
},
|
||||||
|
"h2": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:61e0f6601fa709f35cdb730863b4e5ec7ad449792add80d1410d4174ed139af5",
|
||||||
|
"sha256:875f41ebd6f2c44781259005b157faed1a5031df3ae5aa7bcb4628a6c0782f14"
|
||||||
|
],
|
||||||
|
"version": "==3.2.0"
|
||||||
|
},
|
||||||
|
"hpack": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0edd79eda27a53ba5be2dfabf3b15780928a0dff6eb0c60a3d6767720e970c89",
|
||||||
|
"sha256:8eec9c1f4bfae3408a3f30500261f7e6a65912dc138526ea054f9ad98892e9d2"
|
||||||
|
],
|
||||||
|
"version": "==3.0.0"
|
||||||
|
},
|
||||||
|
"hyperframe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:5187962cb16dcc078f23cb5a4b110098d546c3f41ff2d4038a9896893bbd0b40",
|
||||||
|
"sha256:a9f5c17f2cc3c719b917c4f33ed1c61bd1f8dfac4b1bd23b7c80b3400971b41f"
|
||||||
|
],
|
||||||
|
"version": "==5.2.0"
|
||||||
|
},
|
||||||
|
"idna": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6",
|
||||||
|
"sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==2.10"
|
||||||
|
},
|
||||||
|
"jsonschema": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163",
|
||||||
|
"sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"
|
||||||
|
],
|
||||||
|
"version": "==3.2.0"
|
||||||
|
},
|
||||||
|
"logbook": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0cf2cdbfb65a03b5987d19109dacad13417809dcf697f66e1a7084fb21744ea9",
|
||||||
|
"sha256:2dc85f1510533fddb481e97677bb7bca913560862734c0b3b289bfed04f78c92",
|
||||||
|
"sha256:56ee54c11df3377314cedcd6507638f015b4b88c0238c2e01b5eb44fd3a6ad1b",
|
||||||
|
"sha256:66f454ada0f56eae43066f604a222b09893f98c1adc18df169710761b8f32fe8",
|
||||||
|
"sha256:7c533eb728b3d220b1b5414ba4635292d149d79f74f6973b4aa744c850ca944a",
|
||||||
|
"sha256:8f76a2e7b1f72595f753228732f81ce342caf03babc3fed6bbdcf366f2f20f18",
|
||||||
|
"sha256:94e2e11ff3c2304b0d09a36c6208e5ae756eb948b210e5cbd63cd8d27f911542",
|
||||||
|
"sha256:97fee1bd9605f76335b169430ed65e15e457a844b2121bd1d90a08cf7e30aba0",
|
||||||
|
"sha256:e18f7422214b1cf0240c56f884fd9c9b4ff9d0da2eabca9abccba56df7222f66"
|
||||||
|
],
|
||||||
|
"version": "==1.5.3"
|
||||||
|
},
|
||||||
|
"markdown": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1fafe3f1ecabfb514a5285fca634a53c1b32a81cb0feb154264d55bf2ff22c17",
|
||||||
|
"sha256:c467cd6233885534bf0fe96e62e3cf46cfc1605112356c4f9981512b8174de59"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
|
"version": "==3.2.2"
|
||||||
|
},
|
||||||
|
"matrix-bot": {
|
||||||
|
"editable": true,
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
"matrix-nio": {
|
||||||
|
"extras": [
|
||||||
|
"e2e"
|
||||||
|
],
|
||||||
|
"hashes": [
|
||||||
|
"sha256:8200c07a7584046681222c975aeada8b909c4a09becbccc003e6fd47b9464393",
|
||||||
|
"sha256:c5c45824ac127f550ffdc98241bf5aa1e26d8bdb5835ad36509fec27a08701b0"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.6' and python_version < '4.0'",
|
||||||
|
"version": "==0.14.1"
|
||||||
|
},
|
||||||
|
"multidict": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1ece5a3369835c20ed57adadc663400b5525904e53bae59ec854a5d36b39b21a",
|
||||||
|
"sha256:275ca32383bc5d1894b6975bb4ca6a7ff16ab76fa622967625baeebcf8079000",
|
||||||
|
"sha256:3750f2205b800aac4bb03b5ae48025a64e474d2c6cc79547988ba1d4122a09e2",
|
||||||
|
"sha256:4538273208e7294b2659b1602490f4ed3ab1c8cf9dbdd817e0e9db8e64be2507",
|
||||||
|
"sha256:5141c13374e6b25fe6bf092052ab55c0c03d21bd66c94a0e3ae371d3e4d865a5",
|
||||||
|
"sha256:51a4d210404ac61d32dada00a50ea7ba412e6ea945bbe992e4d7a595276d2ec7",
|
||||||
|
"sha256:5cf311a0f5ef80fe73e4f4c0f0998ec08f954a6ec72b746f3c179e37de1d210d",
|
||||||
|
"sha256:6513728873f4326999429a8b00fc7ceddb2509b01d5fd3f3be7881a257b8d463",
|
||||||
|
"sha256:7388d2ef3c55a8ba80da62ecfafa06a1c097c18032a501ffd4cabbc52d7f2b19",
|
||||||
|
"sha256:9456e90649005ad40558f4cf51dbb842e32807df75146c6d940b6f5abb4a78f3",
|
||||||
|
"sha256:c026fe9a05130e44157b98fea3ab12969e5b60691a276150db9eda71710cd10b",
|
||||||
|
"sha256:d14842362ed4cf63751648e7672f7174c9818459d169231d03c56e84daf90b7c",
|
||||||
|
"sha256:e0d072ae0f2a179c375f67e3da300b47e1a83293c554450b29c900e50afaae87",
|
||||||
|
"sha256:f07acae137b71af3bb548bd8da720956a3bc9f9a0b87733e0899226a2317aeb7",
|
||||||
|
"sha256:fbb77a75e529021e7c4a8d4e823d88ef4d23674a202be4f5addffc72cbb91430",
|
||||||
|
"sha256:fcfbb44c59af3f8ea984de67ec7c306f618a3ec771c2843804069917a8f2e255",
|
||||||
|
"sha256:feed85993dbdb1dbc29102f50bca65bdc68f2c0c8d352468c25b54874f23c39d"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
|
"version": "==4.7.6"
|
||||||
|
},
|
||||||
|
"peewee": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1269a9736865512bd4056298003aab190957afe07d2616cf22eaf56cb6398369"
|
||||||
|
],
|
||||||
|
"version": "==3.13.3"
|
||||||
|
},
|
||||||
|
"pycparser": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0",
|
||||||
|
"sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==2.20"
|
||||||
|
},
|
||||||
|
"pycryptodome": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:02e51e1d5828d58f154896ddfd003e2e7584869c275e5acbe290443575370fba",
|
||||||
|
"sha256:03d5cca8618620f45fd40f827423f82b86b3a202c8d44108601b0f5f56b04299",
|
||||||
|
"sha256:0e24171cf01021bc5dc17d6a9d4f33a048f09d62cc3f62541e95ef104588bda4",
|
||||||
|
"sha256:132a56abba24e2e06a479d8e5db7a48271a73a215f605017bbd476d31f8e71c1",
|
||||||
|
"sha256:1e655746f539421d923fd48df8f6f40b3443d80b75532501c0085b64afed9df5",
|
||||||
|
"sha256:2b998dc45ef5f4e5cf5248a6edfcd8d8e9fb5e35df8e4259b13a1b10eda7b16b",
|
||||||
|
"sha256:360955eece2cd0fa694a708d10303c6abd7b39614fa2547b6bd245da76198beb",
|
||||||
|
"sha256:39ef9fb52d6ec7728fce1f1693cb99d60ce302aeebd59bcedea70ca3203fda60",
|
||||||
|
"sha256:4350a42028240c344ee855f032c7d4ad6ff4f813bfbe7121547b7dc579ecc876",
|
||||||
|
"sha256:50348edd283afdccddc0938cdc674484533912ba8a99a27c7bfebb75030aa856",
|
||||||
|
"sha256:54bdedd28476dea8a3cd86cb67c0df1f0e3d71cae8022354b0f879c41a3d27b2",
|
||||||
|
"sha256:55eb61aca2c883db770999f50d091ff7c14016f2769ad7bca3d9b75d1d7c1b68",
|
||||||
|
"sha256:6276478ada411aca97c0d5104916354b3d740d368407912722bd4d11aa9ee4c2",
|
||||||
|
"sha256:67dcad1b8b201308586a8ca2ffe89df1e4f731d5a4cdd0610cc4ea790351c739",
|
||||||
|
"sha256:709b9f144d23e290b9863121d1ace14a72e01f66ea9c903fbdc690520dfdfcf0",
|
||||||
|
"sha256:8063a712fba642f78d3c506b0896846601b6de7f5c3d534e388ad0cc07f5a149",
|
||||||
|
"sha256:80d57177a0b7c14d4594c62bbb47fe2f6309ad3b0a34348a291d570925c97a82",
|
||||||
|
"sha256:a207231a52426de3ff20f5608f0687261a3329d97a036c51f7d4c606a6f30c23",
|
||||||
|
"sha256:abc2e126c9490e58a36a0f83516479e781d83adfb134576a5cbe5c6af2a3e93c",
|
||||||
|
"sha256:b56638d58a3a4be13229c6a815cd448f9e3ce40c00880a5398471b42ee86f50e",
|
||||||
|
"sha256:bcd5b8416e73e4b0d48afba3704d8c826414764dafaed7a1a93c442188d90ccc",
|
||||||
|
"sha256:bec2bcdf7c9ce7f04d718e51887f3b05dc5c1cfaf5d2c2e9065ecddd1b2f6c9a",
|
||||||
|
"sha256:c8bf40cf6e281a4378e25846924327e728a887e8bf0ee83b2604a0f4b61692e8",
|
||||||
|
"sha256:d8074c8448cfd0705dfa71ca333277fce9786d0b9cac75d120545de6253f996a",
|
||||||
|
"sha256:dd302b6ae3965afeb5ef1b0d92486f986c0e65183cd7835973f0b593800590e6",
|
||||||
|
"sha256:de6e1cd75677423ff64712c337521e62e3a7a4fc84caabbd93207752e831a85a",
|
||||||
|
"sha256:ef39c98d9b8c0736d91937d193653e47c3b19ddf4fc3bccdc5e09aaa4b0c5d21",
|
||||||
|
"sha256:f521178e5a991ffd04182ed08f552daca1affcb826aeda0e1945cd989a9d4345",
|
||||||
|
"sha256:f78a68c2c820e4731e510a2df3eef0322f24fde1781ced970bf497b6c7d92982",
|
||||||
|
"sha256:fbe65d5cfe04ff2f7684160d50f5118bdefb01e3af4718eeb618bfed40f19d94"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==3.9.8"
|
||||||
|
},
|
||||||
|
"pyrsistent": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:28669905fe725965daa16184933676547c5bb40a5153055a8dee2a4bd7933ad3"
|
||||||
|
],
|
||||||
|
"version": "==0.16.0"
|
||||||
|
},
|
||||||
|
"python-olm": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:9a6c6133ce3777788c88e3f18b13c5b36a2f76ed1a0e774d1a48adf542fee871"
|
||||||
|
],
|
||||||
|
"version": "==3.1.3"
|
||||||
|
},
|
||||||
|
"six": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259",
|
||||||
|
"sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==1.15.0"
|
||||||
|
},
|
||||||
|
"unpaddedbase64": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:81cb4eaaa28cc6a282dd3f2c3855eaa1fbaafa736b5ee64df69889e20540a339",
|
||||||
|
"sha256:8917367e4e915b7dce1a72a99db8798c9f3d0d9a74cdd9aafac6d7c65ca495c5"
|
||||||
|
],
|
||||||
|
"version": "==1.1.0"
|
||||||
|
},
|
||||||
|
"yarl": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:040b237f58ff7d800e6e0fd89c8439b841f777dd99b4a9cca04d6935564b9409",
|
||||||
|
"sha256:17668ec6722b1b7a3a05cc0167659f6c95b436d25a36c2d52db0eca7d3f72593",
|
||||||
|
"sha256:3a584b28086bc93c888a6c2aa5c92ed1ae20932f078c46509a66dce9ea5533f2",
|
||||||
|
"sha256:4439be27e4eee76c7632c2427ca5e73703151b22cae23e64adb243a9c2f565d8",
|
||||||
|
"sha256:48e918b05850fffb070a496d2b5f97fc31d15d94ca33d3d08a4f86e26d4e7c5d",
|
||||||
|
"sha256:9102b59e8337f9874638fcfc9ac3734a0cfadb100e47d55c20d0dc6087fb4692",
|
||||||
|
"sha256:9b930776c0ae0c691776f4d2891ebc5362af86f152dd0da463a6614074cb1b02",
|
||||||
|
"sha256:b3b9ad80f8b68519cc3372a6ca85ae02cc5a8807723ac366b53c0f089db19e4a",
|
||||||
|
"sha256:bc2f976c0e918659f723401c4f834deb8a8e7798a71be4382e024bcc3f7e23a8",
|
||||||
|
"sha256:c22c75b5f394f3d47105045ea551e08a3e804dc7e01b37800ca35b58f856c3d6",
|
||||||
|
"sha256:c52ce2883dc193824989a9b97a76ca86ecd1fa7955b14f87bf367a61b6232511",
|
||||||
|
"sha256:ce584af5de8830d8701b8979b18fcf450cef9a382b1a3c8ef189bedc408faf1e",
|
||||||
|
"sha256:da456eeec17fa8aa4594d9a9f27c0b1060b6a75f2419fe0c00609587b2695f4a",
|
||||||
|
"sha256:db6db0f45d2c63ddb1a9d18d1b9b22f308e52c83638c26b422d520a815c4b3fb",
|
||||||
|
"sha256:df89642981b94e7db5596818499c4b2219028f2a528c9c37cc1de45bf2fd3a3f",
|
||||||
|
"sha256:f18d68f2be6bf0e89f1521af2b1bb46e66ab0018faafa81d70f358153170a317",
|
||||||
|
"sha256:f379b7f83f23fe12823085cd6b906edc49df969eb99757f58ff382349a3303c6"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '3.5'",
|
||||||
|
"version": "==1.5.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"develop": {
|
||||||
|
"appdirs": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
|
||||||
|
"sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
|
||||||
|
],
|
||||||
|
"version": "==1.4.4"
|
||||||
|
},
|
||||||
|
"attrs": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c",
|
||||||
|
"sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==19.3.0"
|
||||||
|
},
|
||||||
|
"black": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b",
|
||||||
|
"sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==19.10b0"
|
||||||
|
},
|
||||||
|
"click": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
|
||||||
|
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||||
|
"version": "==7.1.2"
|
||||||
|
},
|
||||||
|
"flake8": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:15e351d19611c887e482fb960eae4d44845013cc142d42896e9862f775d8cf5c",
|
||||||
|
"sha256:f04b9fcbac03b0a3e58c0ab3a0ecc462e023a9faf046d57794184028123aa208"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.8.3"
|
||||||
|
},
|
||||||
|
"flake8-annotations": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7816a5d8f65ffdf37b8e21e5b17e0fd1e492aa92638573276de066e889a22b26",
|
||||||
|
"sha256:8d18db74a750dd97f40b483cc3ef80d07d03f687525bad8fd83365dcd3bfd414"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==2.3.0"
|
||||||
|
},
|
||||||
|
"flake8-quotes": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3f1116e985ef437c130431ac92f9b3155f8f652fda7405ac22ffdfd7a9d1055e"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==3.2.0"
|
||||||
|
},
|
||||||
|
"mccabe": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||||
|
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||||
|
],
|
||||||
|
"version": "==0.6.1"
|
||||||
|
},
|
||||||
|
"pathspec": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0",
|
||||||
|
"sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"
|
||||||
|
],
|
||||||
|
"version": "==0.8.0"
|
||||||
|
},
|
||||||
|
"pycodestyle": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:2295e7b2f6b5bd100585ebcb1f616591b652db8a741695b3d8f5d28bdc934367",
|
||||||
|
"sha256:c58a7d2815e0e8d7972bf1803331fb0152f867bd89adf8a01dfd55085434192e"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==2.6.0"
|
||||||
|
},
|
||||||
|
"pyflakes": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0d94e0e05a19e57a99444b6ddcf9a6eb2e5c68d3ca1e98e90707af8152c90a92",
|
||||||
|
"sha256:35b2d75ee967ea93b55750aa9edbbf72813e06a66ba54438df2cfac9e3c27fc8"
|
||||||
|
],
|
||||||
|
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||||
|
"version": "==2.2.0"
|
||||||
|
},
|
||||||
|
"regex": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0dc64ee3f33cd7899f79a8d788abfbec168410be356ed9bd30bbd3f0a23a7204",
|
||||||
|
"sha256:1269fef3167bb52631ad4fa7dd27bf635d5a0790b8e6222065d42e91bede4162",
|
||||||
|
"sha256:14a53646369157baa0499513f96091eb70382eb50b2c82393d17d7ec81b7b85f",
|
||||||
|
"sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb",
|
||||||
|
"sha256:46bac5ca10fb748d6c55843a931855e2727a7a22584f302dd9bb1506e69f83f6",
|
||||||
|
"sha256:4c037fd14c5f4e308b8370b447b469ca10e69427966527edcab07f52d88388f7",
|
||||||
|
"sha256:51178c738d559a2d1071ce0b0f56e57eb315bcf8f7d4cf127674b533e3101f88",
|
||||||
|
"sha256:5ea81ea3dbd6767873c611687141ec7b06ed8bab43f68fad5b7be184a920dc99",
|
||||||
|
"sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644",
|
||||||
|
"sha256:75aaa27aa521a182824d89e5ab0a1d16ca207318a6b65042b046053cfc8ed07a",
|
||||||
|
"sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840",
|
||||||
|
"sha256:8a51f2c6d1f884e98846a0a9021ff6861bdb98457879f412fdc2b42d14494067",
|
||||||
|
"sha256:9c568495e35599625f7b999774e29e8d6b01a6fb684d77dee1f56d41b11b40cd",
|
||||||
|
"sha256:9eddaafb3c48e0900690c1727fba226c4804b8e6127ea409689c3bb492d06de4",
|
||||||
|
"sha256:bbb332d45b32df41200380fff14712cb6093b61bd142272a10b16778c418e98e",
|
||||||
|
"sha256:bc3d98f621898b4a9bc7fecc00513eec8f40b5b83913d74ccb445f037d58cd89",
|
||||||
|
"sha256:c11d6033115dc4887c456565303f540c44197f4fc1a2bfb192224a301534888e",
|
||||||
|
"sha256:c50a724d136ec10d920661f1442e4a8b010a4fe5aebd65e0c2241ea41dbe93dc",
|
||||||
|
"sha256:d0a5095d52b90ff38592bbdc2644f17c6d495762edf47d876049cfd2968fbccf",
|
||||||
|
"sha256:d6cff2276e502b86a25fd10c2a96973fdb45c7a977dca2138d661417f3728341",
|
||||||
|
"sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"
|
||||||
|
],
|
||||||
|
"version": "==2020.7.14"
|
||||||
|
},
|
||||||
|
"toml": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f",
|
||||||
|
"sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"
|
||||||
|
],
|
||||||
|
"version": "==0.10.1"
|
||||||
|
},
|
||||||
|
"typed-ast": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355",
|
||||||
|
"sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919",
|
||||||
|
"sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa",
|
||||||
|
"sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652",
|
||||||
|
"sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75",
|
||||||
|
"sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01",
|
||||||
|
"sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d",
|
||||||
|
"sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1",
|
||||||
|
"sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907",
|
||||||
|
"sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c",
|
||||||
|
"sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3",
|
||||||
|
"sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b",
|
||||||
|
"sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614",
|
||||||
|
"sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb",
|
||||||
|
"sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b",
|
||||||
|
"sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41",
|
||||||
|
"sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6",
|
||||||
|
"sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34",
|
||||||
|
"sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe",
|
||||||
|
"sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4",
|
||||||
|
"sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"
|
||||||
|
],
|
||||||
|
"version": "==1.4.1"
|
||||||
|
},
|
||||||
|
"yapf": {
|
||||||
|
"hashes": [
|
||||||
|
"sha256:3000abee4c28daebad55da6c85f3cd07b8062ce48e2e9943c8da1b9667d48427",
|
||||||
|
"sha256:3abf61ba67cf603069710d30acbc88cfe565d907e16ad81429ae90ce9651e0c9"
|
||||||
|
],
|
||||||
|
"index": "pypi",
|
||||||
|
"version": "==0.30.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Matrix Bot
|
||||||
|
|
||||||
|
Uses [matrix-nio](https://github.com/poljar/matrix-nio/)
|
||||||
|
|
||||||
|
Requires libolm to be installed. in Debian this is done with `apt install libolm-dev`
|
||||||
|
|
||||||
|
## Requiements
|
||||||
|
|
||||||
|
- Python 3.8
|
||||||
|
- libolm
|
||||||
|
|
||||||
|
## Intallation
|
||||||
|
|
||||||
|
Clone this repo
|
||||||
|
|
||||||
|
git clone https://git.gaja-group.com/gaja-group/matrix-bot MATRIX_BOT_DIR
|
||||||
|
|
||||||
|
Create a virtualenv
|
||||||
|
|
||||||
|
cd MATRIX_BOT_DIR
|
||||||
|
virtualenv -p python3 venv
|
||||||
|
source MATIRX_BOT_DIR/venv/bin/activate
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Before you can send encrypted messages you must verify the bot with the matrix homeserver. To to login and do this use `matrix-bot verify`
|
||||||
|
|
||||||
|
source MATIRX_BOT_DIR/venv/bin/activate
|
||||||
|
cd
|
||||||
|
matrix-bot verify
|
||||||
|
|
||||||
|
After that you can begin sending messages
|
||||||
|
|
||||||
|
source MATIRX_BOT_DIR/venv/bin/activate
|
||||||
|
cd
|
||||||
|
matrix-bot message "Message Content" # To send to the default room
|
||||||
|
matrix-bot message -r '!yourRoomId' "Message Content" # To send to a specific room
|
|
@ -0,0 +1,490 @@
|
||||||
|
from nio import (
|
||||||
|
AsyncClient,
|
||||||
|
AsyncClientConfig,
|
||||||
|
LoginResponse,
|
||||||
|
KeyVerificationEvent,
|
||||||
|
KeyVerificationStart,
|
||||||
|
KeyVerificationCancel,
|
||||||
|
KeyVerificationKey,
|
||||||
|
KeyVerificationMac,
|
||||||
|
ToDeviceError,
|
||||||
|
LocalProtocolError,
|
||||||
|
)
|
||||||
|
import click
|
||||||
|
import traceback
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import asyncio
|
||||||
|
import signal
|
||||||
|
|
||||||
|
# The directory containing the store and credentials file
|
||||||
|
CONFIG_DIRECTORY = '.'
|
||||||
|
# file to store credentials in case you want to run program multiple times
|
||||||
|
# login credentials JSON file
|
||||||
|
CONFIG_FILE = os.path.join(CONFIG_DIRECTORY, 'credentials.json')
|
||||||
|
# directory to store persistent data for end-to-end encryption
|
||||||
|
STORE_PATH = os.path.join(CONFIG_DIRECTORY, 'store') # local directory
|
||||||
|
|
||||||
|
# Default Homeserver URL
|
||||||
|
HOMESERVER_URL = 'https://matrix.gaja-group.com'
|
||||||
|
|
||||||
|
|
||||||
|
def write_details_to_disk(resp: LoginResponse, credentials: dict) -> None:
|
||||||
|
"""Write the required login details to disk.
|
||||||
|
|
||||||
|
It will allow following logins to be made without password.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
---------
|
||||||
|
resp : LoginResponse - successful client login response
|
||||||
|
credentials : dict - The credentials used to sign in
|
||||||
|
|
||||||
|
"""
|
||||||
|
# open the config file in write-mode
|
||||||
|
with open(CONFIG_FILE, 'w') as f:
|
||||||
|
# write the login details to disk
|
||||||
|
json.dump(
|
||||||
|
{
|
||||||
|
'homeserver': credentials[
|
||||||
|
'homeserver'], # e.g. "https://matrix.example.org"
|
||||||
|
'device_name':
|
||||||
|
credentials['device_name'], # e.g. 'matrix-bot'
|
||||||
|
'room_id':
|
||||||
|
credentials['room_id'], # e.g. '!yourRoomId:example.org'
|
||||||
|
'user_id': resp.user_id, # e.g. '@user:example.org'
|
||||||
|
'device_id':
|
||||||
|
resp.device_id, # device ID, 10 uppercase letters
|
||||||
|
'access_token': resp.access_token, # cryptogr. access token
|
||||||
|
},
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Bot:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self._loop = asyncio.get_event_loop()
|
||||||
|
signals = (signal.SIGHUP, signal.SIGTERM, signal.SIGINT)
|
||||||
|
for sig in signals:
|
||||||
|
self._loop.add_signal_handler(
|
||||||
|
sig, lambda sig=sig: asyncio.create_task(self.shutdown(sig)))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def login(cls: any) -> object:
|
||||||
|
bot = cls()
|
||||||
|
await bot._login()
|
||||||
|
return bot
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client(self) -> AsyncClient:
|
||||||
|
return self._client
|
||||||
|
|
||||||
|
@property
|
||||||
|
def loop(self) -> asyncio.BaseEventLoop:
|
||||||
|
return self._loop
|
||||||
|
|
||||||
|
@property
|
||||||
|
def client_config(self) -> AsyncClientConfig:
|
||||||
|
return self._client_config
|
||||||
|
|
||||||
|
@property
|
||||||
|
def config(self) -> dict:
|
||||||
|
return self._config
|
||||||
|
|
||||||
|
def send_text_message_to_room(self, room_id: str, message: str) -> None:
|
||||||
|
async def send_message(room_id: str, message: str) -> None:
|
||||||
|
"""Login and wait for and perform emoji verify."""
|
||||||
|
# Set up event callbacks
|
||||||
|
content = {'msgtype': 'm.text', 'body': message}
|
||||||
|
await self._login()
|
||||||
|
if room_id is None:
|
||||||
|
room_id = self.config['room_id']
|
||||||
|
await self.client.sync(timeout=30000, full_state=True)
|
||||||
|
await self.client.room_send(
|
||||||
|
room_id=room_id,
|
||||||
|
message_type='m.room.message',
|
||||||
|
content=content,
|
||||||
|
ignore_unverified_devices=True,
|
||||||
|
)
|
||||||
|
await self.client.close()
|
||||||
|
|
||||||
|
self.loop.run_until_complete(send_message(room_id, message))
|
||||||
|
|
||||||
|
async def _login(self) -> AsyncClient:
|
||||||
|
"""Login to the matrix homeserver defined in the config file.
|
||||||
|
"""
|
||||||
|
self._client_config = AsyncClientConfig(
|
||||||
|
max_limit_exceeded=0,
|
||||||
|
max_timeouts=0,
|
||||||
|
store_sync_tokens=True,
|
||||||
|
encryption_enabled=True,
|
||||||
|
)
|
||||||
|
# If there are no previously-saved credentials, we'll use the password
|
||||||
|
if not os.path.exists(CONFIG_FILE):
|
||||||
|
click.secho(
|
||||||
|
'First time use. Did not find credential file. Asking '
|
||||||
|
'for homeserver, user, and password to create '
|
||||||
|
'credential file.\n',
|
||||||
|
bold=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not os.path.exists(STORE_PATH):
|
||||||
|
os.makedirs(STORE_PATH)
|
||||||
|
|
||||||
|
credentials = self.ask_credentials()
|
||||||
|
|
||||||
|
# Initialize the matrix client
|
||||||
|
client = AsyncClient(
|
||||||
|
credentials['homeserver'],
|
||||||
|
credentials['user_id'],
|
||||||
|
store_path=STORE_PATH,
|
||||||
|
config=self.client_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
pw = click.prompt(click.style('Your Password', bold=True),
|
||||||
|
hide_input=True)
|
||||||
|
|
||||||
|
resp = await client.login(password=pw,
|
||||||
|
device_name=credentials['device_name'])
|
||||||
|
|
||||||
|
del pw
|
||||||
|
|
||||||
|
# check that we logged in succesfully
|
||||||
|
if isinstance(resp, LoginResponse):
|
||||||
|
write_details_to_disk(resp, credentials)
|
||||||
|
else:
|
||||||
|
click.secho(
|
||||||
|
f'homeserver = {credentials["homeserver"]}; '
|
||||||
|
f' user = {credentials["user_id"]}',
|
||||||
|
fg='red',
|
||||||
|
)
|
||||||
|
click.secho(f'Failed to log in: {resp}', fg='red')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
self._config = {
|
||||||
|
'user_id': credentials['user_id'],
|
||||||
|
'homeserver': credentials['homeserver'],
|
||||||
|
'room_id': credentials['room_id'],
|
||||||
|
'device_name': resp['device_name'],
|
||||||
|
'device_id': resp.device_id,
|
||||||
|
'access_token': resp.access_token,
|
||||||
|
}
|
||||||
|
|
||||||
|
click.secho(
|
||||||
|
'Logged in using a password. Credentials were stored. '
|
||||||
|
'On next execution the stored login credentials will '
|
||||||
|
'be used.',
|
||||||
|
fg='green',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Otherwise the config file exists, so we'll use the stored credentials
|
||||||
|
else:
|
||||||
|
# open the file in read-only mode
|
||||||
|
with open(CONFIG_FILE, 'r') as f:
|
||||||
|
self._config = json.load(f)
|
||||||
|
# Initialize the matrix client based on credentials from file
|
||||||
|
client = AsyncClient(
|
||||||
|
self.config['homeserver'],
|
||||||
|
self.config['user_id'],
|
||||||
|
device_id=self.config['device_id'],
|
||||||
|
store_path=STORE_PATH,
|
||||||
|
config=self.client_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
client.restore_login(
|
||||||
|
user_id=self.config['user_id'],
|
||||||
|
device_id=self.config['device_id'],
|
||||||
|
access_token=self.config['access_token'],
|
||||||
|
)
|
||||||
|
# click.secho('Logged in using stored credentials.', fg='green')
|
||||||
|
|
||||||
|
self._client = client
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
async def shutdown(self, sig: any) -> None:
|
||||||
|
await self.client.close()
|
||||||
|
tasks = [
|
||||||
|
t for t in asyncio.all_tasks() if t is not asyncio.current_task()
|
||||||
|
]
|
||||||
|
for task in tasks:
|
||||||
|
task.cancel()
|
||||||
|
await task
|
||||||
|
|
||||||
|
await asyncio.gather(*tasks, return_exceptions=False)
|
||||||
|
self.loop.stop()
|
||||||
|
|
||||||
|
def verify(self) -> None:
|
||||||
|
async def verify() -> None:
|
||||||
|
"""Login and wait for and perform emoji verify."""
|
||||||
|
# Set up event callbacks
|
||||||
|
client = await self._login()
|
||||||
|
client.add_to_device_callback(self.to_device_callback,
|
||||||
|
(KeyVerificationEvent, ))
|
||||||
|
# Sync encryption keys with the server
|
||||||
|
# Required for participating in encrypted rooms
|
||||||
|
if self.client.should_upload_keys:
|
||||||
|
await self.client.keys_upload()
|
||||||
|
click.secho('\nStarting verification process...', bold=True)
|
||||||
|
click.secho(
|
||||||
|
'\nThis program is ready and waiting for the other '
|
||||||
|
'party to initiate an emoji verification with us by '
|
||||||
|
'selecting "Verify by Emoji" in their Matrix '
|
||||||
|
'client.',
|
||||||
|
fg='green',
|
||||||
|
)
|
||||||
|
await self.client.sync_forever(timeout=30000, full_state=True)
|
||||||
|
|
||||||
|
self.loop.run_until_complete(verify())
|
||||||
|
|
||||||
|
def _ask_credentials(self) -> dict:
|
||||||
|
"""Ask the user for credentials
|
||||||
|
"""
|
||||||
|
homeserver = HOMESERVER_URL
|
||||||
|
homeserver = click.prompt(
|
||||||
|
click.style('Enter your homeserver URL', bold=True),
|
||||||
|
default=homeserver,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not homeserver.startswith('https://'):
|
||||||
|
homeserver = 'https://' + homeserver
|
||||||
|
|
||||||
|
user_id = '@user:gaja-group.com'
|
||||||
|
user_id = click.prompt(click.style('Enter your full user ID',
|
||||||
|
bold=True),
|
||||||
|
default=user_id)
|
||||||
|
|
||||||
|
device_name = 'matrix-bot'
|
||||||
|
device_name = click.prompt(
|
||||||
|
click.style('Choose a name for this device', bold=True),
|
||||||
|
default=device_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
room_id = '!yourRoomId:gaja-group.com'
|
||||||
|
room_id = click.prompt(
|
||||||
|
click.style('Enter a default room ID to send to', bold=True),
|
||||||
|
default=room_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'homeserver': homeserver,
|
||||||
|
'user_id': user_id,
|
||||||
|
'device_name': device_name,
|
||||||
|
'room_id': room_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def to_device_callback(self, event): # noqa
|
||||||
|
"""Handle events sent to device."""
|
||||||
|
try:
|
||||||
|
client = self.client
|
||||||
|
|
||||||
|
if isinstance(event, KeyVerificationStart): # first step
|
||||||
|
""" first step: receive KeyVerificationStart
|
||||||
|
KeyVerificationStart(
|
||||||
|
source={'content':
|
||||||
|
{'method': 'm.sas.v1',
|
||||||
|
'from_device': 'DEVICEIDXY',
|
||||||
|
'key_agreement_protocols':
|
||||||
|
['curve25519-hkdf-sha256', 'curve25519'],
|
||||||
|
'hashes': ['sha256'],
|
||||||
|
'message_authentication_codes':
|
||||||
|
['hkdf-hmac-sha256', 'hmac-sha256'],
|
||||||
|
'short_authentication_string':
|
||||||
|
['decimal', 'emoji'],
|
||||||
|
'transaction_id': 'SomeTxId'
|
||||||
|
},
|
||||||
|
'type': 'm.key.verification.start',
|
||||||
|
'sender': '@user2:example.org'
|
||||||
|
},
|
||||||
|
sender='@user2:example.org',
|
||||||
|
transaction_id='SomeTxId',
|
||||||
|
from_device='DEVICEIDXY',
|
||||||
|
method='m.sas.v1',
|
||||||
|
key_agreement_protocols=[
|
||||||
|
'curve25519-hkdf-sha256', 'curve25519'],
|
||||||
|
hashes=['sha256'],
|
||||||
|
message_authentication_codes=[
|
||||||
|
'hkdf-hmac-sha256', 'hmac-sha256'],
|
||||||
|
short_authentication_string=['decimal', 'emoji'])
|
||||||
|
"""
|
||||||
|
|
||||||
|
if 'emoji' not in event.short_authentication_string:
|
||||||
|
click.secho(
|
||||||
|
'Other device does not support emoji verification '
|
||||||
|
f'{event.short_authentication_string}.',
|
||||||
|
fg='red',
|
||||||
|
)
|
||||||
|
return
|
||||||
|
resp = await client.accept_key_verification(
|
||||||
|
event.transaction_id)
|
||||||
|
if isinstance(resp, ToDeviceError):
|
||||||
|
click.secho(f'accept_key_verification failed with {resp}',
|
||||||
|
fg='red')
|
||||||
|
|
||||||
|
sas = client.key_verifications[event.transaction_id]
|
||||||
|
|
||||||
|
todevice_msg = sas.share_key()
|
||||||
|
resp = await client.to_device(todevice_msg)
|
||||||
|
if isinstance(resp, ToDeviceError):
|
||||||
|
click.secho(f'to_device failed with {resp}', fg='red')
|
||||||
|
|
||||||
|
elif isinstance(event, KeyVerificationCancel): # anytime
|
||||||
|
""" at any time: receive KeyVerificationCancel
|
||||||
|
KeyVerificationCancel(source={
|
||||||
|
'content': {'code': 'm.mismatched_sas',
|
||||||
|
'reason': 'Mismatched authentication string',
|
||||||
|
'transaction_id': 'SomeTxId'},
|
||||||
|
'type': 'm.key.verification.cancel',
|
||||||
|
'sender': '@user2:example.org'},
|
||||||
|
sender='@user2:example.org',
|
||||||
|
transaction_id='SomeTxId',
|
||||||
|
code='m.mismatched_sas',
|
||||||
|
reason='Mismatched short authentication string')
|
||||||
|
"""
|
||||||
|
|
||||||
|
# There is no need to issue a
|
||||||
|
# client.cancel_key_verification(tx_id, reject=False)
|
||||||
|
# here. The SAS flow is already cancelled.
|
||||||
|
# We only need to inform the user.
|
||||||
|
click.secho(
|
||||||
|
'\nVerification has been cancelled by '
|
||||||
|
f'{event.sender} for reason "{event.reason}".',
|
||||||
|
fg='yellow',
|
||||||
|
)
|
||||||
|
|
||||||
|
elif isinstance(event, KeyVerificationKey): # second step
|
||||||
|
""" Second step is to receive KeyVerificationKey
|
||||||
|
KeyVerificationKey(
|
||||||
|
source={'content': {
|
||||||
|
'key': 'SomeCryptoKey',
|
||||||
|
'transaction_id': 'SomeTxId'},
|
||||||
|
'type': 'm.key.verification.key',
|
||||||
|
'sender': '@user2:example.org'
|
||||||
|
},
|
||||||
|
sender='@user2:example.org',
|
||||||
|
transaction_id='SomeTxId',
|
||||||
|
key='SomeCryptoKey')
|
||||||
|
"""
|
||||||
|
|
||||||
|
click.secho('\nEmoji verification initiated.\n')
|
||||||
|
|
||||||
|
sas = client.key_verifications[event.transaction_id]
|
||||||
|
|
||||||
|
emojis = sas.get_emoji()
|
||||||
|
emoji_list = [' '.join(e) for e in emojis]
|
||||||
|
|
||||||
|
click.echo(', '.join(emoji_list))
|
||||||
|
# print(f'{sas.get_emoji()}')'
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if click.confirm(
|
||||||
|
click.style('Do the emojis match?', bold=True), ):
|
||||||
|
click.secho(
|
||||||
|
'\nMatch! The verification for this '
|
||||||
|
'device will be accepted.',
|
||||||
|
fg='green',
|
||||||
|
)
|
||||||
|
resp = await client.confirm_short_auth_string(
|
||||||
|
event.transaction_id)
|
||||||
|
if isinstance(resp, ToDeviceError):
|
||||||
|
click.secho(
|
||||||
|
'confirm_short_auth_string failed with '
|
||||||
|
f'{resp}',
|
||||||
|
fg='red',
|
||||||
|
)
|
||||||
|
else: # no, don't match, reject
|
||||||
|
click.secho(
|
||||||
|
'\nNo match! Device will NOT be verified '
|
||||||
|
'by rejecting verification.',
|
||||||
|
fg='yellow',
|
||||||
|
)
|
||||||
|
resp = await client.cancel_key_verification(
|
||||||
|
event.transaction_id, reject=True)
|
||||||
|
if isinstance(resp, ToDeviceError):
|
||||||
|
click.secho(
|
||||||
|
f'cancel_key_verification failed with {resp}',
|
||||||
|
fg='red',
|
||||||
|
)
|
||||||
|
except click.exceptions.Abort: # C or anything for cancel
|
||||||
|
click.secho(
|
||||||
|
'Cancelled by user! Verification will be '
|
||||||
|
'cancelled.',
|
||||||
|
fg='red',
|
||||||
|
)
|
||||||
|
resp = await client.cancel_key_verification(
|
||||||
|
event.transaction_id, reject=False)
|
||||||
|
if isinstance(resp, ToDeviceError):
|
||||||
|
print(f'cancel_key_verification failed with {resp}')
|
||||||
|
|
||||||
|
elif isinstance(event, KeyVerificationMac): # third step
|
||||||
|
""" Third step is to receive KeyVerificationMac
|
||||||
|
KeyVerificationMac(
|
||||||
|
source={'content': {
|
||||||
|
'mac': {'ed25519:DEVICEIDXY': 'SomeKey1',
|
||||||
|
'ed25519:SomeKey2': 'SomeKey3'},
|
||||||
|
'keys': 'SomeCryptoKey4',
|
||||||
|
'transaction_id': 'SomeTxId'},
|
||||||
|
'type': 'm.key.verification.mac',
|
||||||
|
'sender': '@user2:example.org'},
|
||||||
|
sender='@user2:example.org',
|
||||||
|
transaction_id='SomeTxId',
|
||||||
|
mac={'ed25519:DEVICEIDXY': 'SomeKey1',
|
||||||
|
'ed25519:SomeKey2': 'SomeKey3'},
|
||||||
|
keys='SomeCryptoKey4')
|
||||||
|
"""
|
||||||
|
sas = client.key_verifications[event.transaction_id]
|
||||||
|
try:
|
||||||
|
todevice_msg = sas.get_mac()
|
||||||
|
except LocalProtocolError as e:
|
||||||
|
# e.g. it might have been cancelled by ourselves
|
||||||
|
click.secho(
|
||||||
|
f'Cancelled or protocol error: Reason: {e}.\n'
|
||||||
|
f'Verification with {event.sender} not '
|
||||||
|
'concluded. Try again?',
|
||||||
|
fg='yellow',
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
resp = await client.to_device(todevice_msg)
|
||||||
|
if isinstance(resp, ToDeviceError):
|
||||||
|
print(f'to_device failed with {resp}')
|
||||||
|
# print(f'sas.we_started_it = {sas.we_started_it}\n'
|
||||||
|
# f'sas.sas_accepted = {sas.sas_accepted}\n'
|
||||||
|
# f'sas.canceled = {sas.canceled}\n'
|
||||||
|
# f'sas.timed_out = {sas.timed_out}\n'
|
||||||
|
# f'sas.verified = {sas.verified}\n'
|
||||||
|
# f'sas.verified_devices = {sas.verified_devices}\n')
|
||||||
|
click.secho('Emoji verification was successful!',
|
||||||
|
fg='green')
|
||||||
|
await self.shutdown([], self._loop)
|
||||||
|
else:
|
||||||
|
print(f'Received unexpected event type {type(event)}. '
|
||||||
|
f'Event is {event}. Event will be ignored.')
|
||||||
|
except BaseException:
|
||||||
|
print(traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
@click.option('-v', '--verbose', count=True)
|
||||||
|
def cli(verbose: int) -> None:
|
||||||
|
# click.secho('Matrix Bot\n', bold='true')
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command('verify')
|
||||||
|
def verify_command() -> None:
|
||||||
|
bot = Bot()
|
||||||
|
bot.verify()
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command('message')
|
||||||
|
@click.argument('message')
|
||||||
|
@click.option('-r', '--room', help='the room to send to')
|
||||||
|
def send_command(message: str, room: str) -> None:
|
||||||
|
bot = Bot()
|
||||||
|
bot.send_text_message_to_room(room, message)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
cli()
|
|
@ -0,0 +1,9 @@
|
||||||
|
[yapf]
|
||||||
|
based_on_style = pep8
|
||||||
|
spaces_before_comment = 4
|
||||||
|
split_before_logical_operator = true
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
ignore = ANN101,ANN102
|
||||||
|
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist
|
||||||
|
max-complexity = 10
|
Loading…
Reference in New Issue