From 8c4b7a1ac8460c0d17e2b0a4de2e31d6ab7b3e08 Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 4 Dec 2018 02:02:40 -0300 Subject: [PATCH 01/12] pubsub.lazy_guild: fix list_id for non-everyone lists - utils: add murmurhash3 implementation --- litecord/pubsub/lazy_guild.py | 29 +++++++++++++- litecord/utils.py | 73 +++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) diff --git a/litecord/pubsub/lazy_guild.py b/litecord/pubsub/lazy_guild.py index fcbd153..cc0bf5c 100644 --- a/litecord/pubsub/lazy_guild.py +++ b/litecord/pubsub/lazy_guild.py @@ -13,6 +13,7 @@ from litecord.permissions import ( Permissions, overwrite_find_mix, get_permissions, role_permissions ) from litecord.utils import index_by_func +from litecord.utils import mmh3 log = Logger(__name__) @@ -267,7 +268,33 @@ class GuildMemberList: """get the id of the member list.""" return ('everyone' if self.channel_id == self.guild_id - else str(self.channel_id)) + else self._calculated_id) + + @property + def _calculated_id(self): + """Calculate an id used by the client.""" + + if not self.list: + return str(self.channel_id) + + # list of strings holding the hash input + ovs_i = [] + + print(self.list.overwrites) + + for actor_id, overwrite in self.list.overwrites.items(): + allow, deny = ( + Permissions(overwrite['allow']), + Permissions(overwrite['deny']) + ) + + if allow.bits.read_messages: + ovs_i.append(f'allow:{actor_id}') + elif deny.bits.read_messages: + ovs_i.append(f'deny:{actor_id}') + + hash_in = ','.join(ovs_i) + return str(mmh3(hash_in)) def _set_empty_list(self): """Set the member list as being empty.""" diff --git a/litecord/utils.py b/litecord/utils.py index 2fda9d5..26c6ba2 100644 --- a/litecord/utils.py +++ b/litecord/utils.py @@ -37,3 +37,76 @@ def index_by_func(function, indexable: iter) -> int: return index return None + + +def _u(val): + """convert to unsigned.""" + return val % 0x100000000 + + +def mmh3(key: str, seed: int = 0): + """MurMurHash3 implementation. + + This seems to match Discord's JavaScript implementaiton. + + Based off + https://github.com/garycourt/murmurhash-js/blob/master/murmurhash3_gc.js + """ + key = [ord(c) for c in key] + + remainder = len(key) & 3 + bytecount = len(key) - remainder + h1 = seed + + # mm3 constants + c1 = 0xcc9e2d51 + c2 = 0x1b873593 + i = 0 + + while i < bytecount: + k1 = ( + (key[i] & 0xff) | + ((key[i + 1] & 0xff) << 8) | + ((key[i + 2] & 0xff) << 16) | + ((key[i + 3] & 0xff) << 24) + ) + + i += 4 + + k1 = ((((k1 & 0xffff) * c1) + ((((_u(k1) >> 16) * c1) & 0xffff) << 16))) & 0xffffffff + k1 = (k1 << 15) | (_u(k1) >> 17) + k1 = ((((k1 & 0xffff) * c2) + ((((_u(k1) >> 16) * c2) & 0xffff) << 16))) & 0xffffffff; + + h1 ^= k1 + h1 = (h1 << 13) | (_u(h1) >> 19); + h1b = ((((h1 & 0xffff) * 5) + ((((_u(h1) >> 16) * 5) & 0xffff) << 16))) & 0xffffffff; + h1 = (((h1b & 0xffff) + 0x6b64) + ((((_u(h1b) >> 16) + 0xe654) & 0xffff) << 16)) + + + k1 = 0 + v = None + + if remainder == 3: + v = (key[i + 2] & 0xff) << 16 + elif remainder == 2: + v = (key[i + 1] & 0xff) << 8 + elif remainder == 1: + v = (key[i] & 0xff) + + if v is not None: + k1 ^= v + + k1 = (((k1 & 0xffff) * c1) + ((((_u(k1) >> 16) * c1) & 0xffff) << 16)) & 0xffffffff + k1 = (k1 << 15) | (_u(k1) >> 17) + k1 = (((k1 & 0xffff) * c2) + ((((_u(k1) >> 16) * c2) & 0xffff) << 16)) & 0xffffffff + h1 ^= k1 + + h1 ^= len(key) + + h1 ^= _u(h1) >> 16 + h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((_u(h1) >> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff + h1 ^= _u(h1) >> 13 + h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((_u(h1) >> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff + h1 ^= _u(h1) >> 16 + + return _u(h1) >> 0 From 7d6aab9a296a1c37bf48b4d802716b0971c32f21 Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 4 Dec 2018 02:21:49 -0300 Subject: [PATCH 02/12] litecord.auth: use TimestampSigner this fixes all tokens being the same. --- litecord/auth.py | 4 ++-- litecord/blueprints/auth.py | 2 +- litecord/pubsub/lazy_guild.py | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/litecord/auth.py b/litecord/auth.py index d9cd1e0..f631345 100644 --- a/litecord/auth.py +++ b/litecord/auth.py @@ -4,7 +4,7 @@ from random import randint import bcrypt from asyncpg import UniqueViolationError -from itsdangerous import Signer, BadSignature +from itsdangerous import TimestampSigner, BadSignature from logbook import Logger from quart import request, current_app as app @@ -38,7 +38,7 @@ async def raw_token_check(token, db=None): if not pwd_hash: raise Unauthorized('User ID not found') - signer = Signer(pwd_hash) + signer = TimestampSigner(pwd_hash) try: signer.unsign(token) diff --git a/litecord/blueprints/auth.py b/litecord/blueprints/auth.py index 9327f29..6902d5b 100644 --- a/litecord/blueprints/auth.py +++ b/litecord/blueprints/auth.py @@ -24,7 +24,7 @@ async def check_password(pwd_hash: str, given_password: str) -> bool: def make_token(user_id, user_pwd_hash) -> str: """Generate a single token for a user.""" - signer = itsdangerous.Signer(user_pwd_hash) + signer = itsdangerous.TimestampSigner(user_pwd_hash) user_id = base64.b64encode(str(user_id).encode()) return signer.sign(user_id).decode() diff --git a/litecord/pubsub/lazy_guild.py b/litecord/pubsub/lazy_guild.py index cc0bf5c..ef7c65e 100644 --- a/litecord/pubsub/lazy_guild.py +++ b/litecord/pubsub/lazy_guild.py @@ -280,8 +280,6 @@ class GuildMemberList: # list of strings holding the hash input ovs_i = [] - print(self.list.overwrites) - for actor_id, overwrite in self.list.overwrites.items(): allow, deny = ( Permissions(overwrite['allow']), From dbc6da8ce912d4a1deb1e350514b31c8bda5c84c Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 4 Dec 2018 02:22:38 -0300 Subject: [PATCH 03/12] pubsub.guild: remove print debug --- litecord/pubsub/guild.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/litecord/pubsub/guild.py b/litecord/pubsub/guild.py index c687d25..d86edd3 100644 --- a/litecord/pubsub/guild.py +++ b/litecord/pubsub/guild.py @@ -26,8 +26,6 @@ class GuildDispatcher(DispatcherWithState): user_id, chan_id, storage=self.main_dispatcher.app.storage) - print(user_id, chan_id, chan_perms.bits.read_messages) - if not chan_perms.bits.read_messages: log.debug('skipping cid={}, no read messages', chan_id) From 66f7e55d261fcbae61e7d0f805a5b3d9e11e6241 Mon Sep 17 00:00:00 2001 From: slice Date: Mon, 3 Dec 2018 22:45:05 -0800 Subject: [PATCH 04/12] Ignore macOS .DS_Store files They are like thumbs.db on Windows. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 104e4de..062ffb8 100644 --- a/.gitignore +++ b/.gitignore @@ -105,3 +105,5 @@ venv.bak/ config.py images/* + +.DS_Store From 636dec5ddeb3a9c3d6bb6f32c8d50ee09a6ff398 Mon Sep 17 00:00:00 2001 From: slice Date: Mon, 3 Dec 2018 22:45:22 -0800 Subject: [PATCH 05/12] Add project logo Typeset in Work Sans Bold Italic 96px. --- README.md | 2 +- static/logo/logo.png | Bin 0 -> 5775 bytes static/logo/logo.svg | 5 +++++ static/logo/logo@2x.png | Bin 0 -> 12999 bytes 4 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 static/logo/logo.png create mode 100644 static/logo/logo.svg create mode 100644 static/logo/logo@2x.png diff --git a/README.md b/README.md index 2c78b2f..ae048b6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# litecord +![Litecord logo](static/logo/logo.png) Litecord is an open source implementation of Discord's backend and API in Python. diff --git a/static/logo/logo.png b/static/logo/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d0f3fd94501cd64b5a217e3597b5b2e0bea1bcbe GIT binary patch literal 5775 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 + + + + diff --git a/static/logo/logo@2x.png b/static/logo/logo@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ce35d48a48f5650d3225f5c75a55909a2c96c6f GIT binary patch literal 12999 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 SpQHbv0#H%ZRH%@%4EaA Date: Mon, 3 Dec 2018 23:00:20 -0800 Subject: [PATCH 06/12] Restructure README.md --- README.md | 97 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index ae048b6..2bc8678 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,97 @@ ![Litecord logo](static/logo/logo.png) -Litecord is an open source implementation of Discord's backend and API in -Python. +Litecord is an open source implementation of Discord's HTTP API and Gateway in +Python 3. This project is a rewrite of [litecord-reference]. [litecord-reference]: https://gitlab.com/luna/litecord-reference -## Notes +## Caveats - - Unit testing isn't completly perfect. - - No voice is planned to be developed, for now. - - You must figure out connecting to the server yourself. Litecord will not distribute - Discord's official client code nor provide ways to modify the client. +- Unit testing is incomplete. +- Currently, are no plans to support voice chat. +- You must figure out how to connect to a Litecord instance. Litecord will not + distribute official client code from Discord nor provide ways to modify the + official client. -## Install +## Installation Requirements: -- Python 3.7 or higher -- PostgreSQL -- gifsicle for GIF emoji and avatar handling. -- [Pipenv] + +- **Python 3.7+** +- PostgreSQL (tested using 9.6+) +- gifsicle for GIF emoji and avatar handling +- [pipenv] [pipenv]: https://github.com/pypa/pipenv +### Download the code + ```sh -$ git clone https://gitlab.com/luna/litecord.git && cd litecord +$ git clone https://gitlab.com/litecord/litecord.git && cd litecord +``` -# Setup the database: -# don't forget that you can create a specific -# postgres user just for the litecord database +### Setting up the database + +It's recommended to create a separate user for the `litecord` database. + +```sh +# Create the PostgreSQL database. $ createdb litecord + +# Apply the base schema to the database. $ psql -f schema.sql litecord +``` -# Configure litecord: -# edit config.py as you wish -$ cp config.example.py config.py +Then, you should run database migrations: -# run database migrations (this is a -# required step in setup) +```sh $ pipenv run ./manage.py migrate +``` -# Install all packages: +### Configuring + +Copy the `config.example.py` file and edit it to configure your instance: + +```sh +$ cp config.example.py config.py +$ $EDITOR config.py +``` + +### Install packages + +```sh $ pipenv install --dev ``` ## Running -Hypercorn is used to run litecord. By default, it will bind to `0.0.0.0:5000`. -You can use the `-b` option to change it (e.g. `-b 0.0.0.0:45000`). - -Use `--access-log -` to output access logs to stdout. +Hypercorn is used to run Litecord. By default, it will bind to `0.0.0.0:5000`. +This will expose your Litecord instance to the world. You can use the `-b` +option to change it (e.g. `-b 0.0.0.0:45000`). ```sh $ pipenv run hypercorn run:app ``` -*It is recommended to run litecord behind NGINX.* Because of that, -there is a basic `nginx.conf` file at the root. +You can use `--access-log -` to output access logs to stdout. -### Checking if it is working +**It is recommended to run litecord behind [NGINX].** You can use the +`nginx.conf` file at the root of the repository as a template. -You can check if your instance is running by checking the `/api/v6/gateway` -path. For basic websocket testing a tool such as +[nginx]: https://www.nginx.com + +### Does it work? + +You can check if your instance is running by performing a HTTP `GET` request on +the `/api/v6/gateway` endpoint. For basic websocket testing, a tool such as [ws](https://github.com/hashrocket/ws) can be used. ## Updating +Update the code and run any new database migrations: + ```sh $ git pull $ pipenv run ./manage.py migrate @@ -74,16 +99,16 @@ $ pipenv run ./manage.py migrate ## Running tests -To run tests we must create users that we know the passwords of. -Because of that, **never setup a testing environment in production.** +Running tests involves creating dummy users with known passwords. Because of +this, you should never setup a testing environment in production. ```sh -# setup the testing users +# Setup any testing users: $ pipenv run ./manage.py setup_tests -# make sure you have tox installed +# Install tox: $ pip install tox -# run basic linter and tests +# Run lints and tests: $ tox ``` From cfd0e7ce3456eb04daa1d871d6bb1a07d706fb82 Mon Sep 17 00:00:00 2001 From: slice Date: Mon, 3 Dec 2018 23:02:11 -0800 Subject: [PATCH 07/12] english grammar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2bc8678..71fdc7a 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ You can use `--access-log -` to output access logs to stdout. ### Does it work? -You can check if your instance is running by performing a HTTP `GET` request on +You can check if your instance is running by performing an HTTP `GET` request on the `/api/v6/gateway` endpoint. For basic websocket testing, a tool such as [ws](https://github.com/hashrocket/ws) can be used. From e0a41cfcbe4d11cc3759cae76e1163abe13fa764 Mon Sep 17 00:00:00 2001 From: slice Date: Mon, 3 Dec 2018 23:11:02 -0800 Subject: [PATCH 08/12] Add project goals --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 71fdc7a..aae9f08 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,15 @@ This project is a rewrite of [litecord-reference]. [litecord-reference]: https://gitlab.com/luna/litecord-reference +## Project Goals + +- Being able to unit test bots in an autonomous fashion. +- Doing research and exploration on Discord API. + +### Non-goals + +- Being used as a "self-hostable Discord alternative". + ## Caveats - Unit testing is incomplete. From 34d7f60c99deee2491438b716f83e8216c5b23f8 Mon Sep 17 00:00:00 2001 From: slice Date: Mon, 3 Dec 2018 23:14:43 -0800 Subject: [PATCH 09/12] my hands are typing words --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aae9f08..70b6595 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ ![Litecord logo](static/logo/logo.png) -Litecord is an open source implementation of Discord's HTTP API and Gateway in -Python 3. +Litecord is an open source, [clean-room design][clean-room] reimplementation of +Discord's HTTP API and Gateway in Python 3. This project is a rewrite of [litecord-reference]. +[clean-room]: https://en.wikipedia.org/wiki/Clean_room_design [litecord-reference]: https://gitlab.com/luna/litecord-reference ## Project Goals From 6a3307a06beabef5f4cc716c34e6912c506ed67b Mon Sep 17 00:00:00 2001 From: slice Date: Mon, 3 Dec 2018 23:15:30 -0800 Subject: [PATCH 10/12] this is a very important commit. * implements the entire discord api in scala --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70b6595..35bf9af 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This project is a rewrite of [litecord-reference]. ## Project Goals - Being able to unit test bots in an autonomous fashion. -- Doing research and exploration on Discord API. +- Doing research and exploration on the Discord API. ### Non-goals From 8b3d09a9b1efc48d3c7e3e20a658aadf8c32062b Mon Sep 17 00:00:00 2001 From: slice Date: Mon, 3 Dec 2018 23:17:00 -0800 Subject: [PATCH 11/12] God is dead. Is that what God does? He helps? Tell me, why didn't God help my innocent friend who died for no reason while the guilty ran free? Okay. Fine. Forget the one offs. How about the countless wars declared in his name? Okay. Fine. Let's skip the random, meaningless murder for a second, shall we? How about the racist, sexist, phobia soup we've all been drowning in because of him? And I'm not just talking about Jesus. I'm talking about all organized religion. Exclusive groups created to manage control. A dealer getting people hooked on the drug of hope. His followers, nothing but addicts who want their hit of bullshit to keep their dopamine of ignorance. Addicts. Afraid to believe the truth. That there's no order. There's no power. That all religions are just metastasizing mind worms, meant to divide us so it's easier to rule us by the charlatans that wanna run us. All we are to them are paying fanboys of their poorly-written sci-fi franchise. If I don't listen to my imaginary friend, why the fuck should I listen to yours? People think their worship's some key to happiness. That's just how he owns you. Even I'm not crazy enough to believe that distortion of reality. So fuck God. He's not a good enough scapegoat for me. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35bf9af..e8a3b1b 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This project is a rewrite of [litecord-reference]. ## Caveats - Unit testing is incomplete. -- Currently, are no plans to support voice chat. +- Currently, there are no plans to support voice chat. - You must figure out how to connect to a Litecord instance. Litecord will not distribute official client code from Discord nor provide ways to modify the official client. From 7c9dc0ae34ae6a5d3937bfff93eaf971e7e5f02a Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 4 Dec 2018 04:18:27 -0300 Subject: [PATCH 12/12] users: add impl for user delete untested. --- litecord/blueprints/users.py | 110 +++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 4 deletions(-) diff --git a/litecord/blueprints/users.py b/litecord/blueprints/users.py index 3354a46..bc5352b 100644 --- a/litecord/blueprints/users.py +++ b/litecord/blueprints/users.py @@ -1,22 +1,25 @@ import random +from os import urandom from asyncpg import UniqueViolationError from quart import Blueprint, jsonify, request, current_app as app +from logbook import Logger -from ..auth import token_check -from ..errors import Forbidden, BadRequest +from ..errors import Forbidden, BadRequest, Unauthorized from ..schemas import validate, USER_UPDATE, GET_MENTIONS from .guilds import guild_check -from .auth import check_password -from litecord.auth import hash_data, check_username_usage +from litecord.auth import token_check, hash_data, check_username_usage from litecord.blueprints.guild.mod import remove_member from litecord.enums import PremiumType from litecord.images import parse_data_uri from litecord.permissions import base_permissions +from litecord.blueprints.auth import check_password + bp = Blueprint('user', __name__) +log = Logger(__name__) async def mass_user_update(user_id, app_=None): @@ -441,3 +444,102 @@ async def _get_mentions(): ) return jsonify(res) + + +def rand_hex(length: int = 8) -> str: + """Generate random hex characters.""" + return urandom(length).hex()[:length] + + +async def _del_from_table(table: str, user_id: int): + column = { + 'channel_overwrites': 'target_user', + 'user_settings': 'id' + }.get(table, 'user_id') + + res = await app.db.execute(f""" + DELETE FROM {table} + WHERE {column} = $1 + """, user_id) + + log.info('Deleting uid {} from {}, res: {!r}', + user_id, table, res) + + +@bp.route('/users/@me/delete') +async def delete_account(): + """Delete own account. + + There isn't any inherent need to dispatch + events to connected users, so this is mostly + DB operations. + """ + user_id = await token_check() + + j = await request.get_json() + + try: + password = j['password'] + except KeyError: + raise BadRequest('password required') + + owned_guilds = await app.db.fetchval(""" + SELECT COUNT(*) + FROM guilds + WHERE owner_id = $1 + """, user_id) + + if owned_guilds > 0: + raise BadRequest('You still own guilds.') + + pwd_hash = await app.db.fetchval(""" + SELECT password_hash + FROM users + WHERE id = $1 + """, user_id) + + if not await check_password(pwd_hash, password): + raise Unauthorized('password does not match') + + new_username = f'Deleted User {rand_hex()}' + + await app.db.execute(""" + UPDATE users + SET + username = $1, + email = NULL, + mfa_enabled = false, + verified = false + avatar = NULL, + flags = 0, + premium_since = NULL, + phone = '', + password_hash = '123' + WHERE + id = $2 + """, new_username, user_id) + + # remove the user from various tables + await _del_from_table('user_settings', user_id) + await _del_from_table('user_payment_sources', user_id) + await _del_from_table('user_subscriptions', user_id) + await _del_from_table('user_payments', user_id) + await _del_from_table('user_read_state', user_id) + await _del_from_table('guild_settings', user_id) + await _del_from_table('guild_settings_channel_overrides', user_id) + + await app.db.execute(""" + DELETE FROM relationships + WHERE user_id = $1 OR peer_id = $1 + """, user_id) + + # DMs are still maintained, but not the state. + await _del_from_table('dm_channel_state', user_id) + + # TODO: group DMs + + await _del_from_table('members', user_id) + await _del_from_table('member_roles', user_id) + await _del_from_table('channel_overwrites', user_id) + + return '', 204