mirror of
https://mau.dev/maunium/synapse.git
synced 2024-11-16 23:11:34 +01:00
Add store for client end to end keys
This commit is contained in:
parent
65e69dec8b
commit
b5770f8947
3 changed files with 171 additions and 1 deletions
|
@ -37,6 +37,7 @@ from .rejections import RejectionsStore
|
||||||
from .state import StateStore
|
from .state import StateStore
|
||||||
from .signatures import SignatureStore
|
from .signatures import SignatureStore
|
||||||
from .filtering import FilteringStore
|
from .filtering import FilteringStore
|
||||||
|
from .end_to_end_keys import EndToEndKeyStore
|
||||||
|
|
||||||
|
|
||||||
import fnmatch
|
import fnmatch
|
||||||
|
@ -51,7 +52,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Remember to update this number every time a change is made to database
|
# Remember to update this number every time a change is made to database
|
||||||
# schema files, so the users will be informed on server restarts.
|
# schema files, so the users will be informed on server restarts.
|
||||||
SCHEMA_VERSION = 20
|
SCHEMA_VERSION = 21
|
||||||
|
|
||||||
dir_path = os.path.abspath(os.path.dirname(__file__))
|
dir_path = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
@ -74,6 +75,7 @@ class DataStore(RoomMemberStore, RoomStore,
|
||||||
PushRuleStore,
|
PushRuleStore,
|
||||||
ApplicationServiceTransactionStore,
|
ApplicationServiceTransactionStore,
|
||||||
EventsStore,
|
EventsStore,
|
||||||
|
EndToEndKeyStore,
|
||||||
):
|
):
|
||||||
|
|
||||||
def __init__(self, hs):
|
def __init__(self, hs):
|
||||||
|
|
133
synapse/storage/end_to_end_keys.py
Normal file
133
synapse/storage/end_to_end_keys.py
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2015 OpenMarket Ltd
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
from _base import SQLBaseStore
|
||||||
|
|
||||||
|
|
||||||
|
class EndToEndKeyStore(SQLBaseStore):
|
||||||
|
def set_e2e_device_keys(self, user_id, device_id, time_now, json_bytes):
|
||||||
|
return self._simple_upsert(
|
||||||
|
table="e2e_device_keys_json",
|
||||||
|
keyvalues={
|
||||||
|
"user_id": user_id,
|
||||||
|
"device_id": device_id,
|
||||||
|
},
|
||||||
|
values={
|
||||||
|
"ts_added_ms": time_now,
|
||||||
|
"key_json": json_bytes,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_e2e_device_keys(self, query_list):
|
||||||
|
"""Fetch a list of device keys.
|
||||||
|
Args:
|
||||||
|
query_list(list): List of pairs of user_ids and device_ids.
|
||||||
|
Returns:
|
||||||
|
Dict mapping from user-id to dict mapping from device_id to
|
||||||
|
key json byte strings.
|
||||||
|
"""
|
||||||
|
def _get_e2e_device_keys(txn):
|
||||||
|
result = {}
|
||||||
|
for user_id, device_id in query_list:
|
||||||
|
user_result = result.setdefault(user_id, {})
|
||||||
|
keyvalues = {"user_id": user_id}
|
||||||
|
if device_id:
|
||||||
|
keyvalues["device_id"] = device_id
|
||||||
|
rows = self._simple_select_list_txn(
|
||||||
|
txn, table="e2e_device_keys_json",
|
||||||
|
keyvalues=keyvalues,
|
||||||
|
retcols=["device_id", "key_json"]
|
||||||
|
)
|
||||||
|
for row in rows:
|
||||||
|
user_result[row["device_id"]] = row["key_json"]
|
||||||
|
return result
|
||||||
|
return self.runInteraction("get_e2e_device_keys", _get_e2e_device_keys)
|
||||||
|
|
||||||
|
def add_e2e_one_time_keys(self, user_id, device_id, time_now, valid_until,
|
||||||
|
key_list):
|
||||||
|
def _add_e2e_one_time_keys(txn):
|
||||||
|
for (algorithm, key_id, json_bytes) in key_list:
|
||||||
|
self._simple_upsert_txn(
|
||||||
|
txn, table="e2e_one_time_keys_json",
|
||||||
|
keyvalues={
|
||||||
|
"user_id": user_id,
|
||||||
|
"device_id": device_id,
|
||||||
|
"algorithm": algorithm,
|
||||||
|
"key_id": key_id,
|
||||||
|
},
|
||||||
|
values={
|
||||||
|
"ts_added_ms": time_now,
|
||||||
|
"valid_until_ms": valid_until,
|
||||||
|
"key_json": json_bytes,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return self.runInteraction(
|
||||||
|
"add_e2e_one_time_keys", _add_e2e_one_time_keys
|
||||||
|
)
|
||||||
|
|
||||||
|
def count_e2e_one_time_keys(self, user_id, device_id, time_now):
|
||||||
|
""" Count the number of one time keys the server has for a device
|
||||||
|
Returns:
|
||||||
|
Dict mapping from algorithm to number of keys for that algorithm.
|
||||||
|
"""
|
||||||
|
def _count_e2e_one_time_keys(txn):
|
||||||
|
sql = (
|
||||||
|
"DELETE FROM e2e_one_time_keys_json"
|
||||||
|
" WHERE user_id = ? AND device_id = ? AND valid_until_ms < ?"
|
||||||
|
)
|
||||||
|
txn.execute(sql, (user_id, device_id, time_now))
|
||||||
|
sql = (
|
||||||
|
"SELECT algorithm, COUNT(key_id) FROM e2e_one_time_keys_json"
|
||||||
|
" WHERE user_id = ? AND device_id = ?"
|
||||||
|
" GROUP BY algorithm"
|
||||||
|
)
|
||||||
|
txn.execute(sql, (user_id, device_id))
|
||||||
|
result = {}
|
||||||
|
for algorithm, key_count in txn.fetchall():
|
||||||
|
result[algorithm] = key_count
|
||||||
|
return result
|
||||||
|
return self.runInteraction(
|
||||||
|
"count_e2e_one_time_keys", _count_e2e_one_time_keys
|
||||||
|
)
|
||||||
|
|
||||||
|
def take_e2e_one_time_keys(self, query_list, time_now):
|
||||||
|
"""Take a list of one time keys out of the database"""
|
||||||
|
def _take_e2e_one_time_keys(txn):
|
||||||
|
sql = (
|
||||||
|
"SELECT key_id, key_json FROM e2e_one_time_keys_json"
|
||||||
|
" WHERE user_id = ? AND device_id = ? AND algorithm = ?"
|
||||||
|
" AND valid_until_ms > ?"
|
||||||
|
" LIMIT 1"
|
||||||
|
)
|
||||||
|
result = {}
|
||||||
|
delete = []
|
||||||
|
for user_id, device_id, algorithm in query_list:
|
||||||
|
user_result = result.setdefault(user_id, {})
|
||||||
|
device_result = user_result.setdefault(device_id, {})
|
||||||
|
txn.execute(sql, (user_id, device_id, algorithm, time_now))
|
||||||
|
for key_id, key_json in txn.fetchall():
|
||||||
|
device_result[algorithm + ":" + key_id] = key_json
|
||||||
|
delete.append((user_id, device_id, algorithm, key_id))
|
||||||
|
sql = (
|
||||||
|
"DELETE FROM e2e_one_time_keys_json"
|
||||||
|
" WHERE user_id = ? AND device_id = ? AND algorithm = ?"
|
||||||
|
" AND key_id = ?"
|
||||||
|
)
|
||||||
|
for user_id, device_id, algorithm, key_id in delete:
|
||||||
|
txn.execute(sql, (user_id, device_id, algorithm, key_id))
|
||||||
|
return result
|
||||||
|
return self.runInteraction(
|
||||||
|
"take_e2e_one_time_keys", _take_e2e_one_time_keys
|
||||||
|
)
|
35
synapse/storage/schema/delta/21/end_to_end_keys.sql
Normal file
35
synapse/storage/schema/delta/21/end_to_end_keys.sql
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* Copyright 2015 OpenMarket Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS e2e_device_keys_json (
|
||||||
|
user_id TEXT NOT NULL, -- The user these keys are for.
|
||||||
|
device_id TEXT NOT NULL, -- Which of the user's devices these keys are for.
|
||||||
|
ts_added_ms BIGINT NOT NULL, -- When the keys were uploaded.
|
||||||
|
key_json TEXT NOT NULL, -- The keys for the device as a JSON blob.
|
||||||
|
CONSTRAINT uniqueness UNIQUE (user_id, device_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS e2e_one_time_keys_json (
|
||||||
|
user_id TEXT NOT NULL, -- The user this one-time key is for.
|
||||||
|
device_id TEXT NOT NULL, -- The device this one-time key is for.
|
||||||
|
algorithm TEXT NOT NULL, -- Which algorithm this one-time key is for.
|
||||||
|
key_id TEXT NOT NULL, -- An id for suppressing duplicate uploads.
|
||||||
|
ts_added_ms BIGINT NOT NULL, -- When this key was uploaded.
|
||||||
|
valid_until_ms BIGINT NOT NULL, -- When this key is valid until.
|
||||||
|
key_json TEXT NOT NULL, -- The key as a JSON blob.
|
||||||
|
CONSTRAINT uniqueness UNIQUE (user_id, device_id, algorithm, key_id)
|
||||||
|
);
|
Loading…
Reference in a new issue