def _get_e2e_cross_signing_signatures_for_devices_txn( self, txn: Cursor, device_query: Iterable[Tuple[str, str]] ) -> List[Tuple[str, str, str, str]]: """Get cross-signing signatures for a given list of devices Returns signatures made by the owners of the devices. Returns: a list of results; each entry in the list is a tuple of (user_id, key_id, target_device_id, signature). """ signature_query_clauses = [] signature_query_params = [] for (user_id, device_id) in device_query: signature_query_clauses.append( "target_user_id = ? AND target_device_id = ? AND user_id = ?") signature_query_params.extend([user_id, device_id, user_id]) signature_sql = """ SELECT user_id, key_id, target_device_id, signature FROM e2e_cross_signing_signatures WHERE %s """ % (" OR ".join("(" + q + ")" for q in signature_query_clauses)) txn.execute(signature_sql, signature_query_params) return txn.fetchall()
def run_create(cur: Cursor, database_engine: BaseDatabaseEngine, *args, **kwargs): logger.info("Creating ignored_users table") execute_statements_from_stream(cur, StringIO(_create_commands)) # We now upgrade existing data, if any. We don't do this in `run_upgrade` as # we a) want to run these before adding constraints and b) `run_upgrade` is # not run on empty databases. insert_sql = """ INSERT INTO ignored_users (ignorer_user_id, ignored_user_id) VALUES (?, ?) """ logger.info("Converting existing ignore lists") cur.execute( "SELECT user_id, content FROM account_data WHERE account_data_type = 'm.ignored_user_list'" ) for user_id, content_json in cur.fetchall(): content = db_to_json(content_json) # The content should be the form of a dictionary with a key # "ignored_users" pointing to a dictionary with keys of ignored users. # # { "ignored_users": "@someone:example.org": {} } ignored_users = content.get("ignored_users", {}) if isinstance(ignored_users, dict) and ignored_users: cur.execute_batch(insert_sql, [(user_id, u) for u in ignored_users]) # Add indexes after inserting data for efficiency. logger.info("Adding constraints to ignored_users table") execute_statements_from_stream(cur, StringIO(_constraints_commands))
def check_database_before_upgrade(cur: Cursor, database_engine: BaseDatabaseEngine, config: HomeServerConfig) -> None: """Called before upgrading an existing database to check that it is broadly sane compared with the configuration. """ logger.info("Checking database for consistency with configuration...") # if there are any users in the database, check that the username matches our # configured server name. cur.execute("SELECT name FROM users LIMIT 1") rows = cur.fetchall() if not rows: return user_domain = get_domain_from_id(rows[0][0]) if user_domain == config.server.server_name: return raise Exception( "Found users in database not native to %s!\n" "You cannot change a synapse server_name after it's been configured" % (config.server.server_name, ))
def _calculate_chain_cover_txn( self, txn: Cursor, last_room_id: str, last_depth: int, last_stream: int, batch_size: Optional[int], single_room: bool, ) -> _CalculateChainCover: """Calculate the chain cover for `batch_size` events, ordered by `(room_id, depth, stream)`. Args: txn, last_room_id, last_depth, last_stream: The `(room_id, depth, stream)` tuple to fetch results after. batch_size: The maximum number of events to process. If None then no limit. single_room: Whether to calculate the index for just the given room. """ # Get the next set of events in the room (that we haven't already # computed chain cover for). We do this in topological order. # We want to do a `(topological_ordering, stream_ordering) > (?,?)` # comparison, but that is not supported on older SQLite versions tuple_clause, tuple_args = make_tuple_comparison_clause([ ("events.room_id", last_room_id), ("topological_ordering", last_depth), ("stream_ordering", last_stream), ], ) extra_clause = "" if single_room: extra_clause = "AND events.room_id = ?" tuple_args.append(last_room_id) sql = """ SELECT event_id, state_events.type, state_events.state_key, topological_ordering, stream_ordering, events.room_id FROM events INNER JOIN state_events USING (event_id) LEFT JOIN event_auth_chains USING (event_id) LEFT JOIN event_auth_chain_to_calculate USING (event_id) WHERE event_auth_chains.event_id IS NULL AND event_auth_chain_to_calculate.event_id IS NULL AND %(tuple_cmp)s %(extra)s ORDER BY events.room_id, topological_ordering, stream_ordering %(limit)s """ % { "tuple_cmp": tuple_clause, "limit": "LIMIT ?" if batch_size is not None else "", "extra": extra_clause, } if batch_size is not None: tuple_args.append(batch_size) txn.execute(sql, tuple_args) rows = txn.fetchall() # Put the results in the necessary format for # `_add_chain_cover_index` event_to_room_id = {row[0]: row[5] for row in rows} event_to_types = {row[0]: (row[1], row[2]) for row in rows} # Calculate the new last position we've processed up to. new_last_depth: int = rows[-1][3] if rows else last_depth new_last_stream: int = rows[-1][4] if rows else last_stream new_last_room_id: str = rows[-1][5] if rows else "" # Map from room_id to last depth/stream_ordering processed for the room, # excluding the last room (which we're likely still processing). We also # need to include the room passed in if it's not included in the result # set (as we then know we've processed all events in said room). # # This is the set of rooms that we can now safely flip the # `has_auth_chain_index` bit for. finished_rooms = { row[5]: (row[3], row[4]) for row in rows if row[5] != new_last_room_id } if last_room_id not in finished_rooms and last_room_id != new_last_room_id: finished_rooms[last_room_id] = (last_depth, last_stream) count = len(rows) # We also need to fetch the auth events for them. auth_events = self.db_pool.simple_select_many_txn( txn, table="event_auth", column="event_id", iterable=event_to_room_id, keyvalues={}, retcols=("event_id", "auth_id"), ) event_to_auth_chain: Dict[str, List[str]] = {} for row in auth_events: event_to_auth_chain.setdefault(row["event_id"], []).append(row["auth_id"]) # Calculate and persist the chain cover index for this set of events. # # Annoyingly we need to gut wrench into the persit event store so that # we can reuse the function to calculate the chain cover for rooms. PersistEventsStore._add_chain_cover_index( txn, self.db_pool, self.event_chain_id_gen, event_to_room_id, event_to_types, event_to_auth_chain, ) return _CalculateChainCover( room_id=new_last_room_id, depth=new_last_depth, stream=new_last_stream, processed_count=count, finished_room_map=finished_rooms, )