From f06ae857c3f534c73c6af60f4e9d6904a1360c87 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Tue, 23 Aug 2022 22:55:08 +0300 Subject: [PATCH 01/10] Update changelog --- CHANGELOG.md | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e59f9b8c..6e68bfcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # v0.4.0 (unreleased) -Target signald version: [v0.21.0](https://gitlab.com/signald/signald/-/releases/0.21.0) +Target signald version: [v0.21.1](https://gitlab.com/signald/signald/-/releases/0.21.1) **N.B.** This release requires a homeserver with Matrix v1.1 support, which bumps up the minimum homeserver versions to Synapse 1.54 and Dendrite 0.8.7. @@ -15,6 +15,17 @@ Minimum Conduit version remains at 0.4.0. (thanks to [@maltee1] in [#250]). * Added Matrix -> Signal power level change bridging (thanks to [@maltee1] in [#260] and [#263]). +* Added join rule bridging in both directions (thanks to [@maltee1] in [#268]). +* Added Matrix -> Signal bridging of location messages + (thanks to [@maltee1] in [#287]). + * Since Signal doesn't have actual location messages, they're just bridged as + map links. The link template is configurable. +* Added command to link devices when the bridge is the primary device + (thanks to [@Craeckie] in [#221]). +* Added command to bridge existing Matrix rooms to existing Signal groups + (thanks to [@MaximilianGaedig] in [#288]). +* Added config option to auto-enable relay mode when a specific user is invited + (thanks to [@maltee1] in [#293]). * Added options to make encryption more secure. * The `encryption` -> `verification_levels` config options can be used to make the bridge require encrypted messages to come from cross-signed @@ -36,24 +47,34 @@ Minimum Conduit version remains at 0.4.0. (thanks to [@maltee1] in [#265]). * Syncing chat members will no longer be interrupted if one of the member profiles is unavailable (thanks to [@maltee1] in [#270]). -* Member moderation actions from Signal are now bridged to Matrix with the - correct ghost user if possible instead of always using the bridge bot - (thanks to [@maltee1] in [#273]). +* Group metadata changes are now bridged based on the event itself rather than + resyncing the whole group, which means changes will use the correct ghost + user instead of always using the bridge bot (thanks to [@maltee1] in [#283]). * Added proper captcha error handling when registering (thanks to [@maltee1] in [#280]). +* Added user's phone number as topic in private chat portals + (thanks to [@maltee1] in [#282]). ### Fixed * Call start notices work again +[@Craeckie]: https://github.com/Craeckie +[@MaximilianGaedig]: https://github.com/MaximilianGaedig +[#221]: https://github.com/mautrix/signal/pull/221 [#246]: https://github.com/mautrix/signal/pull/246 [#250]: https://github.com/mautrix/signal/pull/250 [#257]: https://github.com/mautrix/signal/pull/257 [#260]: https://github.com/mautrix/signal/pull/260 [#263]: https://github.com/mautrix/signal/pull/263 [#265]: https://github.com/mautrix/signal/pull/265 +[#268]: https://github.com/mautrix/signal/pull/268 [#270]: https://github.com/mautrix/signal/pull/270 -[#273]: https://github.com/mautrix/signal/pull/273 [#280]: https://github.com/mautrix/signal/pull/280 +[#282]: https://github.com/mautrix/signal/pull/282 +[#283]: https://github.com/mautrix/signal/pull/283 +[#287]: https://github.com/mautrix/signal/pull/287 +[#288]: https://github.com/mautrix/signal/pull/288 +[#293]: https://github.com/mautrix/signal/pull/293 # v0.3.0 (2022-04-20) From 26cc754957c9975d241da7dcb6af4dd121ebe2ea Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 28 Aug 2022 13:00:01 +0300 Subject: [PATCH 02/10] Don't throw error when unsubscribing from accounts that aren't subscribed Fixes #201 --- mausignald/signald.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mausignald/signald.py b/mausignald/signald.py index a34f2489..a788bc4a 100644 --- a/mausignald/signald.py +++ b/mausignald/signald.py @@ -133,7 +133,7 @@ async def subscribe(self, username: str) -> bool: async def unsubscribe(self, username: str) -> bool: try: await self.request_v1("unsubscribe", account=username) - self._subscriptions.remove(username) + self._subscriptions.discard(username) return True except RPCError as e: self.log.debug("Failed to unsubscribe from %s: %s", username, e) From 9211af2444902e8118da1fae936367e6e57cda48 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 28 Aug 2022 13:35:41 +0300 Subject: [PATCH 03/10] Add login alias for link. Fixes #114 --- mautrix_signal/commands/auth.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mautrix_signal/commands/auth.py b/mautrix_signal/commands/auth.py index b91a36e6..c8fedaa5 100644 --- a/mautrix_signal/commands/auth.py +++ b/mautrix_signal/commands/auth.py @@ -97,6 +97,7 @@ async def connect_existing(evt: CommandEvent) -> EventID: help_section=SECTION_AUTH, help_text="Link the bridge as a secondary device", help_args="[device name]", + aliases=["login"], ) async def link(evt: CommandEvent) -> None: if qrcode is None: From c901201de1cda298fd167f1caa4ab2100497c0de Mon Sep 17 00:00:00 2001 From: Sumner Evans Date: Sun, 4 Sep 2022 08:04:46 -0600 Subject: [PATCH 04/10] call notifications: use portal._send_message to encrypt properly Signed-off-by: Sumner Evans --- mautrix_signal/signal.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mautrix_signal/signal.py b/mautrix_signal/signal.py index 5d3c9cc6..bd59cd50 100644 --- a/mautrix_signal/signal.py +++ b/mautrix_signal/signal.py @@ -34,7 +34,7 @@ TypingMessage, WebsocketConnectionStateChangeEvent, ) -from mautrix.types import EventID, MessageType, TextMessageEventContent +from mautrix.types import EventID, Format, MessageType, TextMessageEventContent from mautrix.util.logging import TraceLogger from . import portal as po, puppet as pu, user as u @@ -277,7 +277,12 @@ async def handle_call_message(user: u.User, sender: pu.Puppet, msg: IncomingMess portal.log.debug(f"Unhandled call message. Likely an ICE message. {msg.call_message}") return - await sender.intent_for(portal).send_text(portal.mxid, html=msg_html, msgtype=msg_type) + await portal._send_message( + intent=sender.intent_for(portal), + content=TextMessageEventContent( + format=Format.HTML, formatted_body=msg_html, msgtype=msg_type + ), + ) @staticmethod async def handle_own_receipts(sender: pu.Puppet, receipts: list[OwnReadReceipt]) -> None: From 5eeeeaf4aa8235fda4db9f20f80bc7b9f9e23927 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Wed, 14 Sep 2022 21:24:49 +0300 Subject: [PATCH 05/10] Update mautrix-python --- mautrix_signal/config.py | 2 -- mautrix_signal/example-config.yaml | 9 +++++++-- requirements.txt | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mautrix_signal/config.py b/mautrix_signal/config.py index 2307b752..f8ae5493 100644 --- a/mautrix_signal/config.py +++ b/mautrix_signal/config.py @@ -43,8 +43,6 @@ def do_update(self, helper: ConfigUpdateHelper) -> None: super().do_update(helper) copy, copy_dict, base = helper - copy("homeserver.asmux") - copy("signal.socket_path") copy("signal.outgoing_attachment_dir") copy("signal.avatar_dir") diff --git a/mautrix_signal/example-config.yaml b/mautrix_signal/example-config.yaml index 6f7071f8..9e7b64a7 100644 --- a/mautrix_signal/example-config.yaml +++ b/mautrix_signal/example-config.yaml @@ -7,7 +7,9 @@ homeserver: # Whether or not to verify the SSL certificate of the homeserver. # Only applies if address starts with https:// verify_ssl: true - asmux: false + # What software is the homeserver running? + # Standard Matrix homeservers like Synapse, Dendrite and Conduit should just use "standard" here. + software: standard # Number of retries for all HTTP requests if the homeserver isn't reachable. http_retry_count: 4 # The URL to push real-time bridge status to. @@ -48,8 +50,9 @@ appservice: # https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool # https://docs.python.org/3/library/sqlite3.html#sqlite3.connect # For sqlite, min_size is used as the connection thread pool size and max_size is ignored. + # Additionally, SQLite supports init_commands as an array of SQL queries to run on connect (e.g. to set PRAGMAs). database_opts: - min_size: 5 + min_size: 1 max_size: 10 # The unique ID of this appservice. @@ -170,6 +173,8 @@ bridge: # Default to encryption, force-enable encryption in all portals the bridge creates # This will cause the bridge bot to be in private chats for the encryption to work properly. default: false + # Whether to use MSC2409/MSC3202 instead of /sync long polling for receiving encryption-related data. + appservice: false # Require encryption, drop any unencrypted messages. require: false # Enable key sharing? If enabled, key requests for rooms where users are in will be fulfilled. diff --git a/requirements.txt b/requirements.txt index b56b149a..f8b2d310 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,5 @@ commonmark>=0.8,<0.10 aiohttp>=3,<4 yarl>=1,<2 attrs>=19.1 -mautrix>=0.17.8,<0.18 +mautrix>=0.18.0,<0.19 asyncpg>=0.20,<0.27 From 9da54dfcda55ebf1e6dd554db886cead782a46eb Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Sep 2022 16:56:26 +0300 Subject: [PATCH 06/10] Handle ScanTimeoutError properly --- mautrix_signal/commands/auth.py | 3 ++- mautrix_signal/web/provisioning_api.py | 7 +------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/mautrix_signal/commands/auth.py b/mautrix_signal/commands/auth.py index c8fedaa5..501f71af 100644 --- a/mautrix_signal/commands/auth.py +++ b/mautrix_signal/commands/auth.py @@ -19,6 +19,7 @@ from mausignald.errors import ( AuthorizationFailedError, CaptchaRequiredError, + ScanTimeoutError, TimeoutException, UnexpectedResponse, ) @@ -119,7 +120,7 @@ async def link(evt: CommandEvent) -> None: account = await evt.bridge.signal.finish_link( session_id=sess.session_id, overwrite=True, device_name=device_name ) - except TimeoutException: + except (TimeoutException, ScanTimeoutError): await evt.reply("Linking timed out, please try again.") except Exception: evt.log.exception("Fatal error while waiting for linking to finish") diff --git a/mautrix_signal/web/provisioning_api.py b/mautrix_signal/web/provisioning_api.py index 0558c352..7d525831 100644 --- a/mautrix_signal/web/provisioning_api.py +++ b/mautrix_signal/web/provisioning_api.py @@ -201,15 +201,10 @@ async def _try_shielded_link( f"Client cancelled link wait request ({session_id}) before it finished" ) raise - except TimeoutException: + except (TimeoutException, ScanTimeoutError): raise web.HTTPBadRequest( text='{"error": "Signal linking timed out"}', headers=self._headers ) - except ScanTimeoutError: - raise web.HTTPBadRequest( - text='{"error": "Signald websocket disconnected before linking finished"}', - headers=self._headers, - ) except InternalError: raise web.HTTPInternalServerError( text='{"error": "Fatal error in Signal linking"}', headers=self._headers From 8d379b91efb738d191b4124d3351b1c0c495f485 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Sep 2022 17:24:55 +0300 Subject: [PATCH 07/10] Move config env overrides to mautrix-python --- mautrix_signal/config.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mautrix_signal/config.py b/mautrix_signal/config.py index f8ae5493..8bbaeba5 100644 --- a/mautrix_signal/config.py +++ b/mautrix_signal/config.py @@ -25,12 +25,6 @@ class Config(BaseBridgeConfig): - def __getitem__(self, key: str) -> Any: - try: - return os.environ[f"MAUTRIX_SIGNAL_{key.replace('.', '_').upper()}"] - except KeyError: - return super().__getitem__(key) - @property def forbidden_defaults(self) -> List[ForbiddenDefault]: return [ From fcffb15c506f5b811ffc896d3cd468fdf4f7b4c2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 15 Sep 2022 21:55:01 +0300 Subject: [PATCH 08/10] Update mautrix-python to fix encrypting when a single device is out of OTKs --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index f8b2d310..bf9d1e99 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,5 @@ commonmark>=0.8,<0.10 aiohttp>=3,<4 yarl>=1,<2 attrs>=19.1 -mautrix>=0.18.0,<0.19 +mautrix>=0.18.1,<0.19 asyncpg>=0.20,<0.27 From c934b447768096f0d301cb63a58ebd1a00a08ba0 Mon Sep 17 00:00:00 2001 From: Malte E <97891689+maltee1@users.noreply.github.com> Date: Sat, 17 Sep 2022 21:09:01 +0200 Subject: [PATCH 09/10] Set relaybot as relay on create (#295) --- mautrix_signal/commands/signal.py | 2 +- mautrix_signal/portal.py | 32 +++++++++++++++++++------------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/mautrix_signal/commands/signal.py b/mautrix_signal/commands/signal.py index 254ca19f..52db913b 100644 --- a/mautrix_signal/commands/signal.py +++ b/mautrix_signal/commands/signal.py @@ -567,7 +567,7 @@ async def get_initial_state( except KeyError: # Some state event probably has empty content pass - return title, about, levels, encrypted, avatar_url + return title, about, levels, encrypted, avatar_url, join_rule async def warn_missing_power(levels: PowerLevelStateEventContent, evt: CommandEvent) -> None: diff --git a/mautrix_signal/portal.py b/mautrix_signal/portal.py index 5ea3eb30..1908e8d0 100644 --- a/mautrix_signal/portal.py +++ b/mautrix_signal/portal.py @@ -863,18 +863,7 @@ async def handle_matrix_invite(self, invited_by: u.User, user: u.User | p.Puppet except RPCError as e: raise RejectMatrixInvite(str(e)) from e if user.mxid == self.config["bridge.relay.relaybot"] != "@relaybot:example.com": - if not self.config["bridge.relay.enabled"]: - await self.main_intent.send_notice( - self.mxid, "Relay mode is not enabled in this instance of the bridge." - ) - else: - await self.set_relay_user(user) - await self.main_intent.send_notice( - self.mxid, - "Messages from non-logged-in users in this room will now be bridged " - "through the relaybot's Signal account.", - ) - + await self._handle_relaybot_invited(user) power_levels = await self.main_intent.get_power_levels(self.mxid) invitee_pl = power_levels.get_user_level(user.mxid) if invitee_pl >= 50: @@ -890,6 +879,19 @@ async def handle_matrix_invite(self, invited_by: u.User, user: u.User | p.Puppet await self.signal.get_group(invited_by.username, self.chat_id) ) + async def _handle_relaybot_invited(self, user: u.User) -> None: + if not self.config["bridge.relay.enabled"]: + await self.main_intent.send_notice( + self.mxid, "Relay mode is not enabled in this instance of the bridge." + ) + else: + await self.set_relay_user(user) + await self.main_intent.send_notice( + self.mxid, + "Messages from non-logged-in users in this room will now be bridged " + "through the relaybot's Signal account.", + ) + async def handle_matrix_name(self, user: u.User, name: str) -> None: if self.name == name or self.is_direct or not name: return @@ -1756,10 +1758,14 @@ async def create_signal_group( self.mxid, (Membership.JOIN, Membership.INVITE) ) invitee_addresses = [] + relaybot_mxid = self.config["bridge.relay.relaybot"] + relaybot = None for mxid in user_mxids: mx_user = await u.User.get_by_mxid(mxid, create=False) if mx_user and mx_user.address and mx_user.username != source.username: invitee_addresses.append(mx_user.address) + if mxid == relaybot_mxid != "@relaybot:example.com": + relaybot = mx_user puppet = await p.Puppet.get_by_mxid(mxid, create=False) if puppet: invitee_addresses.append(puppet.address) @@ -1787,6 +1793,8 @@ async def create_signal_group( await self.handle_matrix_join_rules(source, join_rule) await self.update() await self.update_bridge_info() + if relaybot: + await self._handle_relaybot_invited(relaybot) async def bridge_signal_group( self, source: u.User, levels: PowerLevelStateEventContent From 90542f770fe4910df2df9f43734de4a777691860 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 17 Sep 2022 22:12:54 +0300 Subject: [PATCH 10/10] Bump version to 0.4.0 --- CHANGELOG.md | 2 +- mautrix_signal/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e68bfcb..13d007e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# v0.4.0 (unreleased) +# v0.4.0 (2022-09-17) Target signald version: [v0.21.1](https://gitlab.com/signald/signald/-/releases/0.21.1) diff --git a/mautrix_signal/__init__.py b/mautrix_signal/__init__.py index 2078eb8a..bebde31e 100644 --- a/mautrix_signal/__init__.py +++ b/mautrix_signal/__init__.py @@ -1,2 +1,2 @@ -__version__ = "0.3.0" +__version__ = "0.4.0" __author__ = "Tulir Asokan "