Skip to content

Commit e5d12ec

Browse files
committed
Add option to log in to custom puppet with shared secret
1 parent c6b4029 commit e5d12ec

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

mautrix/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
__version__ = "0.4.0rc3"
1+
__version__ = "0.4.0rc4"
22
__author__ = "Tulir Asokan <[email protected]>"
33
__all__ = ["api", "appservice", "bridge", "client", "errors", "util", "types"]

mautrix/bridge/custom_puppet.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88
from itertools import chain
99
import asyncio
1010
import logging
11+
import hashlib
12+
import hmac
13+
import json
1114

1215
from aiohttp import ClientConnectionError
1316

1417
from mautrix.types import (UserID, FilterID, Filter, RoomEventFilter, RoomFilter, EventFilter,
1518
EventType, SyncToken, RoomID, Event, PresenceState)
1619
from mautrix.appservice import AppService, IntentAPI
1720
from mautrix.errors import IntentError, MatrixError, MatrixRequestError, MatrixInvalidToken
21+
from mautrix.api import Path
1822

1923
from .matrix import BaseMatrixHandler
2024

@@ -60,6 +64,8 @@ class CustomPuppetMixin(ABC):
6064

6165
sync_with_custom_puppets: bool = True
6266
only_handle_own_synced_events: bool = True
67+
login_shared_secret: Optional[bytes] = None
68+
login_device_name: Optional[str] = None
6369

6470
az: AppService
6571
loop: asyncio.AbstractEventLoop
@@ -96,6 +102,33 @@ def _fresh_intent(self) -> IntentAPI:
96102
return (self.az.intent.user(self.custom_mxid, self.access_token)
97103
if self.is_real_user else self.default_mxid_intent)
98104

105+
def can_auto_login(self, mxid: UserID) -> bool:
106+
if not self.login_shared_secret:
107+
return False
108+
_, server = self.az.intent.parse_user_id(mxid)
109+
if server != self.az.domain:
110+
return False
111+
return True
112+
113+
async def _login_with_shared_secret(self, mxid: UserID) -> Optional[str]:
114+
if not self.can_auto_login(mxid):
115+
return None
116+
password = hmac.new(self.login_shared_secret, mxid.encode("utf-8"),
117+
hashlib.sha512).hexdigest()
118+
url = self.az.intent.api.base_url + str(Path.login)
119+
resp = await self.az.http_session.post(url, data=json.dumps({
120+
"type": "m.login.password",
121+
"initial_device_display_name": self.login_device_name,
122+
"device_id": self.login_device_name,
123+
"identifier": {
124+
"type": "m.id.user",
125+
"user": mxid,
126+
},
127+
"password": password
128+
}), headers={"Content-Type": "application/json"})
129+
data = await resp.json()
130+
return data["access_token"]
131+
99132
async def switch_mxid(self, access_token: Optional[str], mxid: Optional[UserID]) -> None:
100133
"""
101134
Switch to a real Matrix user or away from one.
@@ -106,6 +139,11 @@ async def switch_mxid(self, access_token: Optional[str], mxid: Optional[UserID])
106139
mxid: The expected Matrix user ID of the custom account, or ``None`` when
107140
``access_token`` is None.
108141
"""
142+
if access_token == "auto":
143+
access_token = await self._login_with_shared_secret(mxid)
144+
if not access_token:
145+
raise ValueError("Failed to log in with shared secret")
146+
self.log.debug(f"Logged in for {mxid} using shared secret")
109147
prev_mxid = self.custom_mxid
110148
self.custom_mxid = mxid
111149
self.access_token = access_token

0 commit comments

Comments
 (0)