diff --git a/conftest.py b/conftest.py index e7343774..eaec0fb9 100644 --- a/conftest.py +++ b/conftest.py @@ -251,17 +251,31 @@ def banned_user(db): @pytest.fixture -def blind_user(db): +def blind15_user(db): import user - return user.User(blinded=True) + return user.User(blinded15=True) @pytest.fixture -def blind_user2(db): +def blind15_user2(db): import user - return user.User(blinded=True) + return user.User(blinded15=True) + + +@pytest.fixture +def blind25_user(db): + import user + + return user.User(blinded25=True) + + +@pytest.fixture +def blind25_user2(db): + import user + + return user.User(blinded25=True) @pytest.fixture diff --git a/contrib/auth-example.py b/contrib/auth-example.py index 0e6767b8..ed52376a 100755 --- a/contrib/auth-example.py +++ b/contrib/auth-example.py @@ -71,7 +71,6 @@ def get_signing_headers( body, blinded: bool = True, ): - assert len(server_pk) == 32 assert len(nonce) == 16 diff --git a/contrib/blind.py b/contrib/blind.py new file mode 100755 index 00000000..375f96c6 --- /dev/null +++ b/contrib/blind.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import sys +import nacl.bindings as sodium +import nacl.hash +import nacl.signing +from nacl.encoding import RawEncoder +from pyonionreq import xed25519 + +if len(sys.argv) < 3: + print( + f"Usage: {sys.argv[0]} SERVERPUBKEY {{SESSIONID|\"RANDOM\"}} [SESSIONID ...] -- blinds IDs", + file=sys.stderr, + ) + sys.exit(1) + +server_pk = sys.argv[1] +sids = sys.argv[2:] + +if len(server_pk) != 64 or not all(c in '0123456789ABCDEFabcdef' for c in server_pk): + print(f"Invalid argument: expected 64 hex digit server pk as first argument") + sys.exit(2) + +server_pk = bytes.fromhex(server_pk) + +print(nacl.hash.blake2b(server_pk, digest_size=64, encoder=RawEncoder)) + +k15 = sodium.crypto_core_ed25519_scalar_reduce( + nacl.hash.blake2b(server_pk, digest_size=64, encoder=RawEncoder) +) + + +for i in range(len(sids)): + if sids[i] == "RANDOM": + sids[i] = ( + "05" + + nacl.signing.SigningKey.generate() + .verify_key.to_curve25519_public_key() + .encode() + .hex() + ) + if ( + len(sids[i]) != 66 + or not sids[i].startswith('05') + or not all(c in '0123456789ABCDEFabcdef' for c in sids[i]) + ): + print(f"Invalid session id: expected 66 hex digit id as first argument") + +print(f"SOGS pubkey: {server_pk.hex()}") + +for s in sids: + s = bytes.fromhex(s) + + if s[0] == 0x05: + k25 = sodium.crypto_core_ed25519_scalar_reduce( + nacl.hash.blake2b(s[1:] + server_pk, digest_size=64, encoder=RawEncoder) + ) + + pk15 = sodium.crypto_scalarmult_ed25519_noclamp(k15, xed25519.pubkey(s[1:])) + pk25 = sodium.crypto_scalarmult_ed25519_noclamp(k25, xed25519.pubkey(s[1:])) + + print( + f"{s.hex()} blinds to:\n - 15{pk15.hex()} or …{pk15[31] ^ 0x80:02x}\n - 25{pk25.hex()} or …{pk25[31] ^ 0x80:02x}" + ) diff --git a/contrib/blind25-testing.py b/contrib/blind25-testing.py new file mode 100644 index 00000000..6625a5d7 --- /dev/null +++ b/contrib/blind25-testing.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +import sys +import nacl.bindings as sodium +import nacl.hash +import nacl.signing +from nacl.encoding import RawEncoder +from pyonionreq import xed25519 + +server_pk = bytes.fromhex("0000000000000000000000000000000000000000000000000000000000000001") + +to_sign = "hello!" + +for i in range(1000): + sk = nacl.signing.SigningKey.generate() + pk = sk.verify_key + xpk = pk.to_curve25519_public_key() + sid = "05" + xpk.encode().hex() + + k25 = sodium.crypto_core_ed25519_scalar_reduce( + nacl.hash.blake2b( + bytes.fromhex(sid) + server_pk, digest_size=64, encoder=RawEncoder, key=b"SOGS_blind_v2" + ) + ) + + # Comment notation: + # P = server pubkey + # a/A = ed25519 keypair + # b/B = x25519 keypair, converted from a/A + # S = session id = 0x05 || B + # T = |A|, that is, A with the sign bit cleared + # t = private scalar s.t. tG = T (which is ± the private scalar associated with A) + # k = blinding factor = H_64(S || P, key="SOGS_blind_v2") + + # This is simulating what the blinding client (i.e. with full keys) can compute: + + # k * A + pk25a = sodium.crypto_scalarmult_ed25519_noclamp(k25, pk.encode()) + # -k * A + neg_k25 = sodium.crypto_core_ed25519_scalar_negate(k25) + pk25b = sodium.crypto_scalarmult_ed25519_noclamp(neg_k25, pk.encode()) + + # print(f"k: {k25.hex()}") + # print(f"-k: {neg_k25.hex()}") + # + # print(f"a: {pk25a.hex()}") + # print(f"b: {pk25b.hex()}") + + assert pk25a != pk25b + assert pk25a[0:31] == pk25b[0:31] + assert pk25a[31] ^ 0x80 == pk25b[31] + + # The one we want to use is what we would end up with *if* our Ed25519 had been positive (but of + # course there's a 50% chance it's negative). + ed_pk_is_positive = pk.encode()[31] & 0x80 == 0 + + pk25 = pk25a if ed_pk_is_positive else pk25b + + ########### + # Make sure we can get to pk25 from the session id + # We know sid and server_pk, so we can compute k25 + T_pk25 = sodium.crypto_scalarmult_ed25519_noclamp(k25, xed25519.pubkey(xpk.encode())) + assert T_pk25 == pk25 + + # To sign something that validates with pk25 we have a bit more work + + # First get our blinded, private scalar; we'll call it j + + # We want to pick j such that it is always associated with |A|, that is, our positive pubkey, + # even if our pubkey is negative, so that someone with our session id can get our signing pubkey + # deterministically. + + t = ( + sk.to_curve25519_private_key().encode() + ) # The value we get here is actually our private scalar, despite the name + if pk.encode()[31] & 0x80: + # If our actual pubkey is negative then negate j so that it is as if we are working from the + # positive version of our pubkey + t = sodium.crypto_core_ed25519_scalar_negate(t) + + kt = sodium.crypto_core_ed25519_scalar_mul(k25, t) + + kT = sodium.crypto_scalarmult_ed25519_base_noclamp(kt) + assert kT == pk25 + + # Now we more or less follow EdDSA, but with our blinded scalar instead of real scalar, and with + # a different hash function. (See comments in libsession-util config/groups/keys.cpp for more + # details). + hseed = nacl.hash.blake2b( + sk.encode()[0:31], key=b"SOGS25Seed", encoder=nacl.encoding.RawEncoder + ) + r = sodium.crypto_core_ed25519_scalar_reduce( + nacl.hash.blake2b( + hseed + pk25 + to_sign.encode(), 64, key=b"SOGS25Sig", encoder=nacl.encoding.RawEncoder + ) + ) + R = sodium.crypto_scalarmult_ed25519_base_noclamp(r) + + # S = r + H(R || A || M) a (with A=kT, a=kt) + hram = nacl.hash.sha512(R + kT + to_sign.encode(), encoder=nacl.encoding.RawEncoder) + S = sodium.crypto_core_ed25519_scalar_reduce(hram) + S = sodium.crypto_core_ed25519_scalar_mul(S, kt) + S = sodium.crypto_core_ed25519_scalar_add(S, r) + + sig = R + S + + ########################################### + # Test bog standard Ed25519 signature verification: + + vk = nacl.signing.VerifyKey(pk25) + vk.verify(to_sign.encode(), sig) diff --git a/contrib/pg-import.py b/contrib/pg-import.py index 61c7a1a3..df832ae8 100755 --- a/contrib/pg-import.py +++ b/contrib/pg-import.py @@ -86,7 +86,6 @@ with pgsql.transaction(): - curin = old.cursor() curout = pgsql.cursor() @@ -131,7 +130,6 @@ curout.execute("ALTER TABLE rooms DROP CONSTRAINT room_image_fk") def copy(table): - cols = [r['name'] for r in curin.execute(f"PRAGMA table_info({table})")] if not cols: raise RuntimeError(f"Expected table {table} does not exist in sqlite db") diff --git a/sogs/__init__.py b/sogs/__init__.py index 7014662a..52c69476 100644 --- a/sogs/__init__.py +++ b/sogs/__init__.py @@ -1 +1 @@ -__version__ = "0.3.8.dev0" +__version__ = "0.4.0.dev0" diff --git a/sogs/__main__.py b/sogs/__main__.py index d897949e..aa55dae4 100644 --- a/sogs/__main__.py +++ b/sogs/__main__.py @@ -400,7 +400,6 @@ def parse_and_set_perm_flags(flags, perm_setting): sys.exit(2) elif update_room: - rooms = [] all_rooms = False global_rooms = False @@ -428,7 +427,7 @@ def parse_and_set_perm_flags(flags, perm_setting): if args.add_moderators: for a in args.add_moderators: - if not re.fullmatch(r'[01]5[A-Fa-f0-9]{64}', a): + if not re.fullmatch(r'[012]5[A-Fa-f0-9]{64}', a): print(f"Error: '{a}' is not a valid session id", file=sys.stderr) sys.exit(1) @@ -436,7 +435,7 @@ def parse_and_set_perm_flags(flags, perm_setting): if global_rooms: for sid in args.add_moderators: - u = User(session_id=sid, try_blinding=True) + u = User(session_id=sid) u.set_moderator(admin=args.admin, visible=args.visible, added_by=sysadmin) print( "Added {} as {} global {}".format( @@ -447,7 +446,7 @@ def parse_and_set_perm_flags(flags, perm_setting): ) else: for sid in args.add_moderators: - u = User(session_id=sid, try_blinding=True) + u = User(session_id=sid) for room in rooms: room.set_moderator( u, admin=args.admin, visible=not args.hidden, added_by=sysadmin @@ -464,7 +463,7 @@ def parse_and_set_perm_flags(flags, perm_setting): if args.delete_moderators: for a in args.delete_moderators: - if not re.fullmatch(r'[01]5[A-Fa-f0-9]{64}', a): + if not re.fullmatch(r'[012]5[A-Fa-f0-9]{64}', a): print(f"Error: '{a}' is not a valid session id", file=sys.stderr) sys.exit(1) @@ -472,49 +471,31 @@ def parse_and_set_perm_flags(flags, perm_setting): if global_rooms: for sid in args.delete_moderators: - u = User(session_id=sid, try_blinding=True) - was_admin = u.global_admin - if not u.global_admin and not u.global_moderator: - print(f"{u.session_id} was not a global moderator") - else: - u.remove_moderator(removed_by=sysadmin) - print( - f"Removed {u.session_id} as global {'admin' if was_admin else 'moderator'}" - ) - - if u.is_blinded and sid.startswith('05'): - try: - u2 = User(session_id=sid, try_blinding=False, autovivify=False) - if u2.global_admin or u2.global_moderator: - was_admin = u2.global_admin - u2.remove_moderator(removed_by=sysadmin) - print( - f"Removed {u2.session_id} as global " - f"{'admin' if was_admin else 'moderator'}" - ) - except NoSuchUser: - pass + try: + u = User(session_id=sid, autovivify=False) + if u.global_admin or u.global_moderator: + was_admin = u.global_admin + u.remove_moderator(removed_by=sysadmin) + print( + f"Removed {u.session_id} " + f"(identified by {sid}) " + f"as global {'admin' if was_admin else 'moderator'}" + ) + except NoSuchUser: + pass else: for sid in args.delete_moderators: - u = User(session_id=sid, try_blinding=True) - u2 = None - if u.is_blinded and sid.startswith('05'): - try: - u2 = User(session_id=sid, try_blinding=False, autovivify=False) - except NoSuchUser: - pass - - for room in rooms: - room.remove_moderator(u, removed_by=sysadmin) - print( - f"Removed {u.session_id} as moderator/admin of {room.name} ({room.token})" - ) - if u2 is not None: - room.remove_moderator(u2, removed_by=sysadmin) + try: + u = User(session_id=sid, autovivify=False) + for room in rooms: + room.remove_moderator(u, removed_by=sysadmin) print( - f"Removed {u2.session_id} as moderator/admin of {room.name} " - f"({room.token})" + f"Removed {u.session_id} " + f"(identified by {sid}) " + f"as moderator/admin of {room.name} ({room.token})" ) + except NoSuchUser: + pass if args.add_perms or args.clear_perms or args.remove_perms: if global_rooms: @@ -524,9 +505,10 @@ def parse_and_set_perm_flags(flags, perm_setting): ) sys.exit(1) + vivify = args.add_perms or args.remove_perms users = [] if args.users: - users = [User(session_id=sid, try_blinding=True) for sid in args.users] + users = [User(session_id=sid, autovivify=vivify) for sid in args.users] # users not specified means set room defaults if not len(users): @@ -577,8 +559,7 @@ def parse_and_set_perm_flags(flags, perm_setting): if args.name is not None: if global_rooms or all_rooms: print( - "Error: --rooms cannot be '+' or '*' (i.e. global/all) with --name", - file=sys.stderr, + "Error: --rooms cannot be '+' or '*' (i.e. global/all) with --name", file=sys.stderr ) sys.exit(1) diff --git a/sogs/config.py b/sogs/config.py index dc41ab94..804a3cb7 100644 --- a/sogs/config.py +++ b/sogs/config.py @@ -36,6 +36,7 @@ ALPHABET_SILENT = True FILTER_MODS = False REQUIRE_BLIND_KEYS = True +REQUIRE_BLIND_V2 = False TEMPLATE_PATH = 'templates' STATIC_PATH = 'static' UPLOAD_PATH = 'uploads' @@ -147,7 +148,10 @@ def reply_to_format(v): 'active_prune_threshold': ('ROOM_ACTIVE_PRUNE_THRESHOLD', None, days_to_seconds), }, 'direct_messages': {'expiry': ('DM_EXPIRY', None, days_to_seconds)}, - 'users': {'require_blind_keys': bool_opt('REQUIRE_BLIND_KEYS')}, + 'users': { + 'require_blind_keys': bool_opt('REQUIRE_BLIND_KEYS'), + 'require_blind_v2': bool_opt('REQUIRE_BLIND_V2'), + }, 'messages': { 'history_prune_threshold': ('MESSAGE_HISTORY_PRUNE_THRESHOLD', None, days_to_seconds), 'profanity_filter': bool_opt('PROFANITY_FILTER'), diff --git a/sogs/crypto.py b/sogs/crypto.py index c0f012e2..2e28b906 100644 --- a/sogs/crypto.py +++ b/sogs/crypto.py @@ -1,6 +1,7 @@ from . import config import os +from typing import Optional import nacl from nacl.public import PrivateKey @@ -18,7 +19,7 @@ import hmac import functools -import pyonionreq +from session_util import blinding, xed25519 if [int(v) for v in nacl.__version__.split('.')] < [1, 4]: raise ImportError("SOGS requires nacl v1.4.0+") @@ -64,9 +65,6 @@ def persist_privkey(): server_pubkey_hex = server_pubkey.encode(HexEncoder).decode('ascii') server_pubkey_base64 = server_pubkey.encode(Base64Encoder).decode('ascii') -_junk_parser = pyonionreq.junk.Parser(privkey=_privkey_bytes, pubkey=server_pubkey_bytes) -parse_junk = _junk_parser.parse_junk - def verify_sig_from_pk(data, sig, pk): return VerifyKey(pk).verify(data, sig) @@ -87,29 +85,26 @@ def server_encrypt(pk, data): return nonce + AESGCM(secret).encrypt(nonce, data, None) -xed25519_sign = pyonionreq.xed25519.sign -xed25519_verify = pyonionreq.xed25519.verify -xed25519_pubkey = pyonionreq.xed25519.pubkey - -# AKA "k" for blinding crypto: -blinding_factor = sodium.crypto_core_ed25519_scalar_reduce( +# AKA "k" for deprecated 15xxx blinding crypto: +blinding15_factor = sodium.crypto_core_ed25519_scalar_reduce( blake2b(server_pubkey_bytes, digest_size=64) ) +b15_inv = sodium.crypto_core_ed25519_scalar_invert(blinding15_factor) @functools.lru_cache(maxsize=1024) -def compute_blinded_abs_key(x_pk: bytes, *, k: bytes = blinding_factor): +def compute_blinded_abs_key_base(x_pk: bytes, *, k: bytes): """ Computes the *positive* blinded Ed25519 pubkey from an unprefixed session X25519 pubkey (i.e. 32 - bytes). The returned value will always have the sign bit (i.e. the most significant bit of the - last byte) set to 0; the actual derived key associated with this session id could have either - sign. + bytes) and blinding factor. The returned value will always have the sign bit (i.e. the most + significant bit of the last byte) set to 0; the actual derived key associated with this session + id could have either sign. - Input and result are in bytes, without the 0x05 or 0x15 prefix. + Input and result are raw pubkeys as bytes (i.e. no 0x05/0x15/0x25 prefix). - k allows you to compute for an alternative blinding factor, but should normally be omitted. + k is specific to the type of ublinding in use (e.g. 15xx or 25xx use different k values). """ - A = xed25519_pubkey(x_pk) + A = xed25519.pubkey(x_pk) kA = sodium.crypto_scalarmult_ed25519_noclamp(k, A) if kA[31] & 0x80: @@ -117,21 +112,75 @@ def compute_blinded_abs_key(x_pk: bytes, *, k: bytes = blinding_factor): return kA -def compute_blinded_abs_id(session_id: str, *, k: bytes = blinding_factor): +def compute_blinded15_abs_key(x_pk: bytes, *, _k: bytes = blinding15_factor): + """ + Computes the *positive* deprecated 15xxx blinded Ed25519 pubkey from an unprefixed session + X25519 pubkey (i.e. 32 bytes). + + Input and result are in bytes, without the 0x05 or 0x15 prefix. + + _k is used by the test suite to use an alternate blinding factor and should not normally be + passed. + """ + return compute_blinded_abs_key_base(x_pk, k=_k) + + +def compute_blinded15_abs_id(session_id: str, *, _k: bytes = blinding15_factor): """ - Computes the *positive* blinded id, as hex, from a prefixed, hex session id. This function is a - wrapper around compute_derived_key_bytes that handles prefixes and hex conversions. + Computes the *positive* 15xxx deprecated blinded id, as hex, from a prefixed, hex session id. + This function is a wrapper around compute_blinded15_abs_key that handles prefixes and hex + conversions. - k allows you to compute for an alternative blinding factor, but should normally be omitted. + _k is used by the test suite to use an alternate blinding factor and should not normally be + passed. """ - return '15' + compute_blinded_abs_key(bytes.fromhex(session_id[2:]), k=k).hex() + return '15' + compute_blinded15_abs_key(bytes.fromhex(session_id[2:]), _k=_k).hex() + + +@functools.lru_cache(maxsize=1024) +def compute_blinded25_key_from_15(blinded15_pubkey: bytes, *, _server_pk: Optional[bytes] = None): + """ + Computes a 25xxx blinded key from a given 15xxx blinded key. Takes just the pubkey (i.e. not + including the 0x15) as bytes, returns just the pubkey as bytes (i.e. no 0x25 prefix). + + _server_pk is only for the test suite and should not be passed. + """ + if _server_pk is None: + _server_pk = server_pubkey_bytes + k15_inv = b15_inv + else: + k15_inv = sodium.crypto_core_ed25519_scalar_invert( + sodium.crypto_core_ed25519_scalar_reduce(blake2b(_server_pk, digest_size=64)) + ) + + ed = sodium.crypto_scalarmult_ed25519_noclamp(k15_inv, blinded15_pubkey) + x = sodium.crypto_sign_ed25519_pk_to_curve25519(ed) + return blinding.blind25_id(x, _server_pk)[1:] + + +def compute_blinded25_id_from_15(blinded15_id: str, *, _server_pk: Optional[bytes] = None): + """ + Same as above, but works on and returns prefixed hex strings. + """ + return ( + '25' + + compute_blinded25_key_from_15( + bytes.fromhex(blinded15_id[2:]), _server_pk=_server_pk + ).hex() + ) + + +def compute_blinded25_id_from_05(session_id: str, *, _server_pk: Optional[bytes] = None): + if _server_pk is None: + _server_pk = server_pubkey_bytes + return '25' + blinding.blind25_id(bytes.fromhex(session_id[2:]), _server_pk)[1:].hex() -def blinded_abs(blinded_id: str): +def blinded15_abs(blinded_id: str): """ - Takes a blinded hex pubkey (i.e. length 66, prefixed with 15) and returns the positive pubkey - alternative: that is, if the pubkey is already positive, it is returned as-is; otherwise the - returned value is a copy with the sign bit cleared. + Takes a 15-blinded hex pubkey (i.e. length 66, prefixed with 15) and returns the positive pubkey + alternative (including prefix): that is, if the pubkey is already positive, it is returned + as-is; otherwise the returned value is a copy with the sign bit cleared. """ # Sign bit is the MSB of the last byte, which will be at [31] of the private key, hence 64 is @@ -142,9 +191,9 @@ def blinded_abs(blinded_id: str): return blinded_id -def blinded_neg(blinded_id: str): +def blinded15_neg(blinded_id: str): """ - Counterpart to blinded_abs that always returns the *negative* pubkey alternative. + Counterpart to blinded15_abs that always returns the *negative* pubkey alternative. """ msn = int(blinded_id[64], 16) diff --git a/sogs/db.py b/sogs/db.py index f078fa9c..5e52a410 100644 --- a/sogs/db.py +++ b/sogs/db.py @@ -5,6 +5,7 @@ import logging import importlib.resources import sqlalchemy +from sys import version_info as python_version from sqlalchemy.sql.expression import bindparam HAVE_FILE_ID_HACKS = False @@ -51,7 +52,7 @@ def query(query, *, dbconn=None, bind_expanding=None, **params): if bind_expanding: q = q.bindparams(*(bindparam(c, expanding=True) for c in bind_expanding)) - return dbconn.execute(q, **params) + return dbconn.execute(q, params) # Begins a (potentially nested) transaction. Takes an optional connection; if omitted uses @@ -108,6 +109,16 @@ def insert_and_get_row(insert, _table, _pk, *, dbconn=None, **params): return query(f"SELECT * FROM {_table} WHERE {_pk} = :pk", pk=pkval).first() +def read_schema(flavour: str): + if python_version >= (3, 9): + with (importlib.resources.files('sogs') / f"schema.{flavour}").open( + "r", encoding='utf-8', errors='strict' + ) as f: + return f.read() + else: + return importlib.resources.read_text('sogs', f"schema.{flavour}") + + def database_init(create=None, upgrade=True): """ Perform database initialization: constructs the schema, if necessary, and performs any required @@ -140,10 +151,10 @@ def database_init(create=None, upgrade=True): logging.warning("No database detected; creating new database schema") if engine.name == "sqlite": - conn.connection.executescript(importlib.resources.read_text('sogs', 'schema.sqlite')) + conn.connection.executescript(read_schema('sqlite')) elif engine.name == "postgresql": cur = conn.connection.cursor() - cur.execute(importlib.resources.read_text('sogs', 'schema.pgsql')) + cur.execute(read_schema('pgsql')) cur.close() else: err = f"Don't know how to create the database for {engine.name}" @@ -174,8 +185,6 @@ def database_init(create=None, upgrade=True): # Make sure the system admin users exists create_admin_user(conn) - check_needs_blinding(conn) - return created or migrated @@ -197,42 +206,6 @@ def create_admin_user(dbconn): ) -def check_needs_blinding(dbconn): - if not config.REQUIRE_BLIND_KEYS: - return - - with transaction(dbconn): - for uid, sid in query( - """ - SELECT id, session_id FROM users WHERE id IN ( - SELECT "user" FROM user_permission_overrides - UNION - SELECT "user" FROM user_permission_futures - UNION - SELECT "user" FROM user_ban_futures - UNION - SELECT id FROM users WHERE session_id LIKE '05%' AND (admin OR moderator OR banned) - EXCEPT - SELECT "user" FROM needs_blinding - ) - AND session_id LIKE '05%' - """, - dbconn=dbconn, - ): - try: - pos_derived = crypto.compute_blinded_abs_id(sid) - except Exception as e: - logging.warning(f"Failed to blind session_id {sid}: {e}") - continue - - query( - 'INSERT INTO needs_blinding (blinded_abs, "user") VALUES (:blinded, :uid)', - blinded=pos_derived, - uid=uid, - dbconn=dbconn, - ) - - engine, engine_initial_pid, metadata = None, None, None @@ -300,7 +273,7 @@ def sqlite_fix_connect(dbapi_connection, connection_record): @sqlalchemy.event.listens_for(engine, "begin") def do_begin(conn): # emit our own BEGIN - conn.execute("BEGIN IMMEDIATE") + conn.exec_driver_sql("BEGIN IMMEDIATE") else: have_returning = True diff --git a/sogs/migrations/__init__.py b/sogs/migrations/__init__.py index e1c797c2..53ed2d8a 100644 --- a/sogs/migrations/__init__.py +++ b/sogs/migrations/__init__.py @@ -4,6 +4,7 @@ from .. import config from . import ( + blind25, file_message, fix_info_update_triggers, import_hacks, @@ -43,6 +44,7 @@ def migrate(conn, *, check_only=False): seqno_etc, reactions, seqno_creation, + blind25, message_views, user_perm_futures, room_accessible, diff --git a/sogs/migrations/blind25.py b/sogs/migrations/blind25.py new file mode 100644 index 00000000..4e5e341a --- /dev/null +++ b/sogs/migrations/blind25.py @@ -0,0 +1,110 @@ +import logging +from .exc import DatabaseUpgradeRequired +from sqlalchemy.schema import UniqueConstraint + + +def migrate(conn, *, check_only): + """ + Migrates any 05 or 15 session_id in users to 25 and updates references to + that table accordingly, de-duplicating as necessary as well + """ + + from .. import db, crypto + + if 'alt_id' in db.metadata.tables['messages'].c: + return False + + if check_only: + raise DatabaseUpgradeRequired("Tables need to be migrated to 25-blinded") + + logging.warning("DB migration: Migrating tables to 25-blinded only") + + conn.execute(f"ALTER TABLE messages ADD COLUMN alt_id TEXT") + conn.execute(f"ALTER TABLE inbox ADD COLUMN alt_id TEXT") + + user_rows_15 = db.query("SELECT * FROM users WHERE session_id LIKE '15%'", dbconn=conn) + for row in user_rows_15.all(): + b15_id = row["session_id"] + rowid = row["id"] + b25 = crypto.compute_blinded25_id_from_15(b15_id) + + conn.execute( + 'UPDATE users SET session_id = :b25 WHERE session_id = :b15_id', b25=b25, b15_id=b15_id + ) + conn.execute( + 'UPDATE messages SET alt_id = :b15_id WHERE "user" = :rowid', b15_id=b15_id, rowid=rowid + ) + conn.execute( + 'UPDATE inbox SET alt_id = :b15_id WHERE "sender" = :rowid', b15_id=b15_id, rowid=rowid + ) + + user_rows_05 = db.query("SELECT * FROM users WHERE session_id LIKE '05%'", dbconn=conn) + for row in user_rows_05.all(): + b05_id = row["session_id"] + rowid = row["id"] + b25 = crypto.compute_blinded25_id_from_05(b05_id) + + new_row = db.query( + "SELECT id FROM users WHERE session_id = :b25", b25=b25, dbconn=conn + ).first() + + # if there were both 05 and 15 user rows for the 25 key, drop the 05 row and point references + # to it to the (modified to 25 above) old 15 row, else do basically as above for the 15 rows + # if both were present, update tables referencing users to reference the 25 row + if new_row: + rowid = new_row["id"] + conn.execute( + 'UPDATE messages SET whisper = :rowid WHERE whisper = :oldrow', + rowid=rowid, + oldrow=row["id"], + ) + conn.execute( + 'UPDATE messages SET user = :rowid, alt_id = :b05_id WHERE user = :oldrow', + rowid=rowid, + b05_id=b05_id, + oldrow=row["id"], + ) + conn.execute( + 'UPDATE pinned_messages SET pinned_by = :rowid WHERE pinned_by = :oldrow', + rowid=rowid, + oldrow=row["id"], + ) + conn.execute( + 'UPDATE files SET uploader = :rowid WHERE uploader = :oldrow', + rowid=rowid, + oldrow=row["id"], + ) + conn.execute( + 'UPDATE user_reactions SET "user" = :rowid WHERE "user" = :oldrow ON CONFLICT IGNORE', + rowid=rowid, + oldrow=row["id"], + ) + conn.execute( + 'UPDATE room_users SET "user" = :rowid WHERE "user" = :oldrow ON CONFLICT IGNORE', + rowid=rowid, + oldrow=row["id"], + ) + conn.execute( + 'UPDATE inbox SET recipient = :rowid WHERE recipient = :oldrow', + rowid=rowid, + oldrow=row["id"], + ) + conn.execute( + 'UPDATE inbox SET sender = :rowid, alt_id = :b05_id WHERE sender = :oldrow', + rowid=rowid, + b05_id=b05_id, + oldrow=row["id"], + ) + conn.execute('DELETE FROM users WHERE id = :oldrow', oldrow=row["id"]) + else: + conn.execute( + 'UPDATE users SET session_id = :b25 WHERE session_id = :b05_id', + b25=b25, + b05_id=b05_id, + ) + + conn.execute( + 'UPDATE messages SET alt_id = :b05_id WHERE "user" = :rowid', b05_id=b05_id, rowid=rowid + ) + + return True diff --git a/sogs/migrations/file_message.py b/sogs/migrations/file_message.py index 14eac2e5..d8680644 100644 --- a/sogs/migrations/file_message.py +++ b/sogs/migrations/file_message.py @@ -3,7 +3,6 @@ def migrate(conn, *, check_only): - from .. import db fix_fk = False diff --git a/sogs/migrations/import_hacks.py b/sogs/migrations/import_hacks.py index 1556cb70..2db9d46a 100644 --- a/sogs/migrations/import_hacks.py +++ b/sogs/migrations/import_hacks.py @@ -43,7 +43,7 @@ def migrate(conn, *, check_only): rows = conn.execute( "SELECT room, old_message_id_max, message_id_offset FROM room_import_hacks" ) - for (room, id_max, offset) in rows: + for room, id_max, offset in rows: db.ROOM_IMPORT_HACKS[room] = (id_max, offset) if not db.HAVE_FILE_ID_HACKS and 'room_import_hacks' not in db.metadata.tables: diff --git a/sogs/migrations/message_views.py b/sogs/migrations/message_views.py index 3ae03d41..1121b660 100644 --- a/sogs/migrations/message_views.py +++ b/sogs/migrations/message_views.py @@ -5,28 +5,42 @@ def migrate(conn, *, check_only): from .. import db - if 'message_metadata' in db.metadata.tables and all( - x in db.metadata.tables['message_metadata'].c - for x in ('whisper_to', 'whisper_mods', 'filtered', 'seqno', 'seqno_data') - ): - query_bad_trigger = ( - """ - SELECT COUNT(*) FROM sqlite_master - WHERE type = 'trigger' AND name = 'message_details_deleter' - AND sql LIKE :like_bad - """ - if db.engine.name == "sqlite" - else """ - SELECT COUNT(*) FROM information_schema.routines - WHERE routine_name = 'trigger_message_details_deleter' - AND routine_definition LIKE :like_bad - """ + need_migration = False + + if not ( + 'message_metadata' in db.metadata.tables + and all( + x in db.metadata.tables['message_metadata'].c + for x in ('whisper_to', 'whisper_mods', 'filtered', 'seqno', 'seqno_data') ) - if ( - db.query(query_bad_trigger, dbconn=conn, like_bad='%DELETE FROM reactions%').first()[0] - == 0 - ): - return False + ): + need_migration = True + + query_bad_trigger = ( + """ + SELECT COUNT(*) FROM sqlite_master + WHERE type = 'trigger' AND name = 'message_details_deleter' + AND sql LIKE :like_bad + """ + if db.engine.name == "sqlite" + else """ + SELECT COUNT(*) FROM information_schema.routines + WHERE routine_name = 'trigger_message_details_deleter' + AND routine_definition LIKE :like_bad + """ + ) + if db.query(query_bad_trigger, dbconn=conn, like_bad='%DELETE FROM reactions%').first()[0] != 0: + need_migration = True + + # added in 25-blinding + if not ( + 'message_details' in db.metadata.tables + and 'signing_id' in db.metadata.tables['message_details'].c + ): + need_migration = True + + if not need_migration: + return False logging.warning("DB migration: recreating message_metadata/message_details views") if check_only: @@ -40,7 +54,7 @@ def migrate(conn, *, check_only): conn.execute( """ CREATE VIEW message_details AS -SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to +SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to, COALESCE(messages.alt_id, uposter.session_id) AS signing_id FROM messages JOIN users uposter ON messages."user" = uposter.id LEFT JOIN users uwhisper ON messages.whisper = uwhisper.id @@ -58,6 +72,7 @@ def migrate(conn, *, check_only): END """ ) + # FIXME: this view appears unused, remove? conn.execute( """ CREATE VIEW message_metadata AS @@ -75,7 +90,7 @@ def migrate(conn, *, check_only): -- table of the user who posted it, and the session id of the whisper recipient (as `whisper_to`) if -- a directed whisper. CREATE VIEW message_details AS -SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to +SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to, COALESCE(messages.alt_id, uposter.session_id) AS signing_id FROM messages JOIN users uposter ON messages.user = uposter.id LEFT JOIN users uwhisper ON messages.whisper = uwhisper.id; diff --git a/sogs/migrations/new_tables.py b/sogs/migrations/new_tables.py index e855d956..ea89604a 100644 --- a/sogs/migrations/new_tables.py +++ b/sogs/migrations/new_tables.py @@ -52,22 +52,6 @@ expiry FLOAT DEFAULT (extract(epoch from now() + '15 days')) ); CREATE INDEX inbox_recipient ON inbox(recipient); -""", - }, - 'needs_blinding': { - 'sqlite': [ - """ -CREATE TABLE needs_blinding ( - blinded_abs TEXT NOT NULL PRIMARY KEY, - "user" BIGINT NOT NULL UNIQUE REFERENCES users ON DELETE CASCADE -) -""" - ], - 'pgsql': """ -CREATE TABLE needs_blinding ( - blinded_abs TEXT NOT NULL PRIMARY KEY, - "user" BIGINT NOT NULL UNIQUE REFERENCES users ON DELETE CASCADE -) """, }, } diff --git a/sogs/migrations/reactions.py b/sogs/migrations/reactions.py index acff1aa7..32acecda 100644 --- a/sogs/migrations/reactions.py +++ b/sogs/migrations/reactions.py @@ -3,7 +3,6 @@ def migrate(conn, *, check_only): - from .. import db if 'user_reactions' in db.metadata.tables: @@ -177,7 +176,6 @@ def migrate(conn, *, check_only): ) else: # postgresql - if 'seqno_data' not in db.metadata.tables['messages'].c: conn.execute( """ diff --git a/sogs/migrations/v_0_1_x.py b/sogs/migrations/v_0_1_x.py index b59c1ef3..eb7716f0 100644 --- a/sogs/migrations/v_0_1_x.py +++ b/sogs/migrations/v_0_1_x.py @@ -5,10 +5,11 @@ import logging import time from .exc import DatabaseUpgradeRequired +from .. import db def migrate(conn, *, check_only): - n_rooms = conn.execute("SELECT COUNT(*) FROM rooms").first()[0] + n_rooms = db.query("SELECT COUNT(*) FROM rooms", dbconn=conn).first()[0] # Migration from a v0.1.x database: if n_rooms > 0 or not os.path.exists("database.db"): @@ -39,7 +40,6 @@ def sqlite_connect_readonly(path): def import_from_0_1_x(conn): - from .. import config, db, utils # Old database database.db is a single table database containing just the list of rooms: @@ -109,7 +109,6 @@ def ins_user(session_id): ) with sqlite_connect_readonly(room_db_path) as rconn: - # Messages were stored in this: # # CREATE TABLE IF NOT EXISTS messages ( @@ -235,7 +234,6 @@ def ins_user(session_id): and data in (None, "deleted") and signature in (None, "deleted") ): - # Deleted message; we still need to insert a tombstone for it, and copy the # deletion id as the "seqno" field. (We do this with a second query # because the first query is going to trigger an automatic update of the @@ -340,7 +338,6 @@ def ins_user(session_id): n_files = rconn.execute("SELECT COUNT(*) FROM files").fetchone()[0] for file_id, timestamp in rconn.execute("SELECT id, timestamp FROM files"): - # file_id is an integer value but stored in a TEXT field, of course. file_id = int(file_id) @@ -507,7 +504,6 @@ def ins_user(session_id): """, (import_cutoff,), ): - ins_user(session_id) db.query( """ diff --git a/sogs/model/__init__.py b/sogs/model/__init__.py index 292ca751..7a76f30b 100644 --- a/sogs/model/__init__.py +++ b/sogs/model/__init__.py @@ -15,9 +15,10 @@ capabilities = { 'sogs', # Basic sogs capabilities 'reactions', # Reactions, added in 0.3.1 + 'blind25', # v2 blinded keys, "25xxx", are supported (check `blind` to see if required) # 'newcap', # Add here } if config.REQUIRE_BLIND_KEYS: - # indicate blinding required if configured to do so + # indicates that blinding is required capabilities.add('blind') diff --git a/sogs/model/message.py b/sogs/model/message.py index a40bca52..4896b56a 100644 --- a/sogs/model/message.py +++ b/sogs/model/message.py @@ -14,9 +14,10 @@ class Message: recip: recipant user of the message data: opaque message data signature: signature of data + alt_id: signing key if not 25-blinded session id """ - def __init__(self, row=None, *, sender=None, recip=None, data=None): + def __init__(self, row=None, *, sender=None, recip=None, data=None, alt_id=None): """ Constructs a Message from a pre-retrieved row *or* sender recipient and data. """ @@ -28,8 +29,8 @@ def __init__(self, row=None, *, sender=None, recip=None, data=None): row = insert_and_get_row( """ - INSERT INTO inbox (sender, recipient, body, expiry) - VALUES (:sender, :recipient, :data, :expiry) + INSERT INTO inbox (sender, recipient, body, expiry, alt_id) + VALUES (:sender, :recipient, :data, :expiry, :alt_id) """, "inbox", "id", @@ -37,6 +38,7 @@ def __init__(self, row=None, *, sender=None, recip=None, data=None): recipient=recip.id, data=data, expiry=time.time() + config.DM_EXPIRY, + alt_id=alt_id, ) # sanity check assert row is not None @@ -112,6 +114,14 @@ def sender(self): self._sender = User(id=self._row['sender'], autovivify=False) return self._sender + @property + def signing_key(self): + if not hasattr(self, "_signing_key"): + self._signing_key = self._row['alt_id'] + if self._signing_key is None: + self._signing_key = User(id=self._row['sender'], autovivify=False).session_id + return self._signing_key + @property def recipient(self): if not hasattr(self, "_recip"): diff --git a/sogs/model/post.py b/sogs/model/post.py index b0d3a5a0..463ad1fc 100644 --- a/sogs/model/post.py +++ b/sogs/model/post.py @@ -18,17 +18,17 @@ def __init__(self, raw=None, *, user=None, text=None): @property def text(self): - """ accessor for the post body """ + """accessor for the post body""" return self._proto.body @property def username(self): - """ accessor for the username of the post's author """ + """accessor for the username of the post's author""" if self.profile is None: return return self.profile.displayName @property def profile(self): - """ accessor for the user profile data containing things like username etc """ + """accessor for the user profile data containing things like username etc""" return self._proto.profile diff --git a/sogs/model/room.py b/sogs/model/room.py index 7217b116..2ac7b403 100644 --- a/sogs/model/room.py +++ b/sogs/model/room.py @@ -703,7 +703,8 @@ def get_messages_for( msgs.append({x: row[x] for x in ('id', 'seqno')}) continue - msg = {x: row[x] for x in ('id', 'session_id', 'posted', 'seqno')} + msg = {x: row[x] for x in ('id', 'posted', 'seqno')} + msg["session_id"] = row["signing_id"] data = row['data'] if data is None: msg['data'] = None @@ -856,8 +857,8 @@ def msg(): if msg_fmt: pbmsg = protobuf.Content() body = msg_fmt.format( - profile_name=(user.session_id if msg().username is None else msg().username), - profile_at="@" + user.session_id, + profile_name=(user.using_id if msg().username is None else msg().username), + profile_at="@" + user.using_id, room_name=self.name, room_token=self.token, ).encode() @@ -1006,9 +1007,9 @@ def add_post( msg_id = db.insert_and_get_pk( """ INSERT INTO messages - (room, "user", data, data_size, signature, filtered, whisper, whisper_mods) + (room, "user", data, data_size, signature, filtered, whisper, whisper_mods, alt_id) VALUES - (:r, :u, :data, :data_size, :signature, :filtered, :whisper, :whisper_mods) + (:r, :u, :data, :data_size, :signature, :filtered, :whisper, :whisper_mods, :alt_id) """, "id", r=self.id, @@ -1019,6 +1020,7 @@ def add_post( filtered=filtered is not None, whisper=whisper_to.id if whisper_to else None, whisper_mods=whisper_mods, + alt_id=user.using_id if user.using_id else None, ) if files: @@ -1029,7 +1031,7 @@ def add_post( row = query("SELECT posted, seqno FROM messages WHERE id = :m", m=msg_id).first() msg = { 'id': msg_id, - 'session_id': user.session_id, + 'session_id': user.using_id, 'posted': row[0], 'seqno': row[1], 'data': data, @@ -1042,7 +1044,7 @@ def add_post( msg['whisper'] = True msg['whisper_mods'] = whisper_mods if whisper_to: - msg['whisper_to'] = whisper_to.session_id + msg['whisper_to'] = whisper_to.using_id # Don't call this inside the transaction because, if it's inserting a reply, we want the # reply to have a later timestamp for proper ordering (because the timestamp inside a @@ -1578,34 +1580,33 @@ def set_moderator(self, user: User, *, added_by: User, admin=False, visible=True raise BadPermission() with db.transaction(): - with user.check_blinding() as u: - query( - f""" - INSERT INTO user_permission_overrides - (room, - "user", - moderator, - {'admin,' if admin is not None else ''} - visible_mod) - VALUES (:r, :u, TRUE, {':admin,' if admin is not None else ''} :visible) - ON CONFLICT (room, "user") DO UPDATE SET - moderator = excluded.moderator, - {'admin = excluded.admin,' if admin is not None else ''} - visible_mod = excluded.visible_mod - """, - r=self.id, - u=u.id, - admin=admin, - visible=visible, - ) + query( + f""" + INSERT INTO user_permission_overrides + (room, + "user", + moderator, + {'admin,' if admin is not None else ''} + visible_mod) + VALUES (:r, :u, TRUE, {':admin,' if admin is not None else ''} :visible) + ON CONFLICT (room, "user") DO UPDATE SET + moderator = excluded.moderator, + {'admin = excluded.admin,' if admin is not None else ''} + visible_mod = excluded.visible_mod + """, + r=self.id, + u=user.id, + admin=admin, + visible=visible, + ) - self._refresh() - if u.id in self._perm_cache: - del self._perm_cache[u.id] + self._refresh() + if user.id in self._perm_cache: + del self._perm_cache[user.id] - app.logger.info( - f"{added_by} set {u} as {'admin' if admin else 'moderator'} of {self}" - ) + app.logger.info( + f"{added_by} set {user} as {'admin' if admin else 'moderator'} of {self}" + ) def remove_moderator(self, user: User, *, removed_by: User, remove_admin_only: bool = False): """ @@ -1619,23 +1620,22 @@ def remove_moderator(self, user: User, *, removed_by: User, remove_admin_only: b raise BadPermission() with db.transaction(): - with user.check_blinding() as u: - query( - f""" - UPDATE user_permission_overrides - SET admin = FALSE - {', moderator = FALSE, visible_mod = TRUE' if not remove_admin_only else ''} - WHERE room = :r AND "user" = :u - """, - r=self.id, - u=user.id, - ) + query( + f""" + UPDATE user_permission_overrides + SET admin = FALSE + {', moderator = FALSE, visible_mod = TRUE' if not remove_admin_only else ''} + WHERE room = :r AND "user" = :u + """, + r=self.id, + u=user.id, + ) - self._refresh() - if user.id in self._perm_cache: - del self._perm_cache[user.id] + self._refresh() + if user.id in self._perm_cache: + del self._perm_cache[user.id] - app.logger.info(f"{removed_by} removed {u} as mod/admin of {self}") + app.logger.info(f"{removed_by} removed {user} ({user.using_id}) as mod/admin of {self}") def ban_user(self, to_ban: User, *, mod: User, timeout: Optional[float] = None): """ @@ -1652,58 +1652,57 @@ def ban_user(self, to_ban: User, *, mod: User, timeout: Optional[float] = None): """ with db.transaction(): - with to_ban.check_blinding() as to_ban: - fail = None - if not self.check_moderator(mod): - fail = "user is not a moderator" - elif to_ban.id == mod.id: - fail = "self-ban not permitted" - elif to_ban.global_moderator: - fail = "global mods/admins cannot be banned" - elif self.check_moderator(to_ban) and not self.check_admin(mod): - fail = "only admins can ban room mods/admins" - - if fail is not None: - app.logger.warning(f"Error banning {to_ban} from {self} by {mod}: {fail}") - raise BadPermission() - - # TODO: log the banning action for auditing + fail = None + if not self.check_moderator(mod): + fail = "user is not a moderator" + elif to_ban.id == mod.id: + fail = "self-ban not permitted" + elif to_ban.global_moderator: + fail = "global mods/admins cannot be banned" + elif self.check_moderator(to_ban) and not self.check_admin(mod): + fail = "only admins can ban room mods/admins" + + if fail is not None: + app.logger.warning(f"Error banning {to_ban} from {self} by {mod}: {fail}") + raise BadPermission() + + # TODO: log the banning action for auditing + query( + """ + INSERT INTO user_permission_overrides (room, "user", banned, moderator, admin) + VALUES (:r, :ban, TRUE, FALSE, FALSE) + ON CONFLICT (room, "user") DO + UPDATE SET banned = TRUE, moderator = FALSE, admin = FALSE + """, + r=self.id, + ban=to_ban.id, + ) + + # Replace (or remove) an existing scheduled bans/unbans: + query( + 'DELETE FROM user_ban_futures WHERE room = :r AND "user" = :u', + r=self.id, + u=to_ban.id, + ) + if timeout: query( """ - INSERT INTO user_permission_overrides (room, "user", banned, moderator, admin) - VALUES (:r, :ban, TRUE, FALSE, FALSE) - ON CONFLICT (room, "user") DO - UPDATE SET banned = TRUE, moderator = FALSE, admin = FALSE + INSERT INTO user_ban_futures + (room, "user", banned, at) VALUES (:r, :u, FALSE, :at) """, r=self.id, - ban=to_ban.id, - ) - - # Replace (or remove) an existing scheduled bans/unbans: - query( - 'DELETE FROM user_ban_futures WHERE room = :r AND "user" = :u', - r=self.id, u=to_ban.id, + at=time.time() + timeout, ) - if timeout: - query( - """ - INSERT INTO user_ban_futures - (room, "user", banned, at) VALUES (:r, :u, FALSE, :at) - """, - r=self.id, - u=to_ban.id, - at=time.time() + timeout, - ) - if to_ban.id in self._perm_cache: - del self._perm_cache[to_ban.id] + if to_ban.id in self._perm_cache: + del self._perm_cache[to_ban.id] - app.logger.debug( - f"Banned {to_ban} from {self} {f'for {timeout}s ' if timeout else ''}" - f"(banned by {mod})" - ) + app.logger.debug( + f"Banned {to_ban} from {self} {f'for {timeout}s ' if timeout else ''}" + f"(banned by {mod})" + ) def unban_user(self, to_unban: User, *, mod: User): """ @@ -1719,27 +1718,26 @@ def unban_user(self, to_unban: User, *, mod: User): raise BadPermission() with db.transaction(): - with to_unban.check_blinding() as to_unban: - result = query( - """ - UPDATE user_permission_overrides SET banned = FALSE - WHERE room = :r AND "user" = :unban AND banned - """, - r=self.id, - unban=to_unban.id, - ) - if result.rowcount > 0: - app.logger.debug(f"{mod} unbanned {to_unban} from {self}") + result = query( + """ + UPDATE user_permission_overrides SET banned = FALSE + WHERE room = :r AND "user" = :unban AND banned + """, + r=self.id, + unban=to_unban.id, + ) + if result.rowcount > 0: + app.logger.warning(f"{mod} unbanned {to_unban} from {self}") - if to_unban.id in self._perm_cache: - del self._perm_cache[to_unban.id] + if to_unban.id in self._perm_cache: + del self._perm_cache[to_unban.id] - return True + return True - app.logger.debug( - f"{mod} unbanned {to_unban} from {self} (but user was already unbanned)" - ) - return False + app.logger.warning( + f"{mod} unbanned {to_unban} from {self} (but user was already unbanned)" + ) + return False def get_bans(self): """ @@ -1790,27 +1788,26 @@ def set_permissions(self, user: User, *, mod: User, **perms): raise BadPermission() with db.transaction(): - with user.check_blinding() as user: - set_perms = perms.keys() - query( - f""" - INSERT INTO user_permission_overrides (room, "user", {', '.join(set_perms)}) - VALUES (:r, :u, :{', :'.join(set_perms)}) - ON CONFLICT (room, "user") DO UPDATE SET - {', '.join(f"{p} = :{p}" for p in set_perms)} - """, - r=self.id, - u=user.id, - read=perms.get('read'), - accessible=perms.get('accessible'), - write=perms.get('write'), - upload=perms.get('upload'), - ) + set_perms = perms.keys() + query( + f""" + INSERT INTO user_permission_overrides (room, "user", {', '.join(set_perms)}) + VALUES (:r, :u, :{', :'.join(set_perms)}) + ON CONFLICT (room, "user") DO UPDATE SET + {', '.join(f"{p} = :{p}" for p in set_perms)} + """, + r=self.id, + u=user.id, + read=perms.get('read'), + accessible=perms.get('accessible'), + write=perms.get('write'), + upload=perms.get('upload'), + ) - if user.id in self._perm_cache: - del self._perm_cache[user.id] + if user.id in self._perm_cache: + del self._perm_cache[user.id] - app.logger.debug(f"{mod} applied {self} permission(s) {perms} to {user}") + app.logger.debug(f"{mod} applied {self} permission(s) {perms} to {user}") def clear_future_permissions( self, @@ -1845,29 +1842,28 @@ def clear_future_permissions( return with db.transaction(): - with user.check_blinding() as u: - r = query( - f""" - UPDATE user_permission_futures - SET {', '.join(sets)} - WHERE room = :r AND "user" = :u + r = query( + f""" + UPDATE user_permission_futures + SET {', '.join(sets)} + WHERE room = :r AND "user" = :u + """, + r=self.id, + u=user.id, + ) + + # Clear any rows that we updated to all-nulls: + if r.rowcount > 0: + query( + """ + DELETE FROM user_permission_futures + WHERE room = :r AND "user" = :u AND + read = NULL AND write = NULL AND upload = NULL """, r=self.id, - u=u.id, + u=user.id, ) - # Clear any rows that we updated to all-nulls: - if r.rowcount > 0: - query( - """ - DELETE FROM user_permission_futures - WHERE room = :r AND "user" = :u AND - read = NULL AND write = NULL AND upload = NULL - """, - r=self.id, - u=u.id, - ) - def add_future_permission( self, user, @@ -1890,19 +1886,18 @@ def add_future_permission( return with db.transaction(): - with user.check_blinding() as u: - query( - """ - INSERT INTO user_permission_futures (room, "user", at, read, write, upload) - VALUES (:r, :u, :at, :read, :write, :upload) - """, - r=self.id, - u=u.id, - at=at, - read=read, - write=write, - upload=upload, - ) + query( + """ + INSERT INTO user_permission_futures (room, "user", at, read, write, upload) + VALUES (:r, :u, :at, :read, :write, :upload) + """, + r=self.id, + u=user.id, + at=at, + read=read, + write=write, + upload=upload, + ) def get_file(self, file_id: int): """Retrieves a file uploaded to this room by id. Returns None if not found.""" diff --git a/sogs/model/user.py b/sogs/model/user.py index e1b452e4..fb3e519b 100644 --- a/sogs/model/user.py +++ b/sogs/model/user.py @@ -16,7 +16,8 @@ class User: Properties: id - the database primary key for this user row - session_id - the session_id of the user, in hex + session_id - the 25-blinded session_id of the user, in hex + using_id - the session_id being used by the user, in hex created - unix timestamp when the user was created last_active - unix timestamp when the user was last active banned - True if the user is (globally) banned @@ -33,7 +34,6 @@ def __init__( session_id: Optional[str] = None, autovivify: bool = True, touch: bool = False, - try_blinding: bool = False, ): """ Constructs a user from a pre-retrieved row *or* a session id or user primary key value. @@ -43,19 +43,11 @@ def __init__( populate the object. This is the default behaviour. If False and the session_id doesn't exist then a NoSuchUser is raised if the session id doesn't exist. - try_blinding - if True and blinding is required, and a given `session_id` is given that is - *not* blinded then attempt to look up the possible blinded versions of the session id and - use one of those (if they exist) rather than the given unblinded id. If no blinded version - exists then the unblinded id will be used (check `.is_blinded` after construction to see if - we found and switched to the blinded id). - touch - if True (default is False) then update the last_activity time of this user before returning it. """ self._touched = False - self._refresh( - row=row, id=id, session_id=session_id, autovivify=autovivify, try_blinding=try_blinding - ) + self._refresh(row=row, id=id, session_id=session_id, autovivify=autovivify) if touch: self._touch() @@ -67,41 +59,34 @@ def _refresh( id: Optional[int] = None, session_id: Optional[str] = None, autovivify: bool = True, - try_blinding: bool = False, ): """ Internal method to (re-)fetch details from the database; this is used during construction but also in the test suite to forcibly re-fetch details. """ + self.using_id = session_id + n_args = sum(x is not None for x in (row, session_id, id)) if n_args == 0 and hasattr(self, 'id'): id = self.id elif n_args != 1: raise ValueError("User() error: exactly one of row/session_id/id is required") - self._tried_blinding = False - if session_id is not None: - if try_blinding and config.REQUIRE_BLIND_KEYS and session_id.startswith('05'): - b_pos = crypto.compute_blinded_abs_id(session_id) - b_neg = crypto.blinded_neg(b_pos) - row = query( - "SELECT * FROM users WHERE session_id IN (:pos, :neg) LIMIT 1", - pos=b_pos, - neg=b_neg, - ).first() - self._tried_blinding = True - - if not row: - row = query("SELECT * FROM users WHERE session_id = :s", s=session_id).first() + b25 = None + if session_id.startswith('05'): + b25 = crypto.compute_blinded25_id_from_05(session_id) + elif session_id.startswith('15'): + b25 = crypto.compute_blinded25_id_from_15(session_id) + else: + b25 = session_id - if not row and autovivify: - if config.REQUIRE_BLIND_KEYS: - row = self._import_blinded(session_id) + row = query("SELECT * FROM users WHERE session_id = :b25", b25=b25).first() + if not row and autovivify: if not row: row = db.insert_and_get_row( - "INSERT INTO users (session_id) VALUES (:s)", "users", "id", s=session_id + "INSERT INTO users (session_id) VALUES (:s)", "users", "id", s=b25 ) # No need to re-touch this user since we just created them: self._touched = True @@ -119,63 +104,10 @@ def _refresh( bool(row[c]) for c in ('banned', 'moderator', 'admin', 'visible_mod') ) - def _import_blinded(self, session_id): - """ - Attempts to import the user and permission rows from an unblinded session_id to a new, - blinded session_id row. - - Any permissions/bans are *moved* from the old, unblinded id to the new blinded user record. - """ - - if not session_id.startswith('15'): - return - blind_abs = crypto.blinded_abs(session_id.lower()) - with db.transaction(): - to_import = query( - """ - SELECT * FROM users WHERE id = ( - SELECT "user" FROM needs_blinding WHERE blinded_abs = :ba - ) - """, - ba=blind_abs, - ).fetchone() - - if to_import is None: - return False - - row = db.insert_and_get_row( - """ - INSERT INTO users - (session_id, created, last_active, banned, moderator, admin, visible_mod) - VALUES (:sid, :cr, :la, :ban, :mod, :admin, :vis) - """, - "users", - "id", - sid=session_id, - cr=to_import["created"], - la=to_import["last_active"], - ban=to_import["banned"], - mod=to_import["moderator"], - admin=to_import["admin"], - vis=to_import["visible_mod"], - ) - # If we have any global ban/admin/mod then clear them (because we've just set up the - # global ban/mod/admin permissions for the blinded id in the query above). - query( - "UPDATE users SET banned = FALSE, admin = FALSE, moderator = FALSE WHERE id = :u", - u=to_import["id"], - ) - - for t in ("user_permission_overrides", "user_permission_futures", "user_ban_futures"): - query( - f'UPDATE {t} SET "user" = :new WHERE "user" = :old', - new=row["id"], - old=to_import["id"], - ) - - query('DELETE FROM needs_blinding WHERE "user" = :u', u=to_import["id"]) + if self.using_id is None: + self.using_id = self.session_id - return row + self.is_blinded = not self.using_id.startswith('05') def __str__(self): """Returns string representation of a user: U[050123…cdef], the id prefixed with @ or % if @@ -237,22 +169,21 @@ def set_moderator(self, *, added_by: User, admin=False, visible=False): raise BadPermission() with db.transaction(): - with self.check_blinding() as u: - query( - f""" - UPDATE users - SET moderator = TRUE, visible_mod = :visible - {', admin = :admin' if admin is not None else ''} - WHERE id = :u - """, - admin=bool(admin), - visible=visible, - u=u.id, - ) + query( + f""" + UPDATE users + SET moderator = TRUE, visible_mod = :visible + {', admin = :admin' if admin is not None else ''} + WHERE id = :u + """, + admin=bool(admin), + visible=visible, + u=self.id, + ) - u.global_admin = admin - u.global_moderator = True - u.visible_mod = visible + self.global_admin = admin + self.global_moderator = True + self.visible_mod = visible def remove_moderator(self, *, removed_by: User, remove_admin_only: bool = False): """Removes this user's global moderator/admin status, if set.""" @@ -292,26 +223,27 @@ def ban(self, *, banned_by: User, timeout: Optional[float] = None): raise BadPermission() with db.transaction(): - with self.check_blinding() as u: - if u.global_moderator: - app.logger.warning(f"Cannot ban {u}: user is a global moderator/admin") - raise BadPermission() - - query("UPDATE users SET banned = TRUE WHERE id = :u", u=u.id) - query('DELETE FROM user_ban_futures WHERE room IS NULL AND "user" = :u', u=u.id) - - if timeout: - query( - """ - INSERT INTO user_ban_futures - ("user", room, banned, at) VALUES (:u, NULL, FALSE, :at) - """, - u=u.id, - at=time.time() + timeout, - ) + if self.global_moderator: + app.logger.warning(f"Cannot ban {self}: user is a global moderator/admin") + raise BadPermission() - app.logger.debug(f"{banned_by} globally banned {u}{f' for {timeout}s' if timeout else ''}") - u.banned = True + query("UPDATE users SET banned = TRUE WHERE id = :u", u=self.id) + query('DELETE FROM user_ban_futures WHERE room IS NULL AND "user" = :u', u=self.id) + + if timeout: + query( + """ + INSERT INTO user_ban_futures + ("user", room, banned, at) VALUES (:u, NULL, FALSE, :at) + """, + u=self.id, + at=time.time() + timeout, + ) + + app.logger.debug( + f"{banned_by} globally banned {self}{f' for {timeout}s' if timeout else ''}" + ) + self.banned = True def unban(self, *, unbanned_by: User): """ @@ -333,84 +265,9 @@ def verify(self, *, message: bytes, sig: bytes): """verify signature signed by this session id return True if the signature is valid otherwise return False """ - pk = crypto.xed25519_pubkey(bytes.fromhex(self.session_id[2:])) + pk = crypto.xed25519.pubkey(bytes.fromhex(self.session_id[2:])) return crypto.verify_sig_from_pk(message, sig, pk) - def find_blinded(self): - """ - Attempts to look up the blinded User associated with this (unblinded) session id. - - If this User is already a blinded id, this simply returns `self`. - - Otherwise, if we find a blinded id in the users table that corresponds to this (unblinded) - id we return a new User object for the blinded user. - - Otherwise returns None. - """ - if self.is_blinded: - return self - - if not self.session_id.startswith('05'): # Mainly here to catch the SystemUser - return None - - if self._tried_blinding: - # We already tried (and failed) to get the blinded id during construction - return None - - b_pos = crypto.compute_blinded_abs_id(self.session_id) - b_neg = crypto.blinded_neg(b_pos) - row = query( - "SELECT * FROM users WHERE session_id IN (:pos, :neg) LIMIT 1", pos=b_pos, neg=b_neg - ).first() - if not row: - self._tried_blinding = True - return None - - return User(row) - - @contextlib.contextmanager - def check_blinding(self): - """ - Context manager that checks to see if blinding is enabled and this user is an unblinded - user. If both are true, this attempts to look up the blinded User record for this user. - The User (either the blinded one or `self`) is yielded. Upon exiting the context - successfully `record_needs_blinding()` is called if required to set up the required blinding - information. - """ - user = self - need_blinding = False - if config.REQUIRE_BLIND_KEYS: - blinded = self.find_blinded() - if blinded is not None: - user = blinded - else: - need_blinding = True - - yield user - - if need_blinding: - user.record_needs_blinding() - - def record_needs_blinding(self): - """ - Inserts a database record into the `needs_blinding` table indicating that this user requires - permission or ban moves. This should only be called for an unblinded user for which - find_blinded did not find an existing blinded user row. - """ - query( - """ - INSERT INTO needs_blinding (blinded_abs, "user") VALUES (:b_abs, :u) - ON CONFLICT DO NOTHING - """, - b_abs=crypto.compute_blinded_abs_id(self.session_id), - u=self.id, - ) - - @property - def is_blinded(self): - """True if the user's session id is a derived key""" - return self.session_id.startswith('15') - @property def system_user(self): """True if (and only if) this is the special SOGS system user diff --git a/sogs/postfork.py b/sogs/postfork.py index 7c544c9d..6800e24b 100644 --- a/sogs/postfork.py +++ b/sogs/postfork.py @@ -11,7 +11,6 @@ def __init__(self, f): def __call__(self, f): pass - else: import uwsgidecorators diff --git a/sogs/routes/auth.py b/sogs/routes/auth.py index dbbf5abf..13315caf 100644 --- a/sogs/routes/auth.py +++ b/sogs/routes/auth.py @@ -261,11 +261,13 @@ def handle_http_auth(): http.BAD_REQUEST, "Invalid authentication: X-SOGS-Pubkey is not a valid 66-hex digit id" ) - if pk[0] not in (0x00, 0x15): + if pk[0] not in (0x00, 0x15, 0x25): abort_with_reason( - http.BAD_REQUEST, "Invalid authentication: X-SOGS-Pubkey must be 00- or 15- prefixed" + http.BAD_REQUEST, + "Invalid authentication: X-SOGS-Pubkey must be 00-, 15-, or 25- prefixed", ) - blinded_pk = pk[0] == 0x15 + blinded15_pk = pk[0] == 0x15 + blinded25_pk = pk[0] == 0x25 pk = pk[1:] if not sodium.crypto_core_ed25519_is_valid_point(pk): @@ -275,7 +277,9 @@ def handle_http_auth(): ) pk = VerifyKey(pk) - if blinded_pk: + if blinded25_pk: + session_id = '25' + pk.encode().hex() + elif blinded15_pk and not config.REQUIRE_BLIND_V2: session_id = '15' + pk.encode().hex() elif config.REQUIRE_BLIND_KEYS: abort_with_reason( diff --git a/sogs/routes/converters.py b/sogs/routes/converters.py index 41a48391..657341b7 100644 --- a/sogs/routes/converters.py +++ b/sogs/routes/converters.py @@ -27,10 +27,10 @@ def to_value(self, value): class AnySessionIDConverter(BaseConverter): """ - A 66-hex-character Session ID (`05...`) or blinded Session ID (`15...`). + A 66-hex-character Session ID (`05...`) or blinded Session ID (`15...` or `25...`). """ - regex = r"[01]5[0-9a-fA-F]{64}" + regex = r"[012]5[0-9a-fA-F]{64}" def to_python(self, value): return value @@ -38,10 +38,10 @@ def to_python(self, value): class BlindSessionIDConverter(BaseConverter): """ - A 66-hex-character blinded Session ID (`15...`). Non-blinded Session IDs are not permitted. + A 66-hex-character blinded Session ID (`15...` or `25...`). Non-blinded Session IDs are not permitted. """ - regex = r"15[0-9a-fA-F]{64}" + regex = r"[12]5[0-9a-fA-F]{64}" def to_python(self, value): return value diff --git a/sogs/routes/dm.py b/sogs/routes/dm.py index ac09ec28..38dc3b80 100644 --- a/sogs/routes/dm.py +++ b/sogs/routes/dm.py @@ -15,7 +15,7 @@ def _serialize_message(msg, include_message=True): "id": msg.id, "posted_at": msg.posted_at, "expires_at": msg.expires_at, - "sender": msg.sender.session_id, + "sender": msg.signing_key, "recipient": msg.recipient.session_id, } if include_message: @@ -93,6 +93,7 @@ def send_inbox(sid): 404 Not Found — if the given Session ID does not exist on this server, either because they have never accessed the server, or because they have been permanently banned. """ + print(f"inbox post, recipient = {sid}") try: recip_user = User(session_id=sid, autovivify=False) except NoSuchUser: @@ -108,7 +109,10 @@ def send_inbox(sid): abort(http.BAD_REQUEST) with db.transaction(): - msg = Message(data=utils.decode_base64(message), recip=recip_user, sender=g.user) + alt_id = g.user.using_id if g.user.using_id != g.user.session_id else None + msg = Message( + data=utils.decode_base64(message), recip=recip_user, sender=g.user, alt_id=alt_id + ) return jsonify(_serialize_message(msg, include_message=False)), http.CREATED diff --git a/sogs/routes/legacy.py b/sogs/routes/legacy.py index 1dee43b7..1ab52cfa 100644 --- a/sogs/routes/legacy.py +++ b/sogs/routes/legacy.py @@ -62,7 +62,7 @@ def legacy_check_user_room( if pubkey is None: if 'user' in g and g.user: - pubkey = g.user.session_id + pubkey = g.user.using_id else: pubkey = get_pubkey_from_token(request.headers.get("Authorization")) if not pubkey or len(pubkey) != (utils.SESSION_ID_SIZE * 2) or not pubkey.startswith('05'): @@ -186,7 +186,6 @@ def legacy_transform_message(m): @legacy.post("/messages") def handle_post_legacy_message(): - user, room = legacy_check_user_room(write=True) req = request.json @@ -335,7 +334,7 @@ def handle_legacy_single_delete(msgid): @legacy.post("/block_list") def handle_legacy_ban(): user, room = legacy_check_user_room(moderator=True) - ban = User(session_id=request.json['public_key'], autovivify=True, try_blinding=True) + ban = User(session_id=request.json['public_key'], autovivify=True) room.ban_user(to_ban=ban, mod=user) @@ -345,7 +344,7 @@ def handle_legacy_ban(): @legacy.post("/ban_and_delete_all") def handle_legacy_banhammer(): mod, room = legacy_check_user_room(moderator=True) - ban = User(session_id=request.json['public_key'], autovivify=True, try_blinding=True) + ban = User(session_id=request.json['public_key'], autovivify=True) with db.transaction(): room.ban_user(to_ban=ban, mod=mod) @@ -357,7 +356,7 @@ def handle_legacy_banhammer(): @legacy.delete("/block_list/") def handle_legacy_unban(session_id): user, room = legacy_check_user_room(moderator=True) - to_unban = User(session_id=session_id, autovivify=False, try_blinding=True) + to_unban = User(session_id=session_id, autovivify=False) if room.unban_user(to_unban, mod=user): return jsonify({"status_code": http.OK}) @@ -399,7 +398,7 @@ def handle_legacy_add_admin(): if len(session_id) != 66 or not session_id.startswith("05"): abort(http.BAD_REQUEST) - mod = User(session_id=session_id, autovivify=True, try_blinding=True) + mod = User(session_id=session_id, autovivify=True) room.set_moderator(mod, admin=True, visible=True, added_by=user) return jsonify({"status_code": http.OK}) @@ -412,7 +411,7 @@ def handle_legacy_add_admin(): def handle_legacy_remove_admin(session_id): user, room = legacy_check_user_room(admin=True) - mod = User(session_id=session_id, autovivify=False, try_blinding=True) + mod = User(session_id=session_id, autovivify=False) room.remove_moderator(mod, removed_by=user) return jsonify({"status_code": http.OK}) diff --git a/sogs/routes/onion_request.py b/sogs/routes/onion_request.py index bdf53a3d..4c2fb416 100644 --- a/sogs/routes/onion_request.py +++ b/sogs/routes/onion_request.py @@ -6,6 +6,8 @@ from .subrequest import make_subrequest +from session_util.onionreq import OnionReqParser + onion_request = Blueprint('onion_request', __name__) @@ -245,7 +247,7 @@ def handle_v4_onionreq_plaintext(body): def decrypt_onionreq(): try: - return crypto.parse_junk(request.data) + return OnionReqParser(crypto.server_pubkey_bytes, crypto._privkey_bytes, request.data) except Exception as e: app.logger.warning("Failed to decrypt onion request: {}".format(e)) abort(http.BAD_REQUEST) @@ -262,8 +264,8 @@ def handle_v3_onion_request(): Deprecated in favour of /v4/. """ - junk = decrypt_onionreq() - return utils.encode_base64(junk.transformReply(handle_v3_onionreq_plaintext(junk.payload))) + parser = decrypt_onionreq() + return utils.encode_base64(parser.encrypt_reply(handle_v3_onionreq_plaintext(parser.payload))) @onion_request.post("/oxen/v4/lsrpc") @@ -287,7 +289,7 @@ def handle_v4_onion_request(): # The parse_junk here takes care of decoding and decrypting this according to the fields *meant # for us* in the json (which include things like the encryption type and ephemeral key): try: - junk = crypto.parse_junk(request.data) + parser = decrypt_onionreq() except RuntimeError as e: app.logger.warning("Failed to decrypt onion request: {}".format(e)) abort(http.BAD_REQUEST) @@ -295,5 +297,5 @@ def handle_v4_onion_request(): # On the way back out we re-encrypt via the junk parser (which uses the ephemeral key and # enc_type that were specified in the outer request). We then return that encrypted binary # payload as-is back to the client which bounces its way through the SN path back to the client. - response = handle_v4_onionreq_plaintext(junk.payload) - return junk.transformReply(response) + response = handle_v4_onionreq_plaintext(parser.payload) + return parser.encrypt_reply(response) diff --git a/sogs/routes/rooms.py b/sogs/routes/rooms.py index 4487a71b..439e7938 100644 --- a/sogs/routes/rooms.py +++ b/sogs/routes/rooms.py @@ -333,7 +333,7 @@ def get_user_permission_info(room, sid): but not room defaults are included in the response. """ - user = muser.User(session_id=sid, try_blinding=True) + user = muser.User(session_id=sid) return jsonify(addExtraPermInfo(room.user_permissions(user))) @@ -364,7 +364,7 @@ def get_user_future_permissions(room, sid): id is known then this returns results for the blinded id rather than the unblinded id. """ - user = muser.User(session_id=sid, try_blinding=True) + user = muser.User(session_id=sid) return jsonify(room.user_future_permissions(user)) @@ -427,7 +427,7 @@ def set_permissions(room, sid): if the blinded ID is known to the server. """ - user = muser.User(session_id=sid, try_blinding=True) + user = muser.User(session_id=sid) req = request.json perms = {} @@ -445,22 +445,20 @@ def set_permissions(room, sid): perms[p] = None with db.transaction(): - with user.check_blinding() as u: - - if req.get('unschedule') is not False and any( - p in perms for p in ('read', 'write', 'upload') - ): - room.clear_future_permissions( - u, - mod=g.user, - read='read' in perms, - write='write' in perms, - upload='upload' in perms, - ) + if req.get('unschedule') is not False and any( + p in perms for p in ('read', 'write', 'upload') + ): + room.clear_future_permissions( + user, + mod=g.user, + read='read' in perms, + write='write' in perms, + upload='upload' in perms, + ) - room.set_permissions(u, mod=g.user, **perms) + room.set_permissions(user, mod=g.user, **perms) - res = room.user_permissions(u) + res = room.user_permissions(user) if res: res = addExtraPermInfo(res) @@ -636,7 +634,7 @@ def set_future_permissions(room, sid): scheduled against the *blinded* Session ID, if known, rather than the unblinded id. """ - user = muser.User(session_id=sid, try_blinding=True) + user = muser.User(session_id=sid) req = request.json perms = {} @@ -663,10 +661,9 @@ def set_future_permissions(room, sid): abort(http.BAD_REQUEST) with db.transaction(): - with user.check_blinding() as u: - room.add_future_permission(u, mod=g.user, at=time.time() + duration, **perms) + room.add_future_permission(user, mod=g.user, at=time.time() + duration, **perms) - res = room.user_future_permissions(u) + res = room.user_future_permissions(user) return jsonify(res) diff --git a/sogs/routes/subrequest.py b/sogs/routes/subrequest.py index d856a5fd..6839460d 100644 --- a/sogs/routes/subrequest.py +++ b/sogs/routes/subrequest.py @@ -85,12 +85,11 @@ def make_subrequest( "PATH_INFO": monkey_path, "QUERY_STRING": query_string, "CONTENT_TYPE": content_type, - "CONTENT_LENGTH": content_length, + "CONTENT_LENGTH": str(content_length), **http_headers, 'wsgi.input': body_input, 'flask._preserve_context': False, } - try: app.logger.debug(f"Initiating sub-request for {method} {path}") g.user_reauth = user_reauth diff --git a/sogs/routes/users.py b/sogs/routes/users.py index 525ea158..37f1110d 100644 --- a/sogs/routes/users.py +++ b/sogs/routes/users.py @@ -178,7 +178,7 @@ def set_mod(sid): 404 Not Found — if one or more of the given `rooms` tokens do not exist. """ - user = User(session_id=sid, try_blinding=True) + user = User(session_id=sid) req = request.json @@ -310,7 +310,7 @@ def ban_user(sid): 404 Not Found — if one or more of the given `rooms` tokens do not exist. """ - user = User(session_id=sid, try_blinding=True) + user = User(session_id=sid) req = request.json rooms, global_ban = extract_rooms_or_global(req, admin=False) @@ -378,7 +378,7 @@ def unban_user(sid): 404 Not Found — if one or more of the given `rooms` tokens do not exist. """ - user = User(session_id=sid, try_blinding=True) + user = User(session_id=sid) rooms, global_ban = extract_rooms_or_global(request.json, admin=False) if rooms: diff --git a/sogs/schema.pgsql b/sogs/schema.pgsql index df5f5f27..acdda5c3 100644 --- a/sogs/schema.pgsql +++ b/sogs/schema.pgsql @@ -43,6 +43,7 @@ CREATE TABLE messages ( data BYTEA, /* Actual message content, not including trailing padding; set to null to delete a message */ data_size BIGINT, /* The message size, including trailing padding (needed because the signature is over the padded data) */ signature BYTEA, /* Signature of `data` by `public_key`; set to null when deleting a message */ + alt_id TEXT, /* The Session ID which generated `signature` if not the user's "25" blinding key; null if it is */ filtered BOOLEAN NOT NULL DEFAULT FALSE, /* If true then we accept the message but never distribute it (e.g. for silent filtration) */ whisper BIGINT, /* foreign key to users(id): If set this is a whisper meant for the given user */ whisper_mods BOOLEAN NOT NULL DEFAULT FALSE /* If true: this is a whisper that all mods should see (may or may not have a `whisper` target) */ @@ -199,17 +200,6 @@ FOR EACH ROW WHEN (NEW.admin AND NOT NEW.moderator) EXECUTE PROCEDURE trigger_user_admins_are_mods(); --- This table tracks unblinded session ids in user_permission (and related) rows that need to be --- blinded, which will happen the first time the user authenticates with their blinded id (until --- they do, we can't know the actual sign bit of their blinded id). It is populated at startup --- when blinding is first enabled, and is used both for the initial blinding transition and when --- ids are added by raw session ID (e.g. when adding a moderator by session id). -CREATE TABLE needs_blinding ( - blinded_abs TEXT NOT NULL PRIMARY KEY, -- the positive of the possible two blinded keys - "user" BIGINT NOT NULL UNIQUE REFERENCES users ON DELETE CASCADE -); - - -- Reactions CREATE TABLE reactions ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, @@ -310,7 +300,7 @@ EXECUTE PROCEDURE trigger_reactions_clear_empty(); -- table of the user who posted it, and the session id of the whisper recipient (as `whisper_to`) if -- a directed whisper. CREATE VIEW message_details AS -SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to +SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to, COALESCE(messages.alt_id, uposter.session_id) AS signing_id FROM messages JOIN users uposter ON messages.user = uposter.id LEFT JOIN users uwhisper ON messages.whisper = uwhisper.id; @@ -595,6 +585,7 @@ CREATE TABLE inbox ( recipient BIGINT NOT NULL REFERENCES users ON DELETE CASCADE, sender BIGINT NOT NULL REFERENCES users ON DELETE CASCADE, body BYTEA NOT NULL, + alt_id TEXT, /* The Session ID which sender used to encrypt the message if not the "25" blinding key; null if it is */ posted_at FLOAT DEFAULT (extract(epoch from now())), expiry FLOAT DEFAULT (extract(epoch from now() + '15 days')) ); diff --git a/sogs/schema.sqlite b/sogs/schema.sqlite index dae7d913..af4feea9 100644 --- a/sogs/schema.sqlite +++ b/sogs/schema.sqlite @@ -42,6 +42,7 @@ CREATE TABLE messages ( data BLOB, /* Actual message content, not including trailing padding; set to null to delete a message */ data_size INTEGER, /* The message size, including trailing padding (needed because the signature is over the padded data) */ signature BLOB, /* Signature of `data` by `public_key`; set to null when deleting a message */ + alt_id TEXT, /* The Session ID which generated `signature` if not the user's "25" blinding key; null if it is */ filtered BOOLEAN NOT NULL DEFAULT FALSE, /* If true then we accept the message but never distribute it (e.g. for silent filtration) */ whisper INTEGER REFERENCES users(id), /* If set: this is a whisper meant for the given user */ whisper_mods BOOLEAN NOT NULL DEFAULT FALSE /* If true: this is a whisper that all mods should see (may or may not have a `whisper` target) */ @@ -171,17 +172,6 @@ BEGIN END; --- This table tracks unblinded session ids in user_permission (and related) rows that need to be --- blinded, which will happen the first time the user authenticates with their blinded id (until --- they do, we can't know the actual sign bit of their blinded id). It is populated at startup --- when blinding is first enabled, and is used both for the initial blinding transition and when --- ids are added by raw session ID (e.g. when adding a moderator by session id). -CREATE TABLE needs_blinding ( - blinded_abs TEXT NOT NULL PRIMARY KEY, -- the positive of the possible two blinded keys - "user" INTEGER NOT NULL UNIQUE REFERENCES users ON DELETE CASCADE -); - - -- Reactions CREATE TABLE reactions ( id INTEGER NOT NULL PRIMARY KEY, @@ -263,7 +253,7 @@ END; -- table of the user who posted it, and the session id of the whisper recipient (as `whisper_to`) if -- a directed whisper. CREATE VIEW message_details AS -SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to +SELECT messages.*, uposter.session_id, uwhisper.session_id AS whisper_to, COALESCE(messages.alt_id, uposter.session_id) AS signing_id FROM messages JOIN users uposter ON messages."user" = uposter.id LEFT JOIN users uwhisper ON messages.whisper = uwhisper.id; @@ -521,6 +511,7 @@ CREATE TABLE inbox ( recipient INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, sender INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, body BLOB NOT NULL, + alt_id TEXT, /* The Session ID which sender used to encrypt the message if not the "25" blinding key; null if it is */ posted_at FLOAT DEFAULT ((julianday('now') - 2440587.5)*86400.0), expiry FLOAT DEFAULT ((julianday('now') - 2440587.5 + 15.0)*86400.0) /* now + 15 days */ ); diff --git a/sogs/session_pb2.py b/sogs/session_pb2.py index f61ac939..e515b805 100644 --- a/sogs/session_pb2.py +++ b/sogs/session_pb2.py @@ -2,1425 +2,2383 @@ # source: sogs/session.proto import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) + +_b = sys.version_info[0] < 3 and (lambda x: x) or (lambda x: x.encode('latin1')) from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database + # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() - - DESCRIPTOR = _descriptor.FileDescriptor( - name='sogs/session.proto', - package='signalservice', - syntax='proto2', - serialized_options=None, - serialized_pb=_b('\n\x12sogs/session.proto\x12\rsignalservice\"\xa1\x01\n\x08\x45nvelope\x12*\n\x04type\x18\x01 \x02(\x0e\x32\x1c.signalservice.Envelope.Type\x12\x0e\n\x06source\x18\x02 \x01(\t\x12\x11\n\ttimestamp\x18\x05 \x02(\x04\x12\x0f\n\x07\x63ontent\x18\x08 \x01(\x0c\"5\n\x04Type\x12\x13\n\x0fSESSION_MESSAGE\x10\x06\x12\x18\n\x14\x43LOSED_GROUP_MESSAGE\x10\x07\"{\n\rTypingMessage\x12\x11\n\ttimestamp\x18\x01 \x02(\x04\x12\x33\n\x06\x61\x63tion\x18\x02 \x02(\x0e\x32#.signalservice.TypingMessage.Action\"\"\n\x06\x41\x63tion\x12\x0b\n\x07STARTED\x10\x00\x12\x0b\n\x07STOPPED\x10\x01\"+\n\x06Unsend\x12\x11\n\ttimestamp\x18\x01 \x02(\x04\x12\x0e\n\x06\x61uthor\x18\x02 \x02(\t\"\x97\x03\n\x07\x43ontent\x12/\n\x0b\x64\x61taMessage\x18\x01 \x01(\x0b\x32\x1a.signalservice.DataMessage\x12/\n\x0b\x63\x61llMessage\x18\x03 \x01(\x0b\x32\x1a.signalservice.CallMessage\x12\x35\n\x0ereceiptMessage\x18\x05 \x01(\x0b\x32\x1d.signalservice.ReceiptMessage\x12\x33\n\rtypingMessage\x18\x06 \x01(\x0b\x32\x1c.signalservice.TypingMessage\x12\x41\n\x14\x63onfigurationMessage\x18\x07 \x01(\x0b\x32#.signalservice.ConfigurationMessage\x12M\n\x1a\x64\x61taExtractionNotification\x18\x08 \x01(\x0b\x32).signalservice.DataExtractionNotification\x12,\n\runsendMessage\x18\t \x01(\x0b\x32\x15.signalservice.Unsend\"0\n\x07KeyPair\x12\x11\n\tpublicKey\x18\x01 \x02(\x0c\x12\x12\n\nprivateKey\x18\x02 \x02(\x0c\"\x96\x01\n\x1a\x44\x61taExtractionNotification\x12<\n\x04type\x18\x01 \x02(\x0e\x32..signalservice.DataExtractionNotification.Type\x12\x11\n\ttimestamp\x18\x02 \x01(\x04\"\'\n\x04Type\x12\x0e\n\nSCREENSHOT\x10\x01\x12\x0f\n\x0bMEDIA_SAVED\x10\x02\"\x97\x0c\n\x0b\x44\x61taMessage\x12\x0c\n\x04\x62ody\x18\x01 \x01(\t\x12\x35\n\x0b\x61ttachments\x18\x02 \x03(\x0b\x32 .signalservice.AttachmentPointer\x12*\n\x05group\x18\x03 \x01(\x0b\x32\x1b.signalservice.GroupContext\x12\r\n\x05\x66lags\x18\x04 \x01(\r\x12\x13\n\x0b\x65xpireTimer\x18\x05 \x01(\r\x12\x12\n\nprofileKey\x18\x06 \x01(\x0c\x12\x11\n\ttimestamp\x18\x07 \x01(\x04\x12/\n\x05quote\x18\x08 \x01(\x0b\x32 .signalservice.DataMessage.Quote\x12\x33\n\x07preview\x18\n \x03(\x0b\x32\".signalservice.DataMessage.Preview\x12\x37\n\x07profile\x18\x65 \x01(\x0b\x32&.signalservice.DataMessage.LokiProfile\x12K\n\x13openGroupInvitation\x18\x66 \x01(\x0b\x32..signalservice.DataMessage.OpenGroupInvitation\x12W\n\x19\x63losedGroupControlMessage\x18h \x01(\x0b\x32\x34.signalservice.DataMessage.ClosedGroupControlMessage\x12\x12\n\nsyncTarget\x18i \x01(\t\x1a\xe9\x01\n\x05Quote\x12\n\n\x02id\x18\x01 \x02(\x04\x12\x0e\n\x06\x61uthor\x18\x02 \x02(\t\x12\x0c\n\x04text\x18\x03 \x01(\t\x12\x46\n\x0b\x61ttachments\x18\x04 \x03(\x0b\x32\x31.signalservice.DataMessage.Quote.QuotedAttachment\x1an\n\x10QuotedAttachment\x12\x13\n\x0b\x63ontentType\x18\x01 \x01(\t\x12\x10\n\x08\x66ileName\x18\x02 \x01(\t\x12\x33\n\tthumbnail\x18\x03 \x01(\x0b\x32 .signalservice.AttachmentPointer\x1aV\n\x07Preview\x12\x0b\n\x03url\x18\x01 \x02(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12/\n\x05image\x18\x03 \x01(\x0b\x32 .signalservice.AttachmentPointer\x1a:\n\x0bLokiProfile\x12\x13\n\x0b\x64isplayName\x18\x01 \x01(\t\x12\x16\n\x0eprofilePicture\x18\x02 \x01(\t\x1a\x30\n\x13OpenGroupInvitation\x12\x0b\n\x03url\x18\x01 \x02(\t\x12\x0c\n\x04name\x18\x03 \x02(\t\x1a\x9a\x04\n\x19\x43losedGroupControlMessage\x12G\n\x04type\x18\x01 \x02(\x0e\x32\x39.signalservice.DataMessage.ClosedGroupControlMessage.Type\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x31\n\x11\x65ncryptionKeyPair\x18\x04 \x01(\x0b\x32\x16.signalservice.KeyPair\x12\x0f\n\x07members\x18\x05 \x03(\x0c\x12\x0e\n\x06\x61\x64mins\x18\x06 \x03(\x0c\x12U\n\x08wrappers\x18\x07 \x03(\x0b\x32\x43.signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper\x12\x13\n\x0b\x65xpireTimer\x18\x08 \x01(\r\x1a=\n\x0eKeyPairWrapper\x12\x11\n\tpublicKey\x18\x01 \x02(\x0c\x12\x18\n\x10\x65ncryptedKeyPair\x18\x02 \x02(\x0c\"\x93\x01\n\x04Type\x12\x07\n\x03NEW\x10\x01\x12\x17\n\x13\x45NCRYPTION_KEY_PAIR\x10\x03\x12\x0f\n\x0bNAME_CHANGE\x10\x04\x12\x11\n\rMEMBERS_ADDED\x10\x05\x12\x13\n\x0fMEMBERS_REMOVED\x10\x06\x12\x0f\n\x0bMEMBER_LEFT\x10\x07\x12\x1f\n\x1b\x45NCRYPTION_KEY_PAIR_REQUEST\x10\x08\"$\n\x05\x46lags\x12\x1b\n\x17\x45XPIRATION_TIMER_UPDATE\x10\x02\"\xcd\x01\n\x0b\x43\x61llMessage\x12-\n\x04type\x18\x01 \x02(\x0e\x32\x1f.signalservice.CallMessage.Type\x12\x0c\n\x04sdps\x18\x02 \x03(\t\x12\x17\n\x0fsdpMLineIndexes\x18\x03 \x03(\r\x12\x0f\n\x07sdpMids\x18\x04 \x03(\t\"W\n\x04Type\x12\t\n\x05OFFER\x10\x01\x12\n\n\x06\x41NSWER\x10\x02\x12\x16\n\x12PROVISIONAL_ANSWER\x10\x03\x12\x12\n\x0eICE_CANDIDATES\x10\x04\x12\x0c\n\x08\x45ND_CALL\x10\x05\"\xce\x03\n\x14\x43onfigurationMessage\x12\x45\n\x0c\x63losedGroups\x18\x01 \x03(\x0b\x32/.signalservice.ConfigurationMessage.ClosedGroup\x12\x12\n\nopenGroups\x18\x02 \x03(\t\x12\x13\n\x0b\x64isplayName\x18\x03 \x01(\t\x12\x16\n\x0eprofilePicture\x18\x04 \x01(\t\x12\x12\n\nprofileKey\x18\x05 \x01(\x0c\x12=\n\x08\x63ontacts\x18\x06 \x03(\x0b\x32+.signalservice.ConfigurationMessage.Contact\x1a\x82\x01\n\x0b\x43losedGroup\x12\x11\n\tpublicKey\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x31\n\x11\x65ncryptionKeyPair\x18\x03 \x01(\x0b\x32\x16.signalservice.KeyPair\x12\x0f\n\x07members\x18\x04 \x03(\x0c\x12\x0e\n\x06\x61\x64mins\x18\x05 \x03(\x0c\x1aV\n\x07\x43ontact\x12\x11\n\tpublicKey\x18\x01 \x02(\x0c\x12\x0c\n\x04name\x18\x02 \x02(\t\x12\x16\n\x0eprofilePicture\x18\x03 \x01(\t\x12\x12\n\nprofileKey\x18\x04 \x01(\x0c\"g\n\x0eReceiptMessage\x12\x30\n\x04type\x18\x01 \x02(\x0e\x32\".signalservice.ReceiptMessage.Type\x12\x11\n\ttimestamp\x18\x02 \x03(\x04\"\x10\n\x04Type\x12\x08\n\x04READ\x10\x01\"\xec\x01\n\x11\x41ttachmentPointer\x12\n\n\x02id\x18\x01 \x02(\x06\x12\x13\n\x0b\x63ontentType\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12\x0c\n\x04size\x18\x04 \x01(\r\x12\x11\n\tthumbnail\x18\x05 \x01(\x0c\x12\x0e\n\x06\x64igest\x18\x06 \x01(\x0c\x12\x10\n\x08\x66ileName\x18\x07 \x01(\t\x12\r\n\x05\x66lags\x18\x08 \x01(\r\x12\r\n\x05width\x18\t \x01(\r\x12\x0e\n\x06height\x18\n \x01(\r\x12\x0f\n\x07\x63\x61ption\x18\x0b \x01(\t\x12\x0b\n\x03url\x18\x65 \x01(\t\"\x1a\n\x05\x46lags\x12\x11\n\rVOICE_MESSAGE\x10\x01\"\xf5\x01\n\x0cGroupContext\x12\n\n\x02id\x18\x01 \x01(\x0c\x12.\n\x04type\x18\x02 \x01(\x0e\x32 .signalservice.GroupContext.Type\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0f\n\x07members\x18\x04 \x03(\t\x12\x30\n\x06\x61vatar\x18\x05 \x01(\x0b\x32 .signalservice.AttachmentPointer\x12\x0e\n\x06\x61\x64mins\x18\x06 \x03(\t\"H\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06UPDATE\x10\x01\x12\x0b\n\x07\x44\x45LIVER\x10\x02\x12\x08\n\x04QUIT\x10\x03\x12\x10\n\x0cREQUEST_INFO\x10\x04') + name='sogs/session.proto', + package='signalservice', + syntax='proto2', + serialized_options=None, + serialized_pb=_b( + '\n\x12sogs/session.proto\x12\rsignalservice\"\xa1\x01\n\x08\x45nvelope\x12*\n\x04type\x18\x01 \x02(\x0e\x32\x1c.signalservice.Envelope.Type\x12\x0e\n\x06source\x18\x02 \x01(\t\x12\x11\n\ttimestamp\x18\x05 \x02(\x04\x12\x0f\n\x07\x63ontent\x18\x08 \x01(\x0c\"5\n\x04Type\x12\x13\n\x0fSESSION_MESSAGE\x10\x06\x12\x18\n\x14\x43LOSED_GROUP_MESSAGE\x10\x07\"{\n\rTypingMessage\x12\x11\n\ttimestamp\x18\x01 \x02(\x04\x12\x33\n\x06\x61\x63tion\x18\x02 \x02(\x0e\x32#.signalservice.TypingMessage.Action\"\"\n\x06\x41\x63tion\x12\x0b\n\x07STARTED\x10\x00\x12\x0b\n\x07STOPPED\x10\x01\"+\n\x06Unsend\x12\x11\n\ttimestamp\x18\x01 \x02(\x04\x12\x0e\n\x06\x61uthor\x18\x02 \x02(\t\"\x97\x03\n\x07\x43ontent\x12/\n\x0b\x64\x61taMessage\x18\x01 \x01(\x0b\x32\x1a.signalservice.DataMessage\x12/\n\x0b\x63\x61llMessage\x18\x03 \x01(\x0b\x32\x1a.signalservice.CallMessage\x12\x35\n\x0ereceiptMessage\x18\x05 \x01(\x0b\x32\x1d.signalservice.ReceiptMessage\x12\x33\n\rtypingMessage\x18\x06 \x01(\x0b\x32\x1c.signalservice.TypingMessage\x12\x41\n\x14\x63onfigurationMessage\x18\x07 \x01(\x0b\x32#.signalservice.ConfigurationMessage\x12M\n\x1a\x64\x61taExtractionNotification\x18\x08 \x01(\x0b\x32).signalservice.DataExtractionNotification\x12,\n\runsendMessage\x18\t \x01(\x0b\x32\x15.signalservice.Unsend\"0\n\x07KeyPair\x12\x11\n\tpublicKey\x18\x01 \x02(\x0c\x12\x12\n\nprivateKey\x18\x02 \x02(\x0c\"\x96\x01\n\x1a\x44\x61taExtractionNotification\x12<\n\x04type\x18\x01 \x02(\x0e\x32..signalservice.DataExtractionNotification.Type\x12\x11\n\ttimestamp\x18\x02 \x01(\x04\"\'\n\x04Type\x12\x0e\n\nSCREENSHOT\x10\x01\x12\x0f\n\x0bMEDIA_SAVED\x10\x02\"\x97\x0c\n\x0b\x44\x61taMessage\x12\x0c\n\x04\x62ody\x18\x01 \x01(\t\x12\x35\n\x0b\x61ttachments\x18\x02 \x03(\x0b\x32 .signalservice.AttachmentPointer\x12*\n\x05group\x18\x03 \x01(\x0b\x32\x1b.signalservice.GroupContext\x12\r\n\x05\x66lags\x18\x04 \x01(\r\x12\x13\n\x0b\x65xpireTimer\x18\x05 \x01(\r\x12\x12\n\nprofileKey\x18\x06 \x01(\x0c\x12\x11\n\ttimestamp\x18\x07 \x01(\x04\x12/\n\x05quote\x18\x08 \x01(\x0b\x32 .signalservice.DataMessage.Quote\x12\x33\n\x07preview\x18\n \x03(\x0b\x32\".signalservice.DataMessage.Preview\x12\x37\n\x07profile\x18\x65 \x01(\x0b\x32&.signalservice.DataMessage.LokiProfile\x12K\n\x13openGroupInvitation\x18\x66 \x01(\x0b\x32..signalservice.DataMessage.OpenGroupInvitation\x12W\n\x19\x63losedGroupControlMessage\x18h \x01(\x0b\x32\x34.signalservice.DataMessage.ClosedGroupControlMessage\x12\x12\n\nsyncTarget\x18i \x01(\t\x1a\xe9\x01\n\x05Quote\x12\n\n\x02id\x18\x01 \x02(\x04\x12\x0e\n\x06\x61uthor\x18\x02 \x02(\t\x12\x0c\n\x04text\x18\x03 \x01(\t\x12\x46\n\x0b\x61ttachments\x18\x04 \x03(\x0b\x32\x31.signalservice.DataMessage.Quote.QuotedAttachment\x1an\n\x10QuotedAttachment\x12\x13\n\x0b\x63ontentType\x18\x01 \x01(\t\x12\x10\n\x08\x66ileName\x18\x02 \x01(\t\x12\x33\n\tthumbnail\x18\x03 \x01(\x0b\x32 .signalservice.AttachmentPointer\x1aV\n\x07Preview\x12\x0b\n\x03url\x18\x01 \x02(\t\x12\r\n\x05title\x18\x02 \x01(\t\x12/\n\x05image\x18\x03 \x01(\x0b\x32 .signalservice.AttachmentPointer\x1a:\n\x0bLokiProfile\x12\x13\n\x0b\x64isplayName\x18\x01 \x01(\t\x12\x16\n\x0eprofilePicture\x18\x02 \x01(\t\x1a\x30\n\x13OpenGroupInvitation\x12\x0b\n\x03url\x18\x01 \x02(\t\x12\x0c\n\x04name\x18\x03 \x02(\t\x1a\x9a\x04\n\x19\x43losedGroupControlMessage\x12G\n\x04type\x18\x01 \x02(\x0e\x32\x39.signalservice.DataMessage.ClosedGroupControlMessage.Type\x12\x11\n\tpublicKey\x18\x02 \x01(\x0c\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x31\n\x11\x65ncryptionKeyPair\x18\x04 \x01(\x0b\x32\x16.signalservice.KeyPair\x12\x0f\n\x07members\x18\x05 \x03(\x0c\x12\x0e\n\x06\x61\x64mins\x18\x06 \x03(\x0c\x12U\n\x08wrappers\x18\x07 \x03(\x0b\x32\x43.signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper\x12\x13\n\x0b\x65xpireTimer\x18\x08 \x01(\r\x1a=\n\x0eKeyPairWrapper\x12\x11\n\tpublicKey\x18\x01 \x02(\x0c\x12\x18\n\x10\x65ncryptedKeyPair\x18\x02 \x02(\x0c\"\x93\x01\n\x04Type\x12\x07\n\x03NEW\x10\x01\x12\x17\n\x13\x45NCRYPTION_KEY_PAIR\x10\x03\x12\x0f\n\x0bNAME_CHANGE\x10\x04\x12\x11\n\rMEMBERS_ADDED\x10\x05\x12\x13\n\x0fMEMBERS_REMOVED\x10\x06\x12\x0f\n\x0bMEMBER_LEFT\x10\x07\x12\x1f\n\x1b\x45NCRYPTION_KEY_PAIR_REQUEST\x10\x08\"$\n\x05\x46lags\x12\x1b\n\x17\x45XPIRATION_TIMER_UPDATE\x10\x02\"\xcd\x01\n\x0b\x43\x61llMessage\x12-\n\x04type\x18\x01 \x02(\x0e\x32\x1f.signalservice.CallMessage.Type\x12\x0c\n\x04sdps\x18\x02 \x03(\t\x12\x17\n\x0fsdpMLineIndexes\x18\x03 \x03(\r\x12\x0f\n\x07sdpMids\x18\x04 \x03(\t\"W\n\x04Type\x12\t\n\x05OFFER\x10\x01\x12\n\n\x06\x41NSWER\x10\x02\x12\x16\n\x12PROVISIONAL_ANSWER\x10\x03\x12\x12\n\x0eICE_CANDIDATES\x10\x04\x12\x0c\n\x08\x45ND_CALL\x10\x05\"\xce\x03\n\x14\x43onfigurationMessage\x12\x45\n\x0c\x63losedGroups\x18\x01 \x03(\x0b\x32/.signalservice.ConfigurationMessage.ClosedGroup\x12\x12\n\nopenGroups\x18\x02 \x03(\t\x12\x13\n\x0b\x64isplayName\x18\x03 \x01(\t\x12\x16\n\x0eprofilePicture\x18\x04 \x01(\t\x12\x12\n\nprofileKey\x18\x05 \x01(\x0c\x12=\n\x08\x63ontacts\x18\x06 \x03(\x0b\x32+.signalservice.ConfigurationMessage.Contact\x1a\x82\x01\n\x0b\x43losedGroup\x12\x11\n\tpublicKey\x18\x01 \x01(\x0c\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x31\n\x11\x65ncryptionKeyPair\x18\x03 \x01(\x0b\x32\x16.signalservice.KeyPair\x12\x0f\n\x07members\x18\x04 \x03(\x0c\x12\x0e\n\x06\x61\x64mins\x18\x05 \x03(\x0c\x1aV\n\x07\x43ontact\x12\x11\n\tpublicKey\x18\x01 \x02(\x0c\x12\x0c\n\x04name\x18\x02 \x02(\t\x12\x16\n\x0eprofilePicture\x18\x03 \x01(\t\x12\x12\n\nprofileKey\x18\x04 \x01(\x0c\"g\n\x0eReceiptMessage\x12\x30\n\x04type\x18\x01 \x02(\x0e\x32\".signalservice.ReceiptMessage.Type\x12\x11\n\ttimestamp\x18\x02 \x03(\x04\"\x10\n\x04Type\x12\x08\n\x04READ\x10\x01\"\xec\x01\n\x11\x41ttachmentPointer\x12\n\n\x02id\x18\x01 \x02(\x06\x12\x13\n\x0b\x63ontentType\x18\x02 \x01(\t\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12\x0c\n\x04size\x18\x04 \x01(\r\x12\x11\n\tthumbnail\x18\x05 \x01(\x0c\x12\x0e\n\x06\x64igest\x18\x06 \x01(\x0c\x12\x10\n\x08\x66ileName\x18\x07 \x01(\t\x12\r\n\x05\x66lags\x18\x08 \x01(\r\x12\r\n\x05width\x18\t \x01(\r\x12\x0e\n\x06height\x18\n \x01(\r\x12\x0f\n\x07\x63\x61ption\x18\x0b \x01(\t\x12\x0b\n\x03url\x18\x65 \x01(\t\"\x1a\n\x05\x46lags\x12\x11\n\rVOICE_MESSAGE\x10\x01\"\xf5\x01\n\x0cGroupContext\x12\n\n\x02id\x18\x01 \x01(\x0c\x12.\n\x04type\x18\x02 \x01(\x0e\x32 .signalservice.GroupContext.Type\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x0f\n\x07members\x18\x04 \x03(\t\x12\x30\n\x06\x61vatar\x18\x05 \x01(\x0b\x32 .signalservice.AttachmentPointer\x12\x0e\n\x06\x61\x64mins\x18\x06 \x03(\t\"H\n\x04Type\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06UPDATE\x10\x01\x12\x0b\n\x07\x44\x45LIVER\x10\x02\x12\x08\n\x04QUIT\x10\x03\x12\x10\n\x0cREQUEST_INFO\x10\x04' + ), ) - _ENVELOPE_TYPE = _descriptor.EnumDescriptor( - name='Type', - full_name='signalservice.Envelope.Type', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='SESSION_MESSAGE', index=0, number=6, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='CLOSED_GROUP_MESSAGE', index=1, number=7, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=146, - serialized_end=199, + name='Type', + full_name='signalservice.Envelope.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SESSION_MESSAGE', index=0, number=6, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='CLOSED_GROUP_MESSAGE', index=1, number=7, serialized_options=None, type=None + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=146, + serialized_end=199, ) _sym_db.RegisterEnumDescriptor(_ENVELOPE_TYPE) _TYPINGMESSAGE_ACTION = _descriptor.EnumDescriptor( - name='Action', - full_name='signalservice.TypingMessage.Action', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='STARTED', index=0, number=0, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='STOPPED', index=1, number=1, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=290, - serialized_end=324, + name='Action', + full_name='signalservice.TypingMessage.Action', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='STARTED', index=0, number=0, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='STOPPED', index=1, number=1, serialized_options=None, type=None + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=290, + serialized_end=324, ) _sym_db.RegisterEnumDescriptor(_TYPINGMESSAGE_ACTION) _DATAEXTRACTIONNOTIFICATION_TYPE = _descriptor.EnumDescriptor( - name='Type', - full_name='signalservice.DataExtractionNotification.Type', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='SCREENSHOT', index=0, number=1, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='MEDIA_SAVED', index=1, number=2, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=943, - serialized_end=982, + name='Type', + full_name='signalservice.DataExtractionNotification.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='SCREENSHOT', index=0, number=1, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='MEDIA_SAVED', index=1, number=2, serialized_options=None, type=None + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=943, + serialized_end=982, ) _sym_db.RegisterEnumDescriptor(_DATAEXTRACTIONNOTIFICATION_TYPE) _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_TYPE = _descriptor.EnumDescriptor( - name='Type', - full_name='signalservice.DataMessage.ClosedGroupControlMessage.Type', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='NEW', index=0, number=1, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='ENCRYPTION_KEY_PAIR', index=1, number=3, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='NAME_CHANGE', index=2, number=4, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='MEMBERS_ADDED', index=3, number=5, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='MEMBERS_REMOVED', index=4, number=6, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='MEMBER_LEFT', index=5, number=7, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='ENCRYPTION_KEY_PAIR_REQUEST', index=6, number=8, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=2359, - serialized_end=2506, + name='Type', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='NEW', index=0, number=1, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='ENCRYPTION_KEY_PAIR', index=1, number=3, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='NAME_CHANGE', index=2, number=4, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='MEMBERS_ADDED', index=3, number=5, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='MEMBERS_REMOVED', index=4, number=6, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='MEMBER_LEFT', index=5, number=7, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='ENCRYPTION_KEY_PAIR_REQUEST', + index=6, + number=8, + serialized_options=None, + type=None, + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=2359, + serialized_end=2506, ) _sym_db.RegisterEnumDescriptor(_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_TYPE) _DATAMESSAGE_FLAGS = _descriptor.EnumDescriptor( - name='Flags', - full_name='signalservice.DataMessage.Flags', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='EXPIRATION_TIMER_UPDATE', index=0, number=2, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=2508, - serialized_end=2544, + name='Flags', + full_name='signalservice.DataMessage.Flags', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='EXPIRATION_TIMER_UPDATE', index=0, number=2, serialized_options=None, type=None + ) + ], + containing_type=None, + serialized_options=None, + serialized_start=2508, + serialized_end=2544, ) _sym_db.RegisterEnumDescriptor(_DATAMESSAGE_FLAGS) _CALLMESSAGE_TYPE = _descriptor.EnumDescriptor( - name='Type', - full_name='signalservice.CallMessage.Type', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='OFFER', index=0, number=1, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='ANSWER', index=1, number=2, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='PROVISIONAL_ANSWER', index=2, number=3, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='ICE_CANDIDATES', index=3, number=4, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='END_CALL', index=4, number=5, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=2665, - serialized_end=2752, + name='Type', + full_name='signalservice.CallMessage.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='OFFER', index=0, number=1, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='ANSWER', index=1, number=2, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='PROVISIONAL_ANSWER', index=2, number=3, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='ICE_CANDIDATES', index=3, number=4, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='END_CALL', index=4, number=5, serialized_options=None, type=None + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=2665, + serialized_end=2752, ) _sym_db.RegisterEnumDescriptor(_CALLMESSAGE_TYPE) _RECEIPTMESSAGE_TYPE = _descriptor.EnumDescriptor( - name='Type', - full_name='signalservice.ReceiptMessage.Type', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='READ', index=0, number=1, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=3306, - serialized_end=3322, + name='Type', + full_name='signalservice.ReceiptMessage.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='READ', index=0, number=1, serialized_options=None, type=None + ) + ], + containing_type=None, + serialized_options=None, + serialized_start=3306, + serialized_end=3322, ) _sym_db.RegisterEnumDescriptor(_RECEIPTMESSAGE_TYPE) _ATTACHMENTPOINTER_FLAGS = _descriptor.EnumDescriptor( - name='Flags', - full_name='signalservice.AttachmentPointer.Flags', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='VOICE_MESSAGE', index=0, number=1, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=3535, - serialized_end=3561, + name='Flags', + full_name='signalservice.AttachmentPointer.Flags', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='VOICE_MESSAGE', index=0, number=1, serialized_options=None, type=None + ) + ], + containing_type=None, + serialized_options=None, + serialized_start=3535, + serialized_end=3561, ) _sym_db.RegisterEnumDescriptor(_ATTACHMENTPOINTER_FLAGS) _GROUPCONTEXT_TYPE = _descriptor.EnumDescriptor( - name='Type', - full_name='signalservice.GroupContext.Type', - filename=None, - file=DESCRIPTOR, - values=[ - _descriptor.EnumValueDescriptor( - name='UNKNOWN', index=0, number=0, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='UPDATE', index=1, number=1, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='DELIVER', index=2, number=2, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='QUIT', index=3, number=3, - serialized_options=None, - type=None), - _descriptor.EnumValueDescriptor( - name='REQUEST_INFO', index=4, number=4, - serialized_options=None, - type=None), - ], - containing_type=None, - serialized_options=None, - serialized_start=3737, - serialized_end=3809, + name='Type', + full_name='signalservice.GroupContext.Type', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='UNKNOWN', index=0, number=0, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='UPDATE', index=1, number=1, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='DELIVER', index=2, number=2, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='QUIT', index=3, number=3, serialized_options=None, type=None + ), + _descriptor.EnumValueDescriptor( + name='REQUEST_INFO', index=4, number=4, serialized_options=None, type=None + ), + ], + containing_type=None, + serialized_options=None, + serialized_start=3737, + serialized_end=3809, ) _sym_db.RegisterEnumDescriptor(_GROUPCONTEXT_TYPE) _ENVELOPE = _descriptor.Descriptor( - name='Envelope', - full_name='signalservice.Envelope', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='type', full_name='signalservice.Envelope.type', index=0, - number=1, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=6, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='source', full_name='signalservice.Envelope.source', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='timestamp', full_name='signalservice.Envelope.timestamp', index=2, - number=5, type=4, cpp_type=4, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='content', full_name='signalservice.Envelope.content', index=3, - number=8, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _ENVELOPE_TYPE, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=38, - serialized_end=199, + name='Envelope', + full_name='signalservice.Envelope', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', + full_name='signalservice.Envelope.type', + index=0, + number=1, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=6, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='source', + full_name='signalservice.Envelope.source', + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='timestamp', + full_name='signalservice.Envelope.timestamp', + index=2, + number=5, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='content', + full_name='signalservice.Envelope.content', + index=3, + number=8, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_ENVELOPE_TYPE], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=38, + serialized_end=199, ) _TYPINGMESSAGE = _descriptor.Descriptor( - name='TypingMessage', - full_name='signalservice.TypingMessage', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='timestamp', full_name='signalservice.TypingMessage.timestamp', index=0, - number=1, type=4, cpp_type=4, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='action', full_name='signalservice.TypingMessage.action', index=1, - number=2, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _TYPINGMESSAGE_ACTION, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=201, - serialized_end=324, + name='TypingMessage', + full_name='signalservice.TypingMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='timestamp', + full_name='signalservice.TypingMessage.timestamp', + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='action', + full_name='signalservice.TypingMessage.action', + index=1, + number=2, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_TYPINGMESSAGE_ACTION], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=201, + serialized_end=324, ) _UNSEND = _descriptor.Descriptor( - name='Unsend', - full_name='signalservice.Unsend', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='timestamp', full_name='signalservice.Unsend.timestamp', index=0, - number=1, type=4, cpp_type=4, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='author', full_name='signalservice.Unsend.author', index=1, - number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=326, - serialized_end=369, + name='Unsend', + full_name='signalservice.Unsend', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='timestamp', + full_name='signalservice.Unsend.timestamp', + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='author', + full_name='signalservice.Unsend.author', + index=1, + number=2, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=326, + serialized_end=369, ) _CONTENT = _descriptor.Descriptor( - name='Content', - full_name='signalservice.Content', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='dataMessage', full_name='signalservice.Content.dataMessage', index=0, - number=1, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='callMessage', full_name='signalservice.Content.callMessage', index=1, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='receiptMessage', full_name='signalservice.Content.receiptMessage', index=2, - number=5, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='typingMessage', full_name='signalservice.Content.typingMessage', index=3, - number=6, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='configurationMessage', full_name='signalservice.Content.configurationMessage', index=4, - number=7, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='dataExtractionNotification', full_name='signalservice.Content.dataExtractionNotification', index=5, - number=8, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='unsendMessage', full_name='signalservice.Content.unsendMessage', index=6, - number=9, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=372, - serialized_end=779, + name='Content', + full_name='signalservice.Content', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='dataMessage', + full_name='signalservice.Content.dataMessage', + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='callMessage', + full_name='signalservice.Content.callMessage', + index=1, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='receiptMessage', + full_name='signalservice.Content.receiptMessage', + index=2, + number=5, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='typingMessage', + full_name='signalservice.Content.typingMessage', + index=3, + number=6, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='configurationMessage', + full_name='signalservice.Content.configurationMessage', + index=4, + number=7, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='dataExtractionNotification', + full_name='signalservice.Content.dataExtractionNotification', + index=5, + number=8, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='unsendMessage', + full_name='signalservice.Content.unsendMessage', + index=6, + number=9, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=372, + serialized_end=779, ) _KEYPAIR = _descriptor.Descriptor( - name='KeyPair', - full_name='signalservice.KeyPair', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='publicKey', full_name='signalservice.KeyPair.publicKey', index=0, - number=1, type=12, cpp_type=9, label=2, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='privateKey', full_name='signalservice.KeyPair.privateKey', index=1, - number=2, type=12, cpp_type=9, label=2, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=781, - serialized_end=829, + name='KeyPair', + full_name='signalservice.KeyPair', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='publicKey', + full_name='signalservice.KeyPair.publicKey', + index=0, + number=1, + type=12, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='privateKey', + full_name='signalservice.KeyPair.privateKey', + index=1, + number=2, + type=12, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=781, + serialized_end=829, ) _DATAEXTRACTIONNOTIFICATION = _descriptor.Descriptor( - name='DataExtractionNotification', - full_name='signalservice.DataExtractionNotification', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='type', full_name='signalservice.DataExtractionNotification.type', index=0, - number=1, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='timestamp', full_name='signalservice.DataExtractionNotification.timestamp', index=1, - number=2, type=4, cpp_type=4, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _DATAEXTRACTIONNOTIFICATION_TYPE, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=832, - serialized_end=982, + name='DataExtractionNotification', + full_name='signalservice.DataExtractionNotification', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', + full_name='signalservice.DataExtractionNotification.type', + index=0, + number=1, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=1, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='timestamp', + full_name='signalservice.DataExtractionNotification.timestamp', + index=1, + number=2, + type=4, + cpp_type=4, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_DATAEXTRACTIONNOTIFICATION_TYPE], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=832, + serialized_end=982, ) _DATAMESSAGE_QUOTE_QUOTEDATTACHMENT = _descriptor.Descriptor( - name='QuotedAttachment', - full_name='signalservice.DataMessage.Quote.QuotedAttachment', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='contentType', full_name='signalservice.DataMessage.Quote.QuotedAttachment.contentType', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='fileName', full_name='signalservice.DataMessage.Quote.QuotedAttachment.fileName', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='thumbnail', full_name='signalservice.DataMessage.Quote.QuotedAttachment.thumbnail', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1657, - serialized_end=1767, + name='QuotedAttachment', + full_name='signalservice.DataMessage.Quote.QuotedAttachment', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='contentType', + full_name='signalservice.DataMessage.Quote.QuotedAttachment.contentType', + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='fileName', + full_name='signalservice.DataMessage.Quote.QuotedAttachment.fileName', + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='thumbnail', + full_name='signalservice.DataMessage.Quote.QuotedAttachment.thumbnail', + index=2, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=1657, + serialized_end=1767, ) _DATAMESSAGE_QUOTE = _descriptor.Descriptor( - name='Quote', - full_name='signalservice.DataMessage.Quote', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='id', full_name='signalservice.DataMessage.Quote.id', index=0, - number=1, type=4, cpp_type=4, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='author', full_name='signalservice.DataMessage.Quote.author', index=1, - number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='text', full_name='signalservice.DataMessage.Quote.text', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='attachments', full_name='signalservice.DataMessage.Quote.attachments', index=3, - number=4, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_DATAMESSAGE_QUOTE_QUOTEDATTACHMENT, ], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1534, - serialized_end=1767, + name='Quote', + full_name='signalservice.DataMessage.Quote', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='id', + full_name='signalservice.DataMessage.Quote.id', + index=0, + number=1, + type=4, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='author', + full_name='signalservice.DataMessage.Quote.author', + index=1, + number=2, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='text', + full_name='signalservice.DataMessage.Quote.text', + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='attachments', + full_name='signalservice.DataMessage.Quote.attachments', + index=3, + number=4, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_DATAMESSAGE_QUOTE_QUOTEDATTACHMENT], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=1534, + serialized_end=1767, ) _DATAMESSAGE_PREVIEW = _descriptor.Descriptor( - name='Preview', - full_name='signalservice.DataMessage.Preview', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='url', full_name='signalservice.DataMessage.Preview.url', index=0, - number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='title', full_name='signalservice.DataMessage.Preview.title', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='image', full_name='signalservice.DataMessage.Preview.image', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1769, - serialized_end=1855, + name='Preview', + full_name='signalservice.DataMessage.Preview', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='url', + full_name='signalservice.DataMessage.Preview.url', + index=0, + number=1, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='title', + full_name='signalservice.DataMessage.Preview.title', + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='image', + full_name='signalservice.DataMessage.Preview.image', + index=2, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=1769, + serialized_end=1855, ) _DATAMESSAGE_LOKIPROFILE = _descriptor.Descriptor( - name='LokiProfile', - full_name='signalservice.DataMessage.LokiProfile', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='displayName', full_name='signalservice.DataMessage.LokiProfile.displayName', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='profilePicture', full_name='signalservice.DataMessage.LokiProfile.profilePicture', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1857, - serialized_end=1915, + name='LokiProfile', + full_name='signalservice.DataMessage.LokiProfile', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='displayName', + full_name='signalservice.DataMessage.LokiProfile.displayName', + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='profilePicture', + full_name='signalservice.DataMessage.LokiProfile.profilePicture', + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=1857, + serialized_end=1915, ) _DATAMESSAGE_OPENGROUPINVITATION = _descriptor.Descriptor( - name='OpenGroupInvitation', - full_name='signalservice.DataMessage.OpenGroupInvitation', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='url', full_name='signalservice.DataMessage.OpenGroupInvitation.url', index=0, - number=1, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='name', full_name='signalservice.DataMessage.OpenGroupInvitation.name', index=1, - number=3, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1917, - serialized_end=1965, + name='OpenGroupInvitation', + full_name='signalservice.DataMessage.OpenGroupInvitation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='url', + full_name='signalservice.DataMessage.OpenGroupInvitation.url', + index=0, + number=1, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='name', + full_name='signalservice.DataMessage.OpenGroupInvitation.name', + index=1, + number=3, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=1917, + serialized_end=1965, ) _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER = _descriptor.Descriptor( - name='KeyPairWrapper', - full_name='signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='publicKey', full_name='signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper.publicKey', index=0, - number=1, type=12, cpp_type=9, label=2, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='encryptedKeyPair', full_name='signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper.encryptedKeyPair', index=1, - number=2, type=12, cpp_type=9, label=2, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2295, - serialized_end=2356, + name='KeyPairWrapper', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='publicKey', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper.publicKey', + index=0, + number=1, + type=12, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='encryptedKeyPair', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper.encryptedKeyPair', + index=1, + number=2, + type=12, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=2295, + serialized_end=2356, ) _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE = _descriptor.Descriptor( - name='ClosedGroupControlMessage', - full_name='signalservice.DataMessage.ClosedGroupControlMessage', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='type', full_name='signalservice.DataMessage.ClosedGroupControlMessage.type', index=0, - number=1, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='publicKey', full_name='signalservice.DataMessage.ClosedGroupControlMessage.publicKey', index=1, - number=2, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='name', full_name='signalservice.DataMessage.ClosedGroupControlMessage.name', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='encryptionKeyPair', full_name='signalservice.DataMessage.ClosedGroupControlMessage.encryptionKeyPair', index=3, - number=4, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='members', full_name='signalservice.DataMessage.ClosedGroupControlMessage.members', index=4, - number=5, type=12, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='admins', full_name='signalservice.DataMessage.ClosedGroupControlMessage.admins', index=5, - number=6, type=12, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='wrappers', full_name='signalservice.DataMessage.ClosedGroupControlMessage.wrappers', index=6, - number=7, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='expireTimer', full_name='signalservice.DataMessage.ClosedGroupControlMessage.expireTimer', index=7, - number=8, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER, ], - enum_types=[ - _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_TYPE, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=1968, - serialized_end=2506, + name='ClosedGroupControlMessage', + full_name='signalservice.DataMessage.ClosedGroupControlMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.type', + index=0, + number=1, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=1, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='publicKey', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.publicKey', + index=1, + number=2, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='name', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.name', + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='encryptionKeyPair', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.encryptionKeyPair', + index=3, + number=4, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='members', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.members', + index=4, + number=5, + type=12, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='admins', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.admins', + index=5, + number=6, + type=12, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='wrappers', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.wrappers', + index=6, + number=7, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='expireTimer', + full_name='signalservice.DataMessage.ClosedGroupControlMessage.expireTimer', + index=7, + number=8, + type=13, + cpp_type=3, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER], + enum_types=[_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_TYPE], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=1968, + serialized_end=2506, ) _DATAMESSAGE = _descriptor.Descriptor( - name='DataMessage', - full_name='signalservice.DataMessage', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='body', full_name='signalservice.DataMessage.body', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='attachments', full_name='signalservice.DataMessage.attachments', index=1, - number=2, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='group', full_name='signalservice.DataMessage.group', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='flags', full_name='signalservice.DataMessage.flags', index=3, - number=4, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='expireTimer', full_name='signalservice.DataMessage.expireTimer', index=4, - number=5, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='profileKey', full_name='signalservice.DataMessage.profileKey', index=5, - number=6, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='timestamp', full_name='signalservice.DataMessage.timestamp', index=6, - number=7, type=4, cpp_type=4, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='quote', full_name='signalservice.DataMessage.quote', index=7, - number=8, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='preview', full_name='signalservice.DataMessage.preview', index=8, - number=10, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='profile', full_name='signalservice.DataMessage.profile', index=9, - number=101, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='openGroupInvitation', full_name='signalservice.DataMessage.openGroupInvitation', index=10, - number=102, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='closedGroupControlMessage', full_name='signalservice.DataMessage.closedGroupControlMessage', index=11, - number=104, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='syncTarget', full_name='signalservice.DataMessage.syncTarget', index=12, - number=105, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_DATAMESSAGE_QUOTE, _DATAMESSAGE_PREVIEW, _DATAMESSAGE_LOKIPROFILE, _DATAMESSAGE_OPENGROUPINVITATION, _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE, ], - enum_types=[ - _DATAMESSAGE_FLAGS, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=985, - serialized_end=2544, + name='DataMessage', + full_name='signalservice.DataMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='body', + full_name='signalservice.DataMessage.body', + index=0, + number=1, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='attachments', + full_name='signalservice.DataMessage.attachments', + index=1, + number=2, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='group', + full_name='signalservice.DataMessage.group', + index=2, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='flags', + full_name='signalservice.DataMessage.flags', + index=3, + number=4, + type=13, + cpp_type=3, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='expireTimer', + full_name='signalservice.DataMessage.expireTimer', + index=4, + number=5, + type=13, + cpp_type=3, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='profileKey', + full_name='signalservice.DataMessage.profileKey', + index=5, + number=6, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='timestamp', + full_name='signalservice.DataMessage.timestamp', + index=6, + number=7, + type=4, + cpp_type=4, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='quote', + full_name='signalservice.DataMessage.quote', + index=7, + number=8, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='preview', + full_name='signalservice.DataMessage.preview', + index=8, + number=10, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='profile', + full_name='signalservice.DataMessage.profile', + index=9, + number=101, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='openGroupInvitation', + full_name='signalservice.DataMessage.openGroupInvitation', + index=10, + number=102, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='closedGroupControlMessage', + full_name='signalservice.DataMessage.closedGroupControlMessage', + index=11, + number=104, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='syncTarget', + full_name='signalservice.DataMessage.syncTarget', + index=12, + number=105, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[ + _DATAMESSAGE_QUOTE, + _DATAMESSAGE_PREVIEW, + _DATAMESSAGE_LOKIPROFILE, + _DATAMESSAGE_OPENGROUPINVITATION, + _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE, + ], + enum_types=[_DATAMESSAGE_FLAGS], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=985, + serialized_end=2544, ) _CALLMESSAGE = _descriptor.Descriptor( - name='CallMessage', - full_name='signalservice.CallMessage', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='type', full_name='signalservice.CallMessage.type', index=0, - number=1, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='sdps', full_name='signalservice.CallMessage.sdps', index=1, - number=2, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='sdpMLineIndexes', full_name='signalservice.CallMessage.sdpMLineIndexes', index=2, - number=3, type=13, cpp_type=3, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='sdpMids', full_name='signalservice.CallMessage.sdpMids', index=3, - number=4, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _CALLMESSAGE_TYPE, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2547, - serialized_end=2752, + name='CallMessage', + full_name='signalservice.CallMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', + full_name='signalservice.CallMessage.type', + index=0, + number=1, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=1, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='sdps', + full_name='signalservice.CallMessage.sdps', + index=1, + number=2, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='sdpMLineIndexes', + full_name='signalservice.CallMessage.sdpMLineIndexes', + index=2, + number=3, + type=13, + cpp_type=3, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='sdpMids', + full_name='signalservice.CallMessage.sdpMids', + index=3, + number=4, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_CALLMESSAGE_TYPE], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=2547, + serialized_end=2752, ) _CONFIGURATIONMESSAGE_CLOSEDGROUP = _descriptor.Descriptor( - name='ClosedGroup', - full_name='signalservice.ConfigurationMessage.ClosedGroup', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='publicKey', full_name='signalservice.ConfigurationMessage.ClosedGroup.publicKey', index=0, - number=1, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='name', full_name='signalservice.ConfigurationMessage.ClosedGroup.name', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='encryptionKeyPair', full_name='signalservice.ConfigurationMessage.ClosedGroup.encryptionKeyPair', index=2, - number=3, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='members', full_name='signalservice.ConfigurationMessage.ClosedGroup.members', index=3, - number=4, type=12, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='admins', full_name='signalservice.ConfigurationMessage.ClosedGroup.admins', index=4, - number=5, type=12, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2999, - serialized_end=3129, + name='ClosedGroup', + full_name='signalservice.ConfigurationMessage.ClosedGroup', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='publicKey', + full_name='signalservice.ConfigurationMessage.ClosedGroup.publicKey', + index=0, + number=1, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='name', + full_name='signalservice.ConfigurationMessage.ClosedGroup.name', + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='encryptionKeyPair', + full_name='signalservice.ConfigurationMessage.ClosedGroup.encryptionKeyPair', + index=2, + number=3, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='members', + full_name='signalservice.ConfigurationMessage.ClosedGroup.members', + index=3, + number=4, + type=12, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='admins', + full_name='signalservice.ConfigurationMessage.ClosedGroup.admins', + index=4, + number=5, + type=12, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=2999, + serialized_end=3129, ) _CONFIGURATIONMESSAGE_CONTACT = _descriptor.Descriptor( - name='Contact', - full_name='signalservice.ConfigurationMessage.Contact', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='publicKey', full_name='signalservice.ConfigurationMessage.Contact.publicKey', index=0, - number=1, type=12, cpp_type=9, label=2, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='name', full_name='signalservice.ConfigurationMessage.Contact.name', index=1, - number=2, type=9, cpp_type=9, label=2, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='profilePicture', full_name='signalservice.ConfigurationMessage.Contact.profilePicture', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='profileKey', full_name='signalservice.ConfigurationMessage.Contact.profileKey', index=3, - number=4, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=3131, - serialized_end=3217, + name='Contact', + full_name='signalservice.ConfigurationMessage.Contact', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='publicKey', + full_name='signalservice.ConfigurationMessage.Contact.publicKey', + index=0, + number=1, + type=12, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='name', + full_name='signalservice.ConfigurationMessage.Contact.name', + index=1, + number=2, + type=9, + cpp_type=9, + label=2, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='profilePicture', + full_name='signalservice.ConfigurationMessage.Contact.profilePicture', + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='profileKey', + full_name='signalservice.ConfigurationMessage.Contact.profileKey', + index=3, + number=4, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=3131, + serialized_end=3217, ) _CONFIGURATIONMESSAGE = _descriptor.Descriptor( - name='ConfigurationMessage', - full_name='signalservice.ConfigurationMessage', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='closedGroups', full_name='signalservice.ConfigurationMessage.closedGroups', index=0, - number=1, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='openGroups', full_name='signalservice.ConfigurationMessage.openGroups', index=1, - number=2, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='displayName', full_name='signalservice.ConfigurationMessage.displayName', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='profilePicture', full_name='signalservice.ConfigurationMessage.profilePicture', index=3, - number=4, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='profileKey', full_name='signalservice.ConfigurationMessage.profileKey', index=4, - number=5, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='contacts', full_name='signalservice.ConfigurationMessage.contacts', index=5, - number=6, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[_CONFIGURATIONMESSAGE_CLOSEDGROUP, _CONFIGURATIONMESSAGE_CONTACT, ], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=2755, - serialized_end=3217, + name='ConfigurationMessage', + full_name='signalservice.ConfigurationMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='closedGroups', + full_name='signalservice.ConfigurationMessage.closedGroups', + index=0, + number=1, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='openGroups', + full_name='signalservice.ConfigurationMessage.openGroups', + index=1, + number=2, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='displayName', + full_name='signalservice.ConfigurationMessage.displayName', + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='profilePicture', + full_name='signalservice.ConfigurationMessage.profilePicture', + index=3, + number=4, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='profileKey', + full_name='signalservice.ConfigurationMessage.profileKey', + index=4, + number=5, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='contacts', + full_name='signalservice.ConfigurationMessage.contacts', + index=5, + number=6, + type=11, + cpp_type=10, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[_CONFIGURATIONMESSAGE_CLOSEDGROUP, _CONFIGURATIONMESSAGE_CONTACT], + enum_types=[], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=2755, + serialized_end=3217, ) _RECEIPTMESSAGE = _descriptor.Descriptor( - name='ReceiptMessage', - full_name='signalservice.ReceiptMessage', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='type', full_name='signalservice.ReceiptMessage.type', index=0, - number=1, type=14, cpp_type=8, label=2, - has_default_value=False, default_value=1, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='timestamp', full_name='signalservice.ReceiptMessage.timestamp', index=1, - number=2, type=4, cpp_type=4, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _RECEIPTMESSAGE_TYPE, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=3219, - serialized_end=3322, + name='ReceiptMessage', + full_name='signalservice.ReceiptMessage', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='type', + full_name='signalservice.ReceiptMessage.type', + index=0, + number=1, + type=14, + cpp_type=8, + label=2, + has_default_value=False, + default_value=1, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='timestamp', + full_name='signalservice.ReceiptMessage.timestamp', + index=1, + number=2, + type=4, + cpp_type=4, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_RECEIPTMESSAGE_TYPE], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=3219, + serialized_end=3322, ) _ATTACHMENTPOINTER = _descriptor.Descriptor( - name='AttachmentPointer', - full_name='signalservice.AttachmentPointer', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='id', full_name='signalservice.AttachmentPointer.id', index=0, - number=1, type=6, cpp_type=4, label=2, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='contentType', full_name='signalservice.AttachmentPointer.contentType', index=1, - number=2, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='key', full_name='signalservice.AttachmentPointer.key', index=2, - number=3, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='size', full_name='signalservice.AttachmentPointer.size', index=3, - number=4, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='thumbnail', full_name='signalservice.AttachmentPointer.thumbnail', index=4, - number=5, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='digest', full_name='signalservice.AttachmentPointer.digest', index=5, - number=6, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='fileName', full_name='signalservice.AttachmentPointer.fileName', index=6, - number=7, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='flags', full_name='signalservice.AttachmentPointer.flags', index=7, - number=8, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='width', full_name='signalservice.AttachmentPointer.width', index=8, - number=9, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='height', full_name='signalservice.AttachmentPointer.height', index=9, - number=10, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='caption', full_name='signalservice.AttachmentPointer.caption', index=10, - number=11, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='url', full_name='signalservice.AttachmentPointer.url', index=11, - number=101, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _ATTACHMENTPOINTER_FLAGS, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=3325, - serialized_end=3561, + name='AttachmentPointer', + full_name='signalservice.AttachmentPointer', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='id', + full_name='signalservice.AttachmentPointer.id', + index=0, + number=1, + type=6, + cpp_type=4, + label=2, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='contentType', + full_name='signalservice.AttachmentPointer.contentType', + index=1, + number=2, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='key', + full_name='signalservice.AttachmentPointer.key', + index=2, + number=3, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='size', + full_name='signalservice.AttachmentPointer.size', + index=3, + number=4, + type=13, + cpp_type=3, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='thumbnail', + full_name='signalservice.AttachmentPointer.thumbnail', + index=4, + number=5, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='digest', + full_name='signalservice.AttachmentPointer.digest', + index=5, + number=6, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='fileName', + full_name='signalservice.AttachmentPointer.fileName', + index=6, + number=7, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='flags', + full_name='signalservice.AttachmentPointer.flags', + index=7, + number=8, + type=13, + cpp_type=3, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='width', + full_name='signalservice.AttachmentPointer.width', + index=8, + number=9, + type=13, + cpp_type=3, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='height', + full_name='signalservice.AttachmentPointer.height', + index=9, + number=10, + type=13, + cpp_type=3, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='caption', + full_name='signalservice.AttachmentPointer.caption', + index=10, + number=11, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='url', + full_name='signalservice.AttachmentPointer.url', + index=11, + number=101, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_ATTACHMENTPOINTER_FLAGS], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=3325, + serialized_end=3561, ) _GROUPCONTEXT = _descriptor.Descriptor( - name='GroupContext', - full_name='signalservice.GroupContext', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='id', full_name='signalservice.GroupContext.id', index=0, - number=1, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='type', full_name='signalservice.GroupContext.type', index=1, - number=2, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='name', full_name='signalservice.GroupContext.name', index=2, - number=3, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='members', full_name='signalservice.GroupContext.members', index=3, - number=4, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='avatar', full_name='signalservice.GroupContext.avatar', index=4, - number=5, type=11, cpp_type=10, label=1, - has_default_value=False, default_value=None, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='admins', full_name='signalservice.GroupContext.admins', index=5, - number=6, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - _GROUPCONTEXT_TYPE, - ], - serialized_options=None, - is_extendable=False, - syntax='proto2', - extension_ranges=[], - oneofs=[ - ], - serialized_start=3564, - serialized_end=3809, + name='GroupContext', + full_name='signalservice.GroupContext', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='id', + full_name='signalservice.GroupContext.id', + index=0, + number=1, + type=12, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b(""), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='type', + full_name='signalservice.GroupContext.type', + index=1, + number=2, + type=14, + cpp_type=8, + label=1, + has_default_value=False, + default_value=0, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='name', + full_name='signalservice.GroupContext.name', + index=2, + number=3, + type=9, + cpp_type=9, + label=1, + has_default_value=False, + default_value=_b("").decode('utf-8'), + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='members', + full_name='signalservice.GroupContext.members', + index=3, + number=4, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='avatar', + full_name='signalservice.GroupContext.avatar', + index=4, + number=5, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + _descriptor.FieldDescriptor( + name='admins', + full_name='signalservice.GroupContext.admins', + index=5, + number=6, + type=9, + cpp_type=9, + label=3, + has_default_value=False, + default_value=[], + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], + extensions=[], + nested_types=[], + enum_types=[_GROUPCONTEXT_TYPE], + serialized_options=None, + is_extendable=False, + syntax='proto2', + extension_ranges=[], + oneofs=[], + serialized_start=3564, + serialized_end=3809, ) _ENVELOPE.fields_by_name['type'].enum_type = _ENVELOPE_TYPE @@ -1444,10 +2402,16 @@ _DATAMESSAGE_PREVIEW.containing_type = _DATAMESSAGE _DATAMESSAGE_LOKIPROFILE.containing_type = _DATAMESSAGE _DATAMESSAGE_OPENGROUPINVITATION.containing_type = _DATAMESSAGE -_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER.containing_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE -_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE.fields_by_name['type'].enum_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_TYPE +_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER.containing_type = ( + _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE +) +_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE.fields_by_name[ + 'type' +].enum_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_TYPE _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE.fields_by_name['encryptionKeyPair'].message_type = _KEYPAIR -_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE.fields_by_name['wrappers'].message_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER +_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE.fields_by_name[ + 'wrappers' +].message_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE.containing_type = _DATAMESSAGE _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_TYPE.containing_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE _DATAMESSAGE.fields_by_name['attachments'].message_type = _ATTACHMENTPOINTER @@ -1456,14 +2420,18 @@ _DATAMESSAGE.fields_by_name['preview'].message_type = _DATAMESSAGE_PREVIEW _DATAMESSAGE.fields_by_name['profile'].message_type = _DATAMESSAGE_LOKIPROFILE _DATAMESSAGE.fields_by_name['openGroupInvitation'].message_type = _DATAMESSAGE_OPENGROUPINVITATION -_DATAMESSAGE.fields_by_name['closedGroupControlMessage'].message_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE +_DATAMESSAGE.fields_by_name[ + 'closedGroupControlMessage' +].message_type = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE _DATAMESSAGE_FLAGS.containing_type = _DATAMESSAGE _CALLMESSAGE.fields_by_name['type'].enum_type = _CALLMESSAGE_TYPE _CALLMESSAGE_TYPE.containing_type = _CALLMESSAGE _CONFIGURATIONMESSAGE_CLOSEDGROUP.fields_by_name['encryptionKeyPair'].message_type = _KEYPAIR _CONFIGURATIONMESSAGE_CLOSEDGROUP.containing_type = _CONFIGURATIONMESSAGE _CONFIGURATIONMESSAGE_CONTACT.containing_type = _CONFIGURATIONMESSAGE -_CONFIGURATIONMESSAGE.fields_by_name['closedGroups'].message_type = _CONFIGURATIONMESSAGE_CLOSEDGROUP +_CONFIGURATIONMESSAGE.fields_by_name[ + 'closedGroups' +].message_type = _CONFIGURATIONMESSAGE_CLOSEDGROUP _CONFIGURATIONMESSAGE.fields_by_name['contacts'].message_type = _CONFIGURATIONMESSAGE_CONTACT _RECEIPTMESSAGE.fields_by_name['type'].enum_type = _RECEIPTMESSAGE_TYPE _RECEIPTMESSAGE_TYPE.containing_type = _RECEIPTMESSAGE @@ -1485,102 +2453,144 @@ DESCRIPTOR.message_types_by_name['GroupContext'] = _GROUPCONTEXT _sym_db.RegisterFileDescriptor(DESCRIPTOR) -Envelope = _reflection.GeneratedProtocolMessageType('Envelope', (_message.Message,), dict( - DESCRIPTOR = _ENVELOPE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.Envelope) - )) +Envelope = _reflection.GeneratedProtocolMessageType( + 'Envelope', + (_message.Message,), + dict( + DESCRIPTOR=_ENVELOPE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.Envelope) + ), +) _sym_db.RegisterMessage(Envelope) -TypingMessage = _reflection.GeneratedProtocolMessageType('TypingMessage', (_message.Message,), dict( - DESCRIPTOR = _TYPINGMESSAGE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.TypingMessage) - )) +TypingMessage = _reflection.GeneratedProtocolMessageType( + 'TypingMessage', + (_message.Message,), + dict( + DESCRIPTOR=_TYPINGMESSAGE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.TypingMessage) + ), +) _sym_db.RegisterMessage(TypingMessage) -Unsend = _reflection.GeneratedProtocolMessageType('Unsend', (_message.Message,), dict( - DESCRIPTOR = _UNSEND, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.Unsend) - )) +Unsend = _reflection.GeneratedProtocolMessageType( + 'Unsend', + (_message.Message,), + dict( + DESCRIPTOR=_UNSEND, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.Unsend) + ), +) _sym_db.RegisterMessage(Unsend) -Content = _reflection.GeneratedProtocolMessageType('Content', (_message.Message,), dict( - DESCRIPTOR = _CONTENT, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.Content) - )) +Content = _reflection.GeneratedProtocolMessageType( + 'Content', + (_message.Message,), + dict( + DESCRIPTOR=_CONTENT, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.Content) + ), +) _sym_db.RegisterMessage(Content) -KeyPair = _reflection.GeneratedProtocolMessageType('KeyPair', (_message.Message,), dict( - DESCRIPTOR = _KEYPAIR, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.KeyPair) - )) +KeyPair = _reflection.GeneratedProtocolMessageType( + 'KeyPair', + (_message.Message,), + dict( + DESCRIPTOR=_KEYPAIR, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.KeyPair) + ), +) _sym_db.RegisterMessage(KeyPair) -DataExtractionNotification = _reflection.GeneratedProtocolMessageType('DataExtractionNotification', (_message.Message,), dict( - DESCRIPTOR = _DATAEXTRACTIONNOTIFICATION, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataExtractionNotification) - )) +DataExtractionNotification = _reflection.GeneratedProtocolMessageType( + 'DataExtractionNotification', + (_message.Message,), + dict( + DESCRIPTOR=_DATAEXTRACTIONNOTIFICATION, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataExtractionNotification) + ), +) _sym_db.RegisterMessage(DataExtractionNotification) -DataMessage = _reflection.GeneratedProtocolMessageType('DataMessage', (_message.Message,), dict( - - Quote = _reflection.GeneratedProtocolMessageType('Quote', (_message.Message,), dict( - - QuotedAttachment = _reflection.GeneratedProtocolMessageType('QuotedAttachment', (_message.Message,), dict( - DESCRIPTOR = _DATAMESSAGE_QUOTE_QUOTEDATTACHMENT, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage.Quote.QuotedAttachment) - )) - , - DESCRIPTOR = _DATAMESSAGE_QUOTE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage.Quote) - )) - , - - Preview = _reflection.GeneratedProtocolMessageType('Preview', (_message.Message,), dict( - DESCRIPTOR = _DATAMESSAGE_PREVIEW, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage.Preview) - )) - , - - LokiProfile = _reflection.GeneratedProtocolMessageType('LokiProfile', (_message.Message,), dict( - DESCRIPTOR = _DATAMESSAGE_LOKIPROFILE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage.LokiProfile) - )) - , - - OpenGroupInvitation = _reflection.GeneratedProtocolMessageType('OpenGroupInvitation', (_message.Message,), dict( - DESCRIPTOR = _DATAMESSAGE_OPENGROUPINVITATION, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage.OpenGroupInvitation) - )) - , - - ClosedGroupControlMessage = _reflection.GeneratedProtocolMessageType('ClosedGroupControlMessage', (_message.Message,), dict( - - KeyPairWrapper = _reflection.GeneratedProtocolMessageType('KeyPairWrapper', (_message.Message,), dict( - DESCRIPTOR = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper) - )) - , - DESCRIPTOR = _DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage.ClosedGroupControlMessage) - )) - , - DESCRIPTOR = _DATAMESSAGE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.DataMessage) - )) +DataMessage = _reflection.GeneratedProtocolMessageType( + 'DataMessage', + (_message.Message,), + dict( + Quote=_reflection.GeneratedProtocolMessageType( + 'Quote', + (_message.Message,), + dict( + QuotedAttachment=_reflection.GeneratedProtocolMessageType( + 'QuotedAttachment', + (_message.Message,), + dict( + DESCRIPTOR=_DATAMESSAGE_QUOTE_QUOTEDATTACHMENT, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage.Quote.QuotedAttachment) + ), + ), + DESCRIPTOR=_DATAMESSAGE_QUOTE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage.Quote) + ), + ), + Preview=_reflection.GeneratedProtocolMessageType( + 'Preview', + (_message.Message,), + dict( + DESCRIPTOR=_DATAMESSAGE_PREVIEW, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage.Preview) + ), + ), + LokiProfile=_reflection.GeneratedProtocolMessageType( + 'LokiProfile', + (_message.Message,), + dict( + DESCRIPTOR=_DATAMESSAGE_LOKIPROFILE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage.LokiProfile) + ), + ), + OpenGroupInvitation=_reflection.GeneratedProtocolMessageType( + 'OpenGroupInvitation', + (_message.Message,), + dict( + DESCRIPTOR=_DATAMESSAGE_OPENGROUPINVITATION, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage.OpenGroupInvitation) + ), + ), + ClosedGroupControlMessage=_reflection.GeneratedProtocolMessageType( + 'ClosedGroupControlMessage', + (_message.Message,), + dict( + KeyPairWrapper=_reflection.GeneratedProtocolMessageType( + 'KeyPairWrapper', + (_message.Message,), + dict( + DESCRIPTOR=_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE_KEYPAIRWRAPPER, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage.ClosedGroupControlMessage.KeyPairWrapper) + ), + ), + DESCRIPTOR=_DATAMESSAGE_CLOSEDGROUPCONTROLMESSAGE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage.ClosedGroupControlMessage) + ), + ), + DESCRIPTOR=_DATAMESSAGE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.DataMessage) + ), +) _sym_db.RegisterMessage(DataMessage) _sym_db.RegisterMessage(DataMessage.Quote) _sym_db.RegisterMessage(DataMessage.Quote.QuotedAttachment) @@ -1590,55 +2600,79 @@ _sym_db.RegisterMessage(DataMessage.ClosedGroupControlMessage) _sym_db.RegisterMessage(DataMessage.ClosedGroupControlMessage.KeyPairWrapper) -CallMessage = _reflection.GeneratedProtocolMessageType('CallMessage', (_message.Message,), dict( - DESCRIPTOR = _CALLMESSAGE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.CallMessage) - )) +CallMessage = _reflection.GeneratedProtocolMessageType( + 'CallMessage', + (_message.Message,), + dict( + DESCRIPTOR=_CALLMESSAGE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.CallMessage) + ), +) _sym_db.RegisterMessage(CallMessage) -ConfigurationMessage = _reflection.GeneratedProtocolMessageType('ConfigurationMessage', (_message.Message,), dict( - - ClosedGroup = _reflection.GeneratedProtocolMessageType('ClosedGroup', (_message.Message,), dict( - DESCRIPTOR = _CONFIGURATIONMESSAGE_CLOSEDGROUP, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.ConfigurationMessage.ClosedGroup) - )) - , - - Contact = _reflection.GeneratedProtocolMessageType('Contact', (_message.Message,), dict( - DESCRIPTOR = _CONFIGURATIONMESSAGE_CONTACT, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.ConfigurationMessage.Contact) - )) - , - DESCRIPTOR = _CONFIGURATIONMESSAGE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.ConfigurationMessage) - )) +ConfigurationMessage = _reflection.GeneratedProtocolMessageType( + 'ConfigurationMessage', + (_message.Message,), + dict( + ClosedGroup=_reflection.GeneratedProtocolMessageType( + 'ClosedGroup', + (_message.Message,), + dict( + DESCRIPTOR=_CONFIGURATIONMESSAGE_CLOSEDGROUP, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.ConfigurationMessage.ClosedGroup) + ), + ), + Contact=_reflection.GeneratedProtocolMessageType( + 'Contact', + (_message.Message,), + dict( + DESCRIPTOR=_CONFIGURATIONMESSAGE_CONTACT, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.ConfigurationMessage.Contact) + ), + ), + DESCRIPTOR=_CONFIGURATIONMESSAGE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.ConfigurationMessage) + ), +) _sym_db.RegisterMessage(ConfigurationMessage) _sym_db.RegisterMessage(ConfigurationMessage.ClosedGroup) _sym_db.RegisterMessage(ConfigurationMessage.Contact) -ReceiptMessage = _reflection.GeneratedProtocolMessageType('ReceiptMessage', (_message.Message,), dict( - DESCRIPTOR = _RECEIPTMESSAGE, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.ReceiptMessage) - )) +ReceiptMessage = _reflection.GeneratedProtocolMessageType( + 'ReceiptMessage', + (_message.Message,), + dict( + DESCRIPTOR=_RECEIPTMESSAGE, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.ReceiptMessage) + ), +) _sym_db.RegisterMessage(ReceiptMessage) -AttachmentPointer = _reflection.GeneratedProtocolMessageType('AttachmentPointer', (_message.Message,), dict( - DESCRIPTOR = _ATTACHMENTPOINTER, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.AttachmentPointer) - )) +AttachmentPointer = _reflection.GeneratedProtocolMessageType( + 'AttachmentPointer', + (_message.Message,), + dict( + DESCRIPTOR=_ATTACHMENTPOINTER, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.AttachmentPointer) + ), +) _sym_db.RegisterMessage(AttachmentPointer) -GroupContext = _reflection.GeneratedProtocolMessageType('GroupContext', (_message.Message,), dict( - DESCRIPTOR = _GROUPCONTEXT, - __module__ = 'sogs.session_pb2' - # @@protoc_insertion_point(class_scope:signalservice.GroupContext) - )) +GroupContext = _reflection.GeneratedProtocolMessageType( + 'GroupContext', + (_message.Message,), + dict( + DESCRIPTOR=_GROUPCONTEXT, + __module__='sogs.session_pb2' + # @@protoc_insertion_point(class_scope:signalservice.GroupContext) + ), +) _sym_db.RegisterMessage(GroupContext) diff --git a/tests/auth.py b/tests/auth.py index 72f9e196..777f2056 100644 --- a/tests/auth.py +++ b/tests/auth.py @@ -23,7 +23,8 @@ def x_sogs_raw( body: Optional[bytes] = None, *, b64_nonce: bool = True, - blinded: bool = False, + blinded15: bool = False, + blinded25: bool = False, timestamp_off: int = 0, nonce: bytes = None, ): @@ -37,7 +38,10 @@ def x_sogs_raw( n = nonce if nonce else x_sogs_nonce() ts = int(time.time()) + timestamp_off - if blinded: + if blinded25: + kA, ka = blinding.blind25_key_pair(s.encode(), sogs.crypto.server_pubkey_bytes) + pubkey = '25' + kA.hex() + elif blinded15: a = s.to_curve25519_private_key().encode() k = sodium.crypto_core_ed25519_scalar_reduce( blake2b(sogs.crypto.server_pubkey_bytes, digest_size=64) @@ -55,7 +59,7 @@ def x_sogs_raw( if body: to_sign.append(blake2b(body, digest_size=64)) - if blinded: + if blinded15 or blinded25: H_rh = sha512(s.encode())[32:] r = sodium.crypto_core_ed25519_scalar_reduce(sha512([H_rh, kA, *to_sign])) sig_R = sodium.crypto_scalarmult_ed25519_base_noclamp(r) @@ -84,4 +88,6 @@ def x_sogs(*args, **kwargs): def x_sogs_for(user, *args, **kwargs): B = sogs.crypto.server_pubkey - return x_sogs(user.ed_key, B, *args, blinded=user.is_blinded, **kwargs) + return x_sogs( + user.ed_key, B, *args, blinded15=user.is_blinded15, blinded25=user.is_blinded25, **kwargs + ) diff --git a/tests/test_auth.py b/tests/test_auth.py index 923c111b..5294989c 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,5 +1,5 @@ from sogs.web import app -from sogs.crypto import server_pubkey +from sogs.crypto import server_pubkey, compute_blinded25_id_from_05 from sogs.routes.auth import user_required from auth import x_sogs_raw, x_sogs import sogs.utils @@ -19,7 +19,7 @@ def auth_test_whoami(): if g.user is None: res["user"] = None else: - res["user"] = {"uid": g.user.id, "session_id": g.user.session_id} + res["user"] = {"uid": g.user.id, "session_id": g.user.using_id} if 'X-Foo' in request.headers: res["foo"] = request.headers['X-Foo'] @@ -134,7 +134,7 @@ def test_auth_banned(client, global_admin, user, db): assert r.json == {'user': None} r = client.get("/auth_test/whoami", headers=x_sogs(a, B, 'GET', '/auth_test/whoami')) assert r.status_code == 200 - assert r.json == {"user": {"uid": 2, "session_id": user.session_id}} + assert r.json == {"user": {"uid": 2, "session_id": user.using_id}} user.ban(banned_by=global_admin) @@ -379,10 +379,9 @@ def test_auth_batch(client, db): def test_auth_legacy(client, db, admin, user, room): - # Make a legacy auth token to make sure it works as expected first, but also to make sure it # gets ignored when we use X-SOGS-*. - raw_token = sogs.utils.make_legacy_token(admin.session_id) + raw_token = sogs.utils.make_legacy_token(admin.using_id) token = sogs.utils.encode_base64(raw_token) a = admin.ed_key @@ -395,7 +394,7 @@ def test_auth_legacy(client, db, admin, user, room): r = client.post( "/legacy/block_list", headers={"Room": room.token, "Authorization": bad_token}, - json={"public_key": user.session_id}, + json={"public_key": user.using_id}, ) assert r.status_code == 401 @@ -403,12 +402,13 @@ def test_auth_legacy(client, db, admin, user, room): r = client.post( "/legacy/block_list", headers={"Room": room.token, "Authorization": token}, - json={"public_key": user.session_id}, + json={"public_key": user.using_id}, ) assert r.status_code == 200 assert r.json == {"status_code": 200} S2 = '05' + a2.verify_key.to_curve25519_public_key().encode().hex() + S2_25 = compute_blinded25_id_from_05(S2) r = client.post( "/legacy/block_list", headers={"Room": room.token, "Authorization": token}, @@ -420,10 +420,10 @@ def test_auth_legacy(client, db, admin, user, room): # Verify that both bans are present r = client.get("/legacy/block_list", headers={"Room": room.token, "Authorization": token}) assert r.status_code == 200 - assert r.json == {"status_code": 200, "banned_members": sorted([user.session_id, S2])} + assert r.json == {"status_code": 200, "banned_members": sorted([user.session_id, S2_25])} # Retrieve bans as one of the banned users: should only see himself - utoken = sogs.utils.encode_base64(sogs.utils.make_legacy_token(user.session_id)) + utoken = sogs.utils.encode_base64(sogs.utils.make_legacy_token(user.using_id)) r = client.get("/legacy/block_list", headers={"Room": room.token, "Authorization": utoken}) assert r.status_code == 200 assert r.json == {"status_code": 200, "banned_members": [user.session_id]} @@ -441,7 +441,9 @@ def test_auth_legacy(client, db, admin, user, room): h['Room'] = room.token r = client.get("/legacy/block_list", headers=h) assert r.status_code == 200 - assert r.json == {"status_code": 200, "banned_members": [S2]} + assert r.json == {"status_code": 200, "banned_members": [S2_25]} + + app.logger.warning(f"spacing log line") # Remove the bans as admin, with X-SOGS rh = {"Room": room.token} @@ -470,7 +472,7 @@ def test_auth_legacy(client, db, admin, user, room): { 'code': 200, 'headers': {'content-type': 'application/json'}, - 'body': {'status_code': 200, 'banned_members': sorted([user.session_id, S2])}, + 'body': {'status_code': 200, 'banned_members': sorted([user.session_id, S2_25])}, }, { 'code': 200, @@ -480,7 +482,7 @@ def test_auth_legacy(client, db, admin, user, room): { 'code': 200, 'headers': {'content-type': 'application/json'}, - 'body': {'status_code': 200, 'banned_members': [S2]}, + 'body': {'status_code': 200, 'banned_members': [S2_25]}, }, { 'code': 200, @@ -524,7 +526,7 @@ def test_small_subgroups(client, db): assert r.data == b'Invalid authentication: given X-SOGS-Pubkey is not a valid Ed25519 pubkey' # Now try with a blinded id: - headers = x_sogs(a, B, 'GET', '/auth_test/whoami', blinded=True) + headers = x_sogs(a, B, 'GET', '/auth_test/whoami', blinded15=True) assert headers['X-SOGS-Pubkey'].startswith('15') A = bytes.fromhex(headers['X-SOGS-Pubkey'][2:]) diff --git a/tests/test_blinding.py b/tests/test_blinding.py index 9c46b599..8e4b2e7a 100644 --- a/tests/test_blinding.py +++ b/tests/test_blinding.py @@ -4,6 +4,7 @@ from user import User as TUser from nacl.signing import SigningKey from sogs.hashing import blake2b +from session_util import blinding from util import config_override import nacl.bindings as sodium import pytest @@ -20,96 +21,117 @@ @pytest.mark.parametrize( - ["seed_hex", "blinded_id_exp"], + ["seed_hex", "blinded15_id_exp", "blinded25_id_exp"], [ pytest.param( "880adf5164a79bce71f7387fbc2cb2693c0bf0ab4cb42bf1edafddade7527a66", "15cef185d46b60a548641bd8c5baa4b7cf90b7da8e883c0ac774c703d249086479", + "25dd332c1de0038e5b5b6d2d037569c343d1e18500a94716f108f1918c0879ce3b", ), - pytest.param( - "67416582e0700081604860d270bc986011fc5e62c53de908a9a5af2cb497c528", - "15f8fbeb20cdde5e0cc0ec84e0b3705ca6090c7b23e8132589970473a5592ba388", - ), - pytest.param( - "a5ad71709cfa315d147921e377186270367fd06926f4dbfe33f519dec6b016f7", - "15758e10dc51210d7a36ea6076e2aa84d9f87283bddb508364272dce0a7618f92a", - ), - pytest.param( - "c929a389a0dcf375ae8177891655b3835773e3a2d6d27490de8b8a160ca472f8", - "1515ad8f8c5e56b31078a4a5ae73938bd523b1c86ea36033d564759e4495fbb64d", - ), - pytest.param( - "0576076b8a82aae0fa1d0f00e97b538b43205f63759a972f26b851a55b60b5d0", - "15375a56d4cbf0538f4b326e54917fd1953e9e3dfe076eb8b35929a8d869a15c13", - ), - pytest.param( - "0a5db01db307ffd1bbe3cdd0d47c71e8837c60b38983d1df1b187301959095c9", - "151a821dd107ac68845f82085efb1f88d046a084a63f7fc381ec07a367e6bc5aac", - ), - pytest.param( - "d9b4ff572d4ebbcf26b07329f9029462f0606087d64e8932e698aa0a98231ce3", - "15a4acf4c814fd1bcf83ebbe42c276630a63e32365633cb57089544b3a60b5e4ac", - ), - pytest.param( - "dbcf64e7e6323ace8a75327119c13ef0b41e0efb94e594a6424ba41472987844", - "1503e60a1fbde2a930e11db0898220ceb41e5ea9161f61ff1dc7d83be3e9b96993", - ), - pytest.param( - "2e90f20775370121a2db8413a68bb41c3618e63c744c865d8b03ca2cb9d52e9e", - "150bfdf09d985453d70b07b779ac7de982c0b6190c19126df74e8ca3adbfb87fec", - ), - pytest.param( - "0b19b8b2f006f73810a86244697ac3feb3500af22f97434bf1e4bac575e95d2f", - "15c430f8cf5e3ca4a3d0fa79d75fe60b3dc21212b4467ddd01fc1173c738161628", - ), - pytest.param( - "32c58327a3856acb77ca0e97993100b4a14475b2d5cd3804213ae2d6f2515709", - "150fdb6a400ade0aa2d261999fc51aa0151201d30626b30ec94d3a06a927948523", - ), - pytest.param( - "f5c57e9949bbb87b3ae9fa374bc05b8e945c33141b7eb19c5125d17023120287", - "15cdda69401f8ca32c4760b025b8315967ce9f5c53d4b75239b26d8ff9db5852f8", - ), - pytest.param( - "3aacbfb5059e1df00d11ff5742f8a5b91cdb9fe163f38906d7dfaae29ad30c0c", - "152701bb6cf273f7c30a0b2bb3a4b027415aab3fdff5d44b7b50af269aaa46007d", - ), - pytest.param( - "cce2487f4f1a01a54811204e8c774e7380c080f5f40cda0ef395752ef96dd35c", - "15c92aa80e809a84d97323f911355d5015e916f3d5bebc297a17b4c44bad487ad6", - ), - pytest.param( - "a414c2990f36a115308f74bbcb56c4238135c0578abf8de0505b08e9c7b69134", - "150e51c490bc7c570310276b7fdaeb9e0e14ab4674ce8217df5418b621b52c5c31", - ), - pytest.param( - "cbf84283c5d4a906b81e7533005fdd832d9d3712e71d5ee8247e3d32c1e2e38c", - "157b0487fa9bc7449a167d66b56eb3e3fc628101d84a08f3f510f46de90de2e3a4", - ), - pytest.param( - "e75399dac3b5b3675874ba1708d1effc6ab9bbd5b0fac4cf78a3c2b36af9cfc5", - "15f277d3d6afbecc15c71d16c3f183e6dbb772b176f3c818265f4459aa649b9d80", - ), - pytest.param( - "6cef60808348898f17123eb4f47556f22ae0e7bd1988455da6d4b685ea0f93d0", - "152d766ba9a19fd108e8f397b7fddaad2473cf13192858b8fd28f641e6c817c7c1", - ), - pytest.param( - "9396176367912b4bc9b2fca427bf7fea97293ee9db75e521e31e4618e2da061c", - "15a2308a015da570bd749348991d4fee7b0ea5816f372a6c584581964680c9d46a", - ), - pytest.param( - "b9ac6f130f0ef218e1fbd9484b38ba3a0a8ec5657744732b0a4a9e7f6c80a62e", - "1513533ac53ea094b0c0e907046ffc2ade32122da069df503583bf89d6af01e127", - ), + # pytest.param( + # "67416582e0700081604860d270bc986011fc5e62c53de908a9a5af2cb497c528", + # "15f8fbeb20cdde5e0cc0ec84e0b3705ca6090c7b23e8132589970473a5592ba388", + # "25c5fd9c611418564208e8b9ccf4268081bde43734bb9e1c86e604e56ce8c14e90", + # ), + # pytest.param( + # "a5ad71709cfa315d147921e377186270367fd06926f4dbfe33f519dec6b016f7", + # "15758e10dc51210d7a36ea6076e2aa84d9f87283bddb508364272dce0a7618f92a", + # "250a882a0fefbd770dd1b75ad8cf621ff8382156103ca0501537bc20b07454da21", + # ), + # pytest.param( + # "c929a389a0dcf375ae8177891655b3835773e3a2d6d27490de8b8a160ca472f8", + # "1515ad8f8c5e56b31078a4a5ae73938bd523b1c86ea36033d564759e4495fbb64d", + # "257321a93753b7b30ddc0f1b14cbba13f5e4e22e3fba0eddb2dcb551c81ad89420", + # ), + # pytest.param( + # "0576076b8a82aae0fa1d0f00e97b538b43205f63759a972f26b851a55b60b5d0", + # "15375a56d4cbf0538f4b326e54917fd1953e9e3dfe076eb8b35929a8d869a15c13", + # "259056850c536fd9f77619f717436ca0cb6f06a4826bad9f9e266bbee17e54f30f", + # ), + # pytest.param( + # "0a5db01db307ffd1bbe3cdd0d47c71e8837c60b38983d1df1b187301959095c9", + # "151a821dd107ac68845f82085efb1f88d046a084a63f7fc381ec07a367e6bc5aac", + # "252431489b136d451833f875079d580c79a11052de4c2aff0715c3a99d4b190418", + # ), + # pytest.param( + # "d9b4ff572d4ebbcf26b07329f9029462f0606087d64e8932e698aa0a98231ce3", + # "15a4acf4c814fd1bcf83ebbe42c276630a63e32365633cb57089544b3a60b5e4ac", + # "25087f66c9a51233b22c9b7f417f5f1c4feb458b61b57f1f43b87bbcd90884e37e", + # ), + # pytest.param( + # "dbcf64e7e6323ace8a75327119c13ef0b41e0efb94e594a6424ba41472987844", + # "1503e60a1fbde2a930e11db0898220ceb41e5ea9161f61ff1dc7d83be3e9b96993", + # "25ea989f9cd4c43a7efbee131f0fe191a5fbc7a9021a3876734991d407c1bbe0ef", + # ), + # pytest.param( + # "2e90f20775370121a2db8413a68bb41c3618e63c744c865d8b03ca2cb9d52e9e", + # "150bfdf09d985453d70b07b779ac7de982c0b6190c19126df74e8ca3adbfb87fec", + # "25bd557beffc4c89ab6e0a6756b56737ece66a7a20c5972bc456aec654a93d742f", + # ), + # pytest.param( + # "0b19b8b2f006f73810a86244697ac3feb3500af22f97434bf1e4bac575e95d2f", + # "15c430f8cf5e3ca4a3d0fa79d75fe60b3dc21212b4467ddd01fc1173c738161628", + # "25bb9c4042a6bd16d3c70d500aba14010c0e550ba9f855f777a804f13605929ff1", + # ), + # pytest.param( + # "32c58327a3856acb77ca0e97993100b4a14475b2d5cd3804213ae2d6f2515709", + # "150fdb6a400ade0aa2d261999fc51aa0151201d30626b30ec94d3a06a927948523", + # "25730a9c8051e9afbb77a119378b3478d6a48460877abad1e5e086c669bb274330", + # ), + # pytest.param( + # "f5c57e9949bbb87b3ae9fa374bc05b8e945c33141b7eb19c5125d17023120287", + # "15cdda69401f8ca32c4760b025b8315967ce9f5c53d4b75239b26d8ff9db5852f8", + # "25e060e2f77a206509eb93fd10fe2356e6f1d7d7c050d1ac6d6d94921f83c81f66", + # ), + # pytest.param( + # "3aacbfb5059e1df00d11ff5742f8a5b91cdb9fe163f38906d7dfaae29ad30c0c", + # "152701bb6cf273f7c30a0b2bb3a4b027415aab3fdff5d44b7b50af269aaa46007d", + # "250c133946491e947fa830a6acb0d64c26f553d1d88192ee08c2ed938ff3962873", + # ), + # pytest.param( + # "cce2487f4f1a01a54811204e8c774e7380c080f5f40cda0ef395752ef96dd35c", + # "15c92aa80e809a84d97323f911355d5015e916f3d5bebc297a17b4c44bad487ad6", + # "255c61e408fc5f2a14ff134cd00f27163389e5f029b47899e521c49eabcad12a77", + # ), + # pytest.param( + # "a414c2990f36a115308f74bbcb56c4238135c0578abf8de0505b08e9c7b69134", + # "150e51c490bc7c570310276b7fdaeb9e0e14ab4674ce8217df5418b621b52c5c31", + # "2500d8b5b43be6ea839c44e1fcdf7cc03bb1bd99fe4dbec1953d0eabe5a25b624d", + # ), + # pytest.param( + # "cbf84283c5d4a906b81e7533005fdd832d9d3712e71d5ee8247e3d32c1e2e38c", + # "157b0487fa9bc7449a167d66b56eb3e3fc628101d84a08f3f510f46de90de2e3a4", + # "2543443a13cb90d7f27b5b1c59cac83cebc622664010c57aeb26ced9f70ba8d3b4", + # ), + # pytest.param( + # "e75399dac3b5b3675874ba1708d1effc6ab9bbd5b0fac4cf78a3c2b36af9cfc5", + # "15f277d3d6afbecc15c71d16c3f183e6dbb772b176f3c818265f4459aa649b9d80", + # "25d9b8100c3e0ea4db99e3b223c109b13a370680b81bd3daefed0d86c22626c823", + # ), + # pytest.param( + # "6cef60808348898f17123eb4f47556f22ae0e7bd1988455da6d4b685ea0f93d0", + # "152d766ba9a19fd108e8f397b7fddaad2473cf13192858b8fd28f641e6c817c7c1", + # "258651b481f18c7cec60324772307214875a1438a1f5bda0c87d07466b22facf1d", + # ), + # pytest.param( + # "9396176367912b4bc9b2fca427bf7fea97293ee9db75e521e31e4618e2da061c", + # "15a2308a015da570bd749348991d4fee7b0ea5816f372a6c584581964680c9d46a", + # "257f0676fe5e799e5025cebd01cb0f3c303a46ebb621d8c7700596a5d9c1aff17a", + # ), + # pytest.param( + # "b9ac6f130f0ef218e1fbd9484b38ba3a0a8ec5657744732b0a4a9e7f6c80a62e", + # "1513533ac53ea094b0c0e907046ffc2ade32122da069df503583bf89d6af01e127", + # "258b5b25de35592d935a5a8682a43478f2d02af48dc4215148e84d067bddd7ee40", + # ), ], ) -def test_blinded_key_derivation(seed_hex, blinded_id_exp): +def test_blinded_key_derivation(seed_hex, blinded15_id_exp, blinded25_id_exp): """ Tests that we can successfully compute the blinded session id from the unblinded session id. seed_hex - the ed25519 master key seed - blinded_id_exp - the expected blinded ed25519-based pubkey + blinded15_id_exp - the expected 15xxx blinded ed25519-based pubkey + blinded25_id_exp - the expected 25xxx blinded ed25519-based pubkey """ s = SigningKey(bytes.fromhex(seed_hex)) @@ -117,29 +139,88 @@ def test_blinded_key_derivation(seed_hex, blinded_id_exp): # (which happens to *also* be the private scalar when converting to curve, hence the name). a = s.to_curve25519_private_key().encode() - k = sodium.crypto_core_ed25519_scalar_reduce(blake2b(fake_server_pubkey_bytes, digest_size=64)) - ka = sodium.crypto_core_ed25519_scalar_mul(k, a) - kA = sodium.crypto_scalarmult_ed25519_base_noclamp(ka) + k15 = sodium.crypto_core_ed25519_scalar_reduce( + blake2b(fake_server_pubkey_bytes, digest_size=64) + ) + k15a = sodium.crypto_core_ed25519_scalar_mul(k15, a) + k15A = sodium.crypto_scalarmult_ed25519_base_noclamp(k15a) + + k25 = sodium.crypto_core_ed25519_scalar_reduce( + blake2b( + [b'\x05' + s.verify_key.to_curve25519_public_key().encode(), fake_server_pubkey_bytes], + digest_size=64, + ) + ) + k25a = sodium.crypto_core_ed25519_scalar_mul(k25, a) + k25A = sodium.crypto_scalarmult_ed25519_base_noclamp(k25a) session_id = '05' + s.to_curve25519_private_key().public_key.encode().hex() - blinded_id = '15' + kA.hex() + import sys - assert blinded_id == blinded_id_exp + print("edpk: {}, sid: {}".format(s.verify_key.encode().hex(), session_id), file=sys.stderr) + blinded15_id = '15' + k15A.hex() + blinded25_id = '25' + k25A.hex() - id_pos = crypto.compute_blinded_abs_id(session_id, k=k) - assert len(id_pos) == 66 - id_neg = crypto.blinded_neg(id_pos) - assert len(id_neg) == 66 - assert id_pos != id_neg - assert id_pos[:64] == id_neg[:64] - assert int(id_pos[64], 16) ^ int(id_neg[64], 16) == 0x8 - assert id_pos[65] == id_neg[65] + assert blinded15_id == blinded15_id_exp + assert blinded25_id == blinded25_id_exp + assert blinded25_id == crypto.compute_blinded25_id_from_05( + session_id, _server_pk=fake_server_pubkey_bytes + ) + assert blinded25_id == crypto.compute_blinded25_id_from_15( + blinded15_id, _server_pk=fake_server_pubkey_bytes + ) - assert blinded_id in (id_pos, id_neg) + assert blinded25_id == blinding.blind25_id(session_id, fake_server_pubkey_bytes.hex()) + + id15_pos = crypto.compute_blinded15_abs_id(session_id, _k=k15) + assert len(id15_pos) == 66 + id15_neg = crypto.blinded15_neg(id15_pos) + print("id15+: {}, id15-: {}".format(id15_pos, id15_neg), file=sys.stderr) + assert len(id15_neg) == 66 + assert id15_pos != id15_neg + assert id15_pos[:64] == id15_neg[:64] + assert int(id15_pos[64], 16) ^ int(id15_neg[64], 16) == 0x8 + assert id15_pos[65] == id15_neg[65] + + assert blinded15_id in (id15_pos, id15_neg) + + assert ( + crypto.compute_blinded25_key_from_15( + bytes.fromhex(blinded15_id[2:]), _server_pk=fake_server_pubkey_bytes + ).hex() + == blinded25_id[2:] + ) + + assert blinded25_id == crypto.compute_blinded25_id_from_15( + blinded15_id, _server_pk=fake_server_pubkey_bytes + ) +# TODO: how to test migration to 25-blinded. This requires a database that the code no +# longer knows how to construct nor populate, so that will be interesting. +''' +@pytest.mark.parametrize( + ["get_blinded_id", "x_sogs_blind"], + [ + pytest.param(lambda x: x.blinded15_id, {"blinded15": True}), + pytest.param(lambda x: x.blinded25_id, {"blinded25": True}), + ], + ids=["blinded15", "blinded25"], +) def test_blinded_transition( - db, client, room, room2, user, user2, mod, admin, global_mod, global_admin, banned_user + db, + client, + room, + room2, + user, + user2, + mod, + admin, + global_mod, + global_admin, + banned_user, + get_blinded_id, + x_sogs_blind, ): r3 = Room.create('R3', name='R3', description='Another room') r3.default_read = False @@ -169,12 +250,11 @@ def test_blinded_transition( ) assert db.query("SELECT COUNT(*) FROM users").fetchone()[0] == 9 - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 0 assert [r[0] for r in db.query('SELECT "user" FROM user_permission_futures')] == [user2.id] assert [r[0] for r in db.query('SELECT "user" FROM user_ban_futures')] == [user2.id] - with config_override(REQUIRE_BLIND_KEYS=True): + with config_override(REQUIRE_BLIND_KEYS=True, REQUIRE_BLIND_V2=False): # Forcibly reinit, which should populate the blinding transition tables db.database_init() @@ -209,7 +289,7 @@ def test_blinded_transition( from sogs.model.user import User # Direct User construction of a new blinded user should transition: - b_mod = User(session_id=mod.blinded_id) + b_mod = User(session_id=get_blinded_id(mod)) unmigrated.remove(mod.id) assert unmigrated == set(r[0] for r in db.query('SELECT "user" FROM needs_blinding')) r1mods[0][0] = b_mod.session_id @@ -218,14 +298,16 @@ def test_blinded_transition( # Transition should occur on the first authenticated request: r = client.get( '/capabilities', - headers=x_sogs(user.ed_key, crypto.server_pubkey, 'GET', '/capabilities', blinded=True), + headers=x_sogs( + user.ed_key, crypto.server_pubkey, 'GET', '/capabilities', **x_sogs_blind + ), ) assert r.status_code == 200 unmigrated.remove(user.id) assert unmigrated == set(r[0] for r in db.query('SELECT "user" FROM needs_blinding')) r3mods[3].clear() - r3mods[3].extend(sorted((user.blinded_id, global_admin.session_id))) + r3mods[3].extend(sorted((get_blinded_id(user), global_admin.session_id))) assert room.get_mods(global_admin) == r1mods assert room2.get_mods(global_admin) == r2mods assert r3.get_mods(global_admin) == r3mods @@ -234,7 +316,7 @@ def test_blinded_transition( r = client.get( '/capabilities', headers=x_sogs( - u.ed_key, crypto.server_pubkey, 'GET', '/capabilities', blinded=True + u.ed_key, crypto.server_pubkey, 'GET', '/capabilities', **x_sogs_blind ), ) # Banned user should still be banned after migration: @@ -252,32 +334,38 @@ def test_blinded_transition( # NB: "global_admin" isn't actually an admin anymore (we transferred the permission to the # blinded equivalent), so shouldn't see the invisible mods: - assert room.get_mods(global_admin) == ([mod.blinded_id], [admin.blinded_id], [], []) + assert room.get_mods(global_admin) == ( + [get_blinded_id(mod)], + [get_blinded_id(admin)], + [], + [], + ) assert room2.get_mods(global_admin) == ([], [], [], []) assert r3.get_mods(global_admin) == ([], [], [], []) r1mods = ( - [mod.blinded_id], - [admin.blinded_id], - [global_mod.blinded_id], - [global_admin.blinded_id], + [get_blinded_id(mod)], + [get_blinded_id(admin)], + [get_blinded_id(global_mod)], + [get_blinded_id(global_admin)], ) - r2mods = ([], [], [global_mod.blinded_id], [global_admin.blinded_id]) + r2mods = ([], [], [get_blinded_id(global_mod)], [get_blinded_id(global_admin)]) r3mods = ( [], [], - [global_mod.blinded_id], - sorted((user.blinded_id, global_admin.blinded_id)), + [get_blinded_id(global_mod)], + sorted((get_blinded_id(user), get_blinded_id(global_admin))), ) - b_g_admin = User(session_id=global_admin.blinded_id) + b_g_admin = User(session_id=get_blinded_id(global_admin)) assert room.get_mods(b_g_admin) == r1mods assert room2.get_mods(b_g_admin) == r2mods assert r3.get_mods(b_g_admin) == r3mods - b_u2 = User(session_id=user2.blinded_id) + b_u2 = User(session_id=get_blinded_id(user2)) assert [r[0] for r in db.query('SELECT "user" FROM user_permission_futures')] == [b_u2.id] assert [r[0] for r in db.query('SELECT "user" FROM user_ban_futures')] == [b_u2.id] +''' def get_perm_flags(db, cols, exclude=[]): @@ -298,83 +386,15 @@ def get_perm_flags(db, cols, exclude=[]): def test_auto_blinding(db, client, room, user, user2, mod, global_admin): with config_override(REQUIRE_BLIND_KEYS=True): assert db.query("SELECT COUNT(*) FROM users").fetchone()[0] == 5 - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 0 - - # Banning a user by unblinded ID should set up the ban for the unblinded id *and* put them - # in the needs_blinding table - - room.ban_user(user2, mod=mod) - # Set these in two separate calls so that we are making sure multiple changes on the same - # user works as expected: - room.set_permissions(user, mod=mod, write=True) - room.set_permissions(user, mod=mod, write=False) - room.set_permissions(user, mod=mod, upload=False) - - upo = get_perm_flags(db, ['write', 'banned', 'upload'], [mod]) - assert upo == { - user.id: {'banned': False, 'write': False, 'upload': False}, - user2.id: {'banned': True, 'write': None, 'upload': None}, - } - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 2 - # Initializing the blinded user should resolve the needs_blinding: - b_user2 = User(session_id=user2.blinded_id) - assert b_user2.id != user2.id - - upo = get_perm_flags(db, ['write', 'banned'], [mod]) - assert upo == { - user.id: {'banned': False, 'write': False}, - b_user2.id: {'banned': True, 'write': None}, - } - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 1 - - room.unban_user(b_user2, mod=mod) - upo = get_perm_flags(db, ['write', 'banned'], [mod]) - assert upo == {user.id: {'banned': False, 'write': False}} - # Now, since user2's blinded account already exists, attempting to ban user2 should ban - # b_user2 directly: - user2._refresh() - room.ban_user(user2, mod=mod) - upo = get_perm_flags(db, ['write', 'banned'], [mod]) - assert upo == { - user.id: {'banned': False, 'write': False}, - b_user2.id: {'banned': True, 'write': None}, - } - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 1 - - u3 = TUser() - # Try the same for a global ban: - u3.ban(banned_by=global_admin) - u3.unban(unbanned_by=global_admin) - u3.ban(banned_by=global_admin) - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 2 - u3._refresh() - assert u3.banned - - b_u3 = User(session_id=u3.blinded_id) - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 1 - assert b_u3.banned - u3._refresh() - assert not u3.banned - - b_u3.unban(unbanned_by=global_admin) - u3._refresh() - b_u3._refresh() - assert not u3.banned - assert not b_u3.banned - u3.ban(banned_by=global_admin) # should ban b_u3 instead - b_u3._refresh() - u3._refresh() - assert not u3.banned - assert b_u3.banned - - # Moderator setting migration: - b_user = User(session_id=user.blinded_id) - user._refresh() - assert db.query("SELECT COUNT(*) FROM needs_blinding").fetchone()[0] == 0 - room.set_moderator(user, added_by=global_admin) - user._refresh() - b_user._refresh() - assert not room.check_moderator(user) - assert room.check_moderator(b_user) - assert not room.check_admin(b_user) + # Getting a user by unblinded ID or 15-blinded ID should get the single user row for that + # user, and user.using_id will equal the unblinded or 15-blinded ID used + b_user2 = User(session_id=user2.blinded15_id) + b25_user2 = User(session_id=user2.blinded25_id) + assert user2.session_id == user2.blinded25_id + assert user2.session_id == crypto.compute_blinded25_id_from_05(user2.unblinded_id) + assert user2.session_id == crypto.compute_blinded25_id_from_15(user2.blinded15_id) + assert b_user2.session_id == user2.session_id + assert b25_user2.session_id == user2.session_id + assert b_user2.id == user2.id + assert b25_user2.id == user2.id diff --git a/tests/test_dm.py b/tests/test_dm.py index b84d691e..d78a6103 100644 --- a/tests/test_dm.py +++ b/tests/test_dm.py @@ -9,8 +9,13 @@ from itertools import product -def test_dm_default_empty(client, blind_user): - r = sogs_get(client, '/inbox', blind_user) +def test_dm_inbox_nonblinded(client, user): + r = sogs_get(client, '/inbox', user) + assert r.status_code == 401 + + +def test_dm_default_empty(client, blind15_user): + r = sogs_get(client, '/inbox', blind15_user) assert r.status_code == 200 assert r.json == [] @@ -24,8 +29,8 @@ def make_post(message, sender, to): assert sender.is_blinded assert to.is_blinded a = sender.ed_key.to_curve25519_private_key().encode() - kA = bytes.fromhex(sender.session_id[2:]) - kB = bytes.fromhex(to.session_id[2:]) + kA = bytes.fromhex(sender.using_id[2:]) + kB = bytes.fromhex(to.using_id[2:]) key = blake2b(sodium.crypto_scalarmult_ed25519_noclamp(a, kB) + kA + kB, digest_size=32) # MESSAGE || UNBLINDED_ED_PUBKEY @@ -38,45 +43,45 @@ def make_post(message, sender, to): return {'message': encode_base64(data)} -def test_dm_send_from_banned_user(client, blind_user, blind_user2): - blind_user2.ban(banned_by=SystemUser()) +def test_dm_send_from_banned_user(client, blind15_user, blind15_user2): + blind15_user2.ban(banned_by=SystemUser()) r = sogs_post( client, - f'/inbox/{blind_user.session_id}', - make_post(b'beep', sender=blind_user2, to=blind_user), - blind_user2, + f'/inbox/{blind15_user.session_id}', + make_post(b'beep', sender=blind15_user2, to=blind15_user), + blind15_user2, ) assert r.status_code == 403 -def test_dm_send_to_banned_user(client, blind_user, blind_user2): - blind_user2.ban(banned_by=SystemUser()) +def test_dm_send_to_banned_user(client, blind15_user, blind15_user2): + blind15_user2.ban(banned_by=SystemUser()) r = sogs_post( client, - f'/inbox/{blind_user2.session_id}', - make_post(b'beep', sender=blind_user, to=blind_user2), - blind_user, + f'/inbox/{blind15_user2.session_id}', + make_post(b'beep', sender=blind15_user, to=blind15_user2), + blind15_user, ) assert r.status_code == 404 -def test_dm_send(client, blind_user, blind_user2): - post = make_post(b'bep', sender=blind_user, to=blind_user2) +def test_dm_send(client, blind15_user, blind15_user2): + post = make_post(b'bep', sender=blind15_user, to=blind15_user2) msg_expected = { 'id': 1, 'message': post['message'], - 'sender': blind_user.session_id, - 'recipient': blind_user2.session_id, + 'sender': blind15_user.using_id, + 'recipient': blind15_user2.session_id, } - r = sogs_post(client, f'/inbox/{blind_user2.session_id}', post, blind_user) + r = sogs_post(client, f'/inbox/{blind15_user2.using_id}', post, blind15_user) assert r.status_code == 201 data = r.json assert data.pop('posted_at') == from_now.seconds(0) assert data.pop('expires_at') == from_now.seconds(config.DM_EXPIRY) assert data == {k: v for k, v in msg_expected.items() if k != 'message'} - r = sogs_get(client, '/inbox', blind_user2) + r = sogs_get(client, '/inbox', blind15_user2) assert r.status_code == 200 assert len(r.json) == 1 data = r.json[0] @@ -84,7 +89,7 @@ def test_dm_send(client, blind_user, blind_user2): assert data.pop('expires_at') == from_now.seconds(config.DM_EXPIRY) assert data == msg_expected - r = sogs_get(client, '/outbox', blind_user) + r = sogs_get(client, '/outbox', blind15_user) assert len(r.json) == 1 data = r.json[0] assert data.pop('posted_at') == from_now.seconds(0) @@ -92,11 +97,12 @@ def test_dm_send(client, blind_user, blind_user2): assert data == msg_expected -def test_dm_delete(client, blind_user, blind_user2): +def test_dm_delete(client, blind15_user, blind15_user2): num_posts = 10 - for sender, recip in product((blind_user, blind_user2), repeat=2): + for sender, recip in product((blind15_user, blind15_user2), repeat=2): # make DMs for n in range(num_posts): + print(f"from: {sender.using_id}, to: {recip.using_id}") post = make_post(f"bep-{n}".encode('ascii'), sender=sender, to=recip) r = sogs_post(client, f'/inbox/{recip.session_id}', post, sender) assert r.status_code == 201 diff --git a/tests/test_files.py b/tests/test_files.py index e304b703..05702ea4 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -156,9 +156,9 @@ def test_no_file_crosspost(client, room, room2, user, global_admin): def _file_upload(client, room, user, *, unsafe=False, utf=False, filename): - url_post = f"/room/{room.token}/file" file_content = random(1024) + filename = filename.replace('\0', '\ufffd').replace('/', '\ufffd') filename_escaped = urllib.parse.quote(filename.encode('utf-8')) r = sogs_post_raw( client, @@ -175,8 +175,12 @@ def _file_upload(client, room, user, *, unsafe=False, utf=False, filename): r = sogs_get(client, f'/room/{room.token}/file/{id}', user) assert r.status_code == 200 assert r.data == file_content - expected = ('attachment', {'filename': filename.replace('\0', '\ufffd').replace('/', '\ufffd')}) - assert parse_options_header(r.headers.get('content-disposition')) == expected + + # FIXME: the filename.replace \0 and / above was in this "expected" line, but this caused + # the following assertion to fail. What is the correct behavior? + expected = ('attachment', {'filename': filename}) + content_disposition = parse_options_header(r.headers.get('content-disposition')) + assert content_disposition == expected f = File(id=id) if unsafe or utf: exp_path = f'{id}_' + re.sub(sogs.config.UPLOAD_FILENAME_BAD, "_", filename) diff --git a/tests/test_onion_requests.py b/tests/test_onion_requests.py index dd4d2fa5..3d519197 100644 --- a/tests/test_onion_requests.py +++ b/tests/test_onion_requests.py @@ -138,7 +138,6 @@ def decrypt_reply(data, *, v, enc_type): def test_v3(room, client): - # Construct an onion request for /room/test-room req = {'method': 'GET', 'endpoint': '/room/test-room'} data = build_payload(req, v=3, enc_type="xchacha20") @@ -154,7 +153,6 @@ def test_v3(room, client): def test_v3_authenticated(room, mod, client): - # Construct an onion request for /room/test-room req = {'method': 'GET', 'endpoint': '/room/test-room'} req['headers'] = auth.x_sogs(mod.ed_key, crypto.server_pubkey, req['method'], req['endpoint']) diff --git a/tests/test_reactions.py b/tests/test_reactions.py index 771fefb5..1ae4ef6b 100644 --- a/tests/test_reactions.py +++ b/tests/test_reactions.py @@ -124,7 +124,7 @@ def test_reactions(client, room, room2, user, user2, mod, admin, global_mod, glo 'data': 'ZWRpdGVkIGZha2UgZGF0YSA0', 'signature': 'ZmFrZSBzaWcgNGI' + 'A' * 71 + '==', 'seqno': seqno + 17, - 'session_id': mod.session_id, + 'session_id': mod.using_id, 'reactions': exp_reactions, } ] @@ -258,7 +258,7 @@ def test_reactions(client, room, room2, user, user2, mod, admin, global_mod, glo 'data': None, 'deleted': True, 'seqno': seqno, - 'session_id': user.session_id, + 'session_id': user.using_id, } @@ -291,7 +291,7 @@ def test_reaction_encoding(client, room, user, user2): 'data': 'ZmFrZSBkYXRh', # fake data 'id': 1, 'seqno': 5, - 'session_id': user.session_id, + 'session_id': user.using_id, 'signature': 'ZmFrZSBzaWc' + 'A' * 75 + '==', 'reactions': { '❤️': {'count': 2, 'index': 1, 'you': True}, diff --git a/tests/test_room_routes.py b/tests/test_room_routes.py index e5980829..0f1eb700 100644 --- a/tests/test_room_routes.py +++ b/tests/test_room_routes.py @@ -10,7 +10,6 @@ def test_list(client, room, room2, user, user2, admin, mod, global_mod, global_admin): - room2.default_write = False room2.default_upload = False @@ -652,7 +651,7 @@ def test_fetch_since(client, room, user, no_rate_limit): 'posted', 'reactions', } - assert post['session_id'] == user.session_id + assert post['session_id'] == user.using_id assert post['seqno'] == j assert utils.decode_base64(post['data']) == f"fake data {j}".encode() assert utils.decode_base64(post['signature']) == pad64(f"fake sig {j}") @@ -750,17 +749,13 @@ def deleted_entry(id, seqno): *(deleted_entry(i, s) for i, s in ((2, 11), (4, 12), (5, 13), (8, 14), (9, 15))), ] assert get_and_clean_since(10) == [ - *(deleted_entry(i, s) for i, s in ((2, 11), (4, 12), (5, 13), (8, 14), (9, 15))), + *(deleted_entry(i, s) for i, s in ((2, 11), (4, 12), (5, 13), (8, 14), (9, 15))) ] assert get_and_clean_since(11) == [ - *(deleted_entry(i, s) for i, s in ((4, 12), (5, 13), (8, 14), (9, 15))), - ] - assert get_and_clean_since(13) == [ - *(deleted_entry(i, s) for i, s in ((8, 14), (9, 15))), - ] - assert get_and_clean_since(14) == [ - *(deleted_entry(i, s) for i, s in ((9, 15),)), + *(deleted_entry(i, s) for i, s in ((4, 12), (5, 13), (8, 14), (9, 15))) ] + assert get_and_clean_since(13) == [*(deleted_entry(i, s) for i, s in ((8, 14), (9, 15)))] + assert get_and_clean_since(14) == [*(deleted_entry(i, s) for i, s in ((9, 15),))] assert get_and_clean_since(15) == [] @@ -934,7 +929,6 @@ def room_json(): def test_posting(client, room, user, user2, mod, global_mod): - url_post = "/room/test-room/message" d, s = (utils.encode_base64(x) for x in (b"post 1", pad64("sig 1"))) r = sogs_post(client, url_post, {"data": d, "signature": s}, user) @@ -944,7 +938,7 @@ def test_posting(client, room, user, user2, mod, global_mod): assert filter_timestamps(p1) == { 'id': 1, 'seqno': 1, - 'session_id': user.session_id, + 'session_id': user.using_id, 'data': d, 'signature': s, 'reactions': {}, @@ -957,7 +951,6 @@ def test_posting(client, room, user, user2, mod, global_mod): def test_whisper_to(client, room, user, user2, mod, global_mod): - url_post = "/room/test-room/message" d, s = (utils.encode_base64(x) for x in (b"whisper 1", pad64("sig 1"))) p = {"data": d, "signature": s, "whisper_to": user2.session_id} @@ -972,7 +965,7 @@ def test_whisper_to(client, room, user, user2, mod, global_mod): assert filter_timestamps(msg) == { 'id': 1, 'seqno': 1, - 'session_id': mod.session_id, + 'session_id': mod.using_id, 'data': d, 'signature': s, 'whisper': True, @@ -1005,7 +998,6 @@ def test_whisper_to(client, room, user, user2, mod, global_mod): def test_whisper_mods(client, room, user, user2, mod, global_mod, admin): - url_post = "/room/test-room/message" d, s = (utils.encode_base64(x) for x in (b"whisper 1", pad64("sig 1"))) p = {"data": d, "signature": s, "whisper_mods": True} @@ -1020,7 +1012,7 @@ def test_whisper_mods(client, room, user, user2, mod, global_mod, admin): assert filter_timestamps(msg) == { 'id': 1, 'seqno': 1, - 'session_id': mod.session_id, + 'session_id': mod.using_id, 'data': d, 'signature': s, 'whisper': True, @@ -1045,7 +1037,6 @@ def test_whisper_mods(client, room, user, user2, mod, global_mod, admin): def test_whisper_both(client, room, user, user2, mod, admin): - # A whisper aimed at both a user *and* all mods (e.g. a warning to a user) url_post = "/room/test-room/message" @@ -1057,7 +1048,7 @@ def test_whisper_both(client, room, user, user2, mod, admin): assert filter_timestamps(msg) == { 'id': 1, 'seqno': 1, - 'session_id': user.session_id, + 'session_id': user.using_id, 'data': d, 'signature': s, 'reactions': {}, @@ -1086,7 +1077,7 @@ def test_whisper_both(client, room, user, user2, mod, admin): { 'id': 1, 'seqno': 1, - 'session_id': user.session_id, + 'session_id': user.using_id, 'data': utils.encode_base64('offensive post!'.encode()), 'signature': utils.encode_base64(pad64('sig')), 'reactions': {}, @@ -1094,7 +1085,7 @@ def test_whisper_both(client, room, user, user2, mod, admin): { 'id': 2, 'seqno': 2, - 'session_id': mod.session_id, + 'session_id': mod.using_id, 'data': utils.encode_base64("I'm going to scare this guy".encode()), 'signature': utils.encode_base64(pad64('sig2')), 'whisper': True, @@ -1104,7 +1095,7 @@ def test_whisper_both(client, room, user, user2, mod, admin): { 'id': 3, 'seqno': 3, - 'session_id': mod.session_id, + 'session_id': mod.using_id, 'data': utils.encode_base64("WTF, do you want a ban?".encode()), 'signature': utils.encode_base64(pad64('sig3')), 'whisper': True, @@ -1115,7 +1106,7 @@ def test_whisper_both(client, room, user, user2, mod, admin): { 'id': 4, 'seqno': 4, - 'session_id': user.session_id, + 'session_id': user.using_id, 'data': utils.encode_base64("No please I'm sorry!!!".encode()), 'signature': utils.encode_base64(pad64('sig4')), 'reactions': {}, @@ -1138,7 +1129,6 @@ def test_whisper_both(client, room, user, user2, mod, admin): def test_edits(client, room, user, user2, mod, global_admin): - url_post = "/room/test-room/message" d, s = (utils.encode_base64(x) for x in (b"post 1", pad64("sig 1"))) r = sogs_post(client, url_post, {"data": d, "signature": s}, user) @@ -1148,7 +1138,7 @@ def test_edits(client, room, user, user2, mod, global_admin): assert filter_timestamps(p1) == { 'id': 1, 'seqno': 1, - 'session_id': user.session_id, + 'session_id': user.using_id, 'data': d, 'signature': s, 'reactions': {}, @@ -1193,7 +1183,7 @@ def test_edits(client, room, user, user2, mod, global_admin): assert filter_timestamps(p2) == { 'id': 2, 'seqno': 3, - 'session_id': user2.session_id, + 'session_id': user2.using_id, 'data': d, 'signature': s, 'reactions': {}, @@ -1401,7 +1391,6 @@ def test_set_room_perms(client, room, user, mod): def test_set_room_perm_futures(client, room, user, mod): - r = sogs_post( client, '/sequence', @@ -1499,7 +1488,7 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): r = client.get( f'/room/{room.token}', headers=x_sogs( - user.ed_key, crypto.server_pubkey, 'GET', f'/room/{room.token}', blinded=True + user.ed_key, crypto.server_pubkey, 'GET', f'/room/{room.token}', blinded15=True ), ) assert r.status_code == 200 @@ -1531,7 +1520,7 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): r = client.post( '/sequence', headers=x_sogs( - mod.ed_key, crypto.server_pubkey, 'POST', '/sequence', body, blinded=True + mod.ed_key, crypto.server_pubkey, 'POST', '/sequence', body, blinded15=True ), content_type='application/json', data=body, @@ -1570,16 +1559,15 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): crypto.server_pubkey, 'GET', f'/room/{room.token}/permissions', - blinded=True, + blinded15=True, ), ) assert r.status_code == 200 assert r.json == { - # user has a known blinded id so should have been inserted blinded: - user.blinded_id: {'read': True, 'write': False}, - # user2 doesn't, so would be set up unblinded: - user2.session_id: {'upload': False}, - mod.blinded_id: {'moderator': True}, + # all users are 25-blinded in the database now + user.blinded25_id: {'read': True, 'write': False}, + user2.blinded25_id: {'upload': False}, + mod.blinded25_id: {'moderator': True}, } r = client.get( @@ -1589,13 +1577,13 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): crypto.server_pubkey, 'GET', f'/room/{room.token}/futurePermissions', - blinded=True, + blinded15=True, ), ) assert r.status_code == 200 assert filter_timestamps(r.json) == [ - {'session_id': user.blinded_id, 'write': True}, - {'session_id': user2.session_id, 'upload': True}, + {'session_id': user.blinded25_id, 'write': True}, + {'session_id': user2.blinded25_id, 'upload': True}, ] assert r.json[0]['at'] == from_now.seconds(0.001) assert r.json[1]['at'] == from_now.seconds(0.002) @@ -1605,7 +1593,7 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): r = client.get( f'/room/{room.token}', headers=x_sogs( - user2.ed_key, crypto.server_pubkey, 'GET', f'/room/{room.token}', blinded=True + user2.ed_key, crypto.server_pubkey, 'GET', f'/room/{room.token}', blinded15=True ), ) assert r.status_code == 200 @@ -1617,14 +1605,14 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): crypto.server_pubkey, 'GET', f'/room/{room.token}/permissions', - blinded=True, + blinded15=True, ), ) assert r.status_code == 200 assert r.json == { - user.blinded_id: {'read': True, 'write': False}, - user2.blinded_id: {'upload': False}, - mod.blinded_id: {'moderator': True}, + user.blinded25_id: {'read': True, 'write': False}, + user2.blinded25_id: {'upload': False}, + mod.blinded25_id: {'moderator': True}, } r = client.get( @@ -1634,13 +1622,13 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): crypto.server_pubkey, 'GET', f'/room/{room.token}/futurePermissions', - blinded=True, + blinded15=True, ), ) assert r.status_code == 200 assert filter_timestamps(r.json) == [ - {'session_id': user.blinded_id, 'write': True}, - {'session_id': user2.blinded_id, 'upload': True}, + {'session_id': user.blinded25_id, 'write': True}, + {'session_id': user2.blinded25_id, 'upload': True}, ] assert r.json[0]['at'] == from_now.seconds(0.001) assert r.json[1]['at'] == from_now.seconds(0.002) @@ -1653,19 +1641,19 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): crypto.server_pubkey, 'GET', f'/room/{room.token}/permissions/{user.session_id}', - blinded=True, + blinded15=True, ), ) assert r.status_code == 200 assert r.json == {'read': True, 'write': False} r2 = client.get( - f'/room/{room.token}/permissions/{user.blinded_id}', + f'/room/{room.token}/permissions/{user.blinded15_id}', headers=x_sogs( mod.ed_key, crypto.server_pubkey, 'GET', - f'/room/{room.token}/permissions/{user.blinded_id}', - blinded=True, + f'/room/{room.token}/permissions/{user.blinded15_id}', + blinded15=True, ), ) assert r2.status_code == 200 @@ -1678,20 +1666,20 @@ def test_set_room_perms_blinding(client, db, room, user, user2, mod): crypto.server_pubkey, 'GET', f'/room/{room.token}/futurePermissions/{user2.session_id}', - blinded=True, + blinded15=True, ), ) assert r.status_code == 200 assert filter_timestamps(r.json) == [{'upload': True}] assert r.json[0]['at'] == from_now.seconds(0.002) r2 = client.get( - f'/room/{room.token}/futurePermissions/{user2.blinded_id}', + f'/room/{room.token}/futurePermissions/{user2.blinded15_id}', headers=x_sogs( mod.ed_key, crypto.server_pubkey, 'GET', - f'/room/{room.token}/futurePermissions/{user2.blinded_id}', - blinded=True, + f'/room/{room.token}/futurePermissions/{user2.blinded15_id}', + blinded15=True, ), ) assert r2.status_code == 200 diff --git a/tests/test_rooms.py b/tests/test_rooms.py index 59b4469e..0f21311c 100644 --- a/tests/test_rooms.py +++ b/tests/test_rooms.py @@ -9,7 +9,6 @@ def test_create(room, room2): - r3 = Room.create('Test_Room-3', name='Test room 3', description='Test suite testing room3') rooms = get_rooms() @@ -36,7 +35,6 @@ def test_create(room, room2): def test_token_insensitive(room): - r = Room.create('Test_Ro-om', name='TR2', description='Test suite testing room2') r_a = Room(token='Test_Ro-om') @@ -92,7 +90,6 @@ def test_info(room): def test_updates(room): - assert room.message_sequence == 0 and room.info_updates == 0 and room.name == 'Test room' room.name = 'Test Room' @@ -118,7 +115,6 @@ def test_updates(room): def test_permissions(room, user, user2, mod, admin, global_mod, global_admin): - # Public permissions: assert not room.check_permission(admin=True) assert not room.check_permission(moderator=True) @@ -386,7 +382,6 @@ def test_bans(room, user, user2, mod, admin, global_mod, global_admin): def test_mods(room, user, user2, mod, admin, global_mod, global_admin): - room.set_moderator(user, added_by=admin) assert room.check_moderator(user) assert not room.check_admin(user) @@ -458,7 +453,6 @@ def test_mods(room, user, user2, mod, admin, global_mod, global_admin): def test_upload(room, user): - import os file = File(id=room.upload_file(content=b'abc', uploader=user, filename="abc.txt", lifetime=30)) @@ -489,7 +483,6 @@ def test_upload(room, user): def test_upload_expiry(room, user): - import os file = File(id=room.upload_file(content=b'abc', uploader=user, filename="abc.txt", lifetime=-1)) @@ -512,7 +505,6 @@ def test_upload_expiry(room, user): def test_image(room, user): - assert room.image is None fid = room.upload_file(content=b'abc', uploader=user, filename="abc.txt") diff --git a/tests/test_routes_general.py b/tests/test_routes_general.py index 9744b494..169d215c 100644 --- a/tests/test_routes_general.py +++ b/tests/test_routes_general.py @@ -134,7 +134,6 @@ def batch_test_endpoint4(): def test_batch(client): - d1, b1_exp = batch_data() b1 = client.post("/batch", json=d1) assert b1.json == b1_exp diff --git a/tests/test_user_routes.py b/tests/test_user_routes.py index 9fe54063..ea2fcb43 100644 --- a/tests/test_user_routes.py +++ b/tests/test_user_routes.py @@ -5,7 +5,6 @@ def test_global_mods(client, room, room2, user, user2, mod, admin, global_admin, global_mod): - assert not room2.check_moderator(user) assert not room2.check_moderator(user2) @@ -167,7 +166,6 @@ def test_global_mods(client, room, room2, user, user2, mod, admin, global_admin, def test_room_mods(client, room, room2, user, user2, mod, admin, global_admin, global_mod): - # Track expected info_updates values; the initial values are because creating the mod/admin/etc. # fixtures imported here perform db modifications that trigger updates (2 global mods + 2 mods # of `room`): diff --git a/tests/user.py b/tests/user.py index 8a794eaf..ac3bb6a1 100644 --- a/tests/user.py +++ b/tests/user.py @@ -2,19 +2,32 @@ from nacl.signing import SigningKey import nacl.bindings as sodium import sogs.crypto +from sogs.hashing import blake2b + +from session_util import blinding class User(sogs.model.user.User): - def __init__(self, blinded=False): + def __init__(self, blinded15=False, blinded25=False): + self.is_blinded15 = blinded15 + self.is_blinded25 = blinded25 + self.ed_key = SigningKey.generate() self.a = self.ed_key.to_curve25519_private_key().encode() - self.ka = sodium.crypto_core_ed25519_scalar_mul(sogs.crypto.blinding_factor, self.a) - self.kA = sodium.crypto_scalarmult_ed25519_base_noclamp(self.ka) - self.blinded_id = '15' + self.kA.hex() - if blinded: - session_id = self.blinded_id + self.ka15 = sodium.crypto_core_ed25519_scalar_mul(sogs.crypto.blinding15_factor, self.a) + self.kA15 = sodium.crypto_scalarmult_ed25519_base_noclamp(self.ka15) + pub25, sec25 = blinding.blind25_key_pair( + self.ed_key.encode(), sogs.crypto.server_pubkey_bytes + ) + self.unblinded_id = '05' + self.ed_key.to_curve25519_private_key().public_key.encode().hex() + self.blinded15_id = '15' + self.kA15.hex() + self.blinded25_id = '25' + pub25.hex() + if blinded25: + session_id = self.blinded25_id + elif blinded15: + session_id = self.blinded15_id else: - session_id = '05' + self.ed_key.to_curve25519_private_key().public_key.encode().hex() + session_id = self.unblinded_id super().__init__(session_id=session_id, touch=True)