Skip to content

Commit 5e3dbf5

Browse files
committed
Add API calls for SSSS
1 parent 799cb27 commit 5e3dbf5

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

mautrix/crypto/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from mautrix.util.logging import TraceLogger
3232

3333
from .. import client as cli, crypto
34+
from .ssss import Machine as SSSSMachine
3435

3536

3637
class SignedObject(TypedDict):
@@ -40,6 +41,7 @@ class SignedObject(TypedDict):
4041

4142
class BaseOlmMachine:
4243
client: cli.Client
44+
ssss: SSSSMachine
4345
log: TraceLogger
4446
crypto_store: crypto.CryptoStore
4547
state_store: crypto.StateStore

mautrix/crypto/machine.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from .encrypt_megolm import MegolmEncryptionMachine
3737
from .key_request import KeyRequestingMachine
3838
from .key_share import KeySharingMachine
39+
from .ssss import Machine as SSSSMachine
3940
from .store import CryptoStore, StateStore
4041
from .unwedge import OlmUnwedgingMachine
4142

@@ -58,6 +59,7 @@ class OlmMachine(
5859
log: TraceLogger
5960
crypto_store: CryptoStore
6061
state_store: StateStore
62+
ssss: SSSSMachine
6163

6264
account: Optional[OlmAccount]
6365

@@ -70,6 +72,7 @@ def __init__(
7072
) -> None:
7173
super().__init__()
7274
self.client = client
75+
self.ssss = SSSSMachine(client)
7376
self.log = log or logging.getLogger("mau.crypto")
7477
self.crypto_store = crypto_store
7578
self.state_store = state_store

mautrix/crypto/ssss/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from .key import Key, KeyMetadata, PassphraseMetadata
2+
from .machine import Machine
23
from .types import (
34
Algorithm,
45
EncryptedAccountDataEventContent,

mautrix/crypto/ssss/machine.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright (c) 2025 Tulir Asokan
2+
#
3+
# This Source Code Form is subject to the terms of the Mozilla Public
4+
# License, v. 2.0. If a copy of the MPL was not distributed with this
5+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
from mautrix import client as cli
7+
from mautrix.errors import MNotFound
8+
from mautrix.types import EventType, SecretStorageDefaultKeyEventContent
9+
10+
from .key import Key, KeyMetadata
11+
from .types import EncryptedAccountDataEventContent
12+
13+
14+
class Machine:
15+
client: cli.Client
16+
17+
def __init__(self, client: cli.Client) -> None:
18+
self.client = client
19+
20+
async def get_default_key_id(self) -> str | None:
21+
try:
22+
data = await self.client.get_account_data(EventType.SECRET_STORAGE_DEFAULT_KEY)
23+
return SecretStorageDefaultKeyEventContent.deserialize(data).key
24+
except (MNotFound, ValueError):
25+
return None
26+
27+
async def set_default_key_id(self, key_id: str) -> None:
28+
await self.client.set_account_data(
29+
EventType.SECRET_STORAGE_DEFAULT_KEY,
30+
SecretStorageDefaultKeyEventContent(key=key_id),
31+
)
32+
33+
async def get_key_data(self, key_id: str) -> KeyMetadata:
34+
data = await self.client.get_account_data(f"m.secret_storage.key.{key_id}")
35+
return KeyMetadata.deserialize(data)
36+
37+
async def set_key_data(self, key_id: str, data: KeyMetadata) -> None:
38+
await self.client.set_account_data(f"m.secret_storage.key.{key_id}", data)
39+
40+
async def get_default_key_data(self) -> tuple[str, KeyMetadata]:
41+
key_id = await self.get_default_key_id()
42+
if not key_id:
43+
raise ValueError("No default key ID set")
44+
return key_id, await self.get_key_data(key_id)
45+
46+
async def get_decrypted_account_data(self, event_type: EventType | str, key: Key) -> bytes:
47+
data = await self.client.get_account_data(event_type)
48+
parsed = EncryptedAccountDataEventContent.deserialize(data)
49+
return parsed.decrypt(event_type, key)
50+
51+
async def set_encrypted_account_data(
52+
self, event_type: EventType | str, data: bytes, *keys: Key
53+
) -> None:
54+
encrypted_data = {}
55+
for key in keys:
56+
encrypted_data[key.id] = key.encrypt(event_type, data)
57+
await self.client.set_account_data(
58+
event_type,
59+
EncryptedAccountDataEventContent(encrypted=encrypted_data),
60+
)
61+
62+
async def generate_and_upload_key(self, passphrase: str | None = None) -> Key:
63+
key = Key.generate(passphrase)
64+
await self.set_key_data(key.id, key.metadata)
65+
return key

0 commit comments

Comments
 (0)