From 7eabcbf2ea3eda4948b5bc4c66d193b14a2901e3 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 23 Nov 2021 17:23:07 -0500
Subject: [PATCH 01/16] Working in relay mode

---
 mautrix/bridge/config.py |  4 +++-
 mautrix/bridge/portal.py | 27 ++++++++++++++++++++++++++-
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/mautrix/bridge/config.py b/mautrix/bridge/config.py
index b2581654..ede25bb2 100644
--- a/mautrix/bridge/config.py
+++ b/mautrix/bridge/config.py
@@ -50,7 +50,7 @@ def forbidden_defaults(self) -> List[ForbiddenDefault]:
         ] if self._check_tokens else [])
 
     def do_update(self, helper: ConfigUpdateHelper) -> None:
-        copy = helper.copy
+        copy, copy_dict = helper
 
         copy("homeserver.address")
         copy("homeserver.domain")
@@ -86,6 +86,8 @@ def do_update(self, helper: ConfigUpdateHelper) -> None:
         copy("bridge.management_room_text.welcome_unconnected")
         copy("bridge.management_room_text.additional_help")
         copy("bridge.management_room_multiple_messages")
+        copy("bridge.relay.enabled")
+        copy_dict("bridge.relay.message_formats")
 
         copy("manhole.enabled")
         copy("manhole.path")
diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index 0a2ad8de..faf83e28 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -3,7 +3,7 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-from typing import Optional, Dict, Any, List, TYPE_CHECKING
+from typing import Optional, Dict, Tuple, Any, List, TYPE_CHECKING
 from collections import defaultdict
 from abc import ABC, abstractmethod
 import asyncio
@@ -45,6 +45,31 @@ async def handle_matrix_message(self, sender: 'BaseUser', message: MessageEventC
                                     event_id: EventID) -> None:
         pass
 
+    @property
+    @abstractmethod
+    async def has_relay(self) -> bool:
+        pass
+
+    @abstractmethod
+    async def set_relay_user(self, user: Optional['BaseUser']) -> None:
+        pass
+
+    @abstractmethod
+    async def get_relay_user(self) -> Optional['BaseUser']:
+        pass
+
+    @abstractmethod
+    async def apply_msg_format(self, sender: 'BaseUser', content: MessageEventContent) -> None:
+        pass
+
+    @abstractmethod
+    async def get_relay_sender(self, sender: 'BaseUser', evt_identifier: str
+                                ) -> Tuple[Optional['BaseUser'], bool]:
+        pass
+
+    async def get_displayname(self, user: 'BaseUser') -> str:
+        return await self.main_intent.get_room_displayname(self.mxid, user.mxid) or user.mxid
+
     async def check_dm_encryption(self) -> Optional[bool]:
         try:
             evt = await self.main_intent.get_state_event(self.mxid, EventType.ROOM_ENCRYPTION)

From 0150c57dbcad9e2cde4f33b54d6cc417d9603071 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 23 Nov 2021 17:48:18 -0500
Subject: [PATCH 02/16] Fixed the import of BaseUser

---
 mautrix/bridge/portal.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index f059b7af..c0b2cd72 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -49,23 +49,23 @@ async def has_relay(self) -> bool:
         pass
 
     @abstractmethod
-    async def set_relay_user(self, user: Optional['BaseUser']) -> None:
+    async def set_relay_user(self, user: Optional[br.BaseUser]) -> None:
         pass
 
     @abstractmethod
-    async def get_relay_user(self) -> Optional['BaseUser']:
+    async def get_relay_user(self) -> Optional[br.BaseUser]:
         pass
 
     @abstractmethod
-    async def apply_msg_format(self, sender: 'BaseUser', content: MessageEventContent) -> None:
+    async def apply_msg_format(self, sender: br.BaseUser, content: MessageEventContent) -> None:
         pass
 
     @abstractmethod
-    async def get_relay_sender(self, sender: 'BaseUser', evt_identifier: str
-                                ) -> Tuple[Optional['BaseUser'], bool]:
+    async def get_relay_sender(self, sender: br.BaseUser, evt_identifier: str
+                                ) -> Tuple[Optional[br.BaseUser], bool]:
         pass
 
-    async def get_displayname(self, user: 'BaseUser') -> str:
+    async def get_displayname(self, user: br.BaseUser) -> str:
         return await self.main_intent.get_room_displayname(self.mxid, user.mxid) or user.mxid
 
     async def check_dm_encryption(self) -> Optional[bool]:

From fec24bc62fe48690411ecfdd7ba43dbe313e6582 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 23 Nov 2021 18:28:42 -0500
Subject: [PATCH 03/16] Added the relay.py file and the commands set-relay and
 unset-realy

---
 mautrix/bridge/commands/handler.py |  2 +-
 mautrix/bridge/commands/relay.py   | 32 ++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 1 deletion(-)
 create mode 100644 mautrix/bridge/commands/relay.py

diff --git a/mautrix/bridge/commands/handler.py b/mautrix/bridge/commands/handler.py
index b0e0a695..8152a2b4 100644
--- a/mautrix/bridge/commands/handler.py
+++ b/mautrix/bridge/commands/handler.py
@@ -27,7 +27,7 @@
 SECTION_GENERAL = HelpSection("General", 0, "")
 SECTION_AUTH = HelpSection("Authentication", 10, "")
 SECTION_ADMIN = HelpSection("Administration", 50, "")
-
+SECTION_CONNECTION = HelpSection("Connection management", 15, "")
 
 def ensure_trailing_newline(s: str) -> str:
     """Returns the passed string, but with a guaranteed trailing newline."""
diff --git a/mautrix/bridge/commands/relay.py b/mautrix/bridge/commands/relay.py
new file mode 100644
index 00000000..18dfbb66
--- /dev/null
+++ b/mautrix/bridge/commands/relay.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2020 Tulir Asokan
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+from mautrix.types import EventID
+from .handler import (command_handler, CommandEvent, SECTION_CONNECTION)
+
+@command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
+                 help_text="Relay messages in this room through your Instagram account.")
+async def set_relay(evt: CommandEvent) -> EventID:
+    if not evt.config["bridge.relay.enabled"]:
+        return await evt.reply("Relay mode is not enable in this instance of the bridge.")
+    elif not evt.is_portal:
+        return await evt.reply("This is not a portal room.")
+    await evt.portal.set_relay_user(evt.sender)
+    return await evt.reply("Messages from non-logged-in users in this room will now be bridged "
+                           "through your Instagram account.")
+
+@command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
+                 help_text="Stop relaying messages in this room.")
+async def unset_relay(evt: CommandEvent) -> EventID:
+    if not evt.config["bridge.relay.enabled"]:
+        return await evt.reply("Relay mode is not enable in this instance of the bridge.")
+    elif not evt.is_portal:
+        return await evt.reply("This is not a portal room.")
+    elif not evt.portal.has_relay:
+        return await evt.reply("This room does not have a relay user set.")
+    await evt.portal.set_relay_user(None)
+    return await evt.reply("Messages from non-logged-in users will no longer be bridged.")
\ No newline at end of file

From 61e0a2badf0a7d81725a7ed5544eece9e1a6dd91 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 30 Nov 2021 13:26:14 -0500
Subject: [PATCH 04/16] Working in relay mode

---
 mautrix/bridge/portal.py | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index c0b2cd72..75fd2987 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -33,6 +33,7 @@ class BasePortal(ABC):
     encrypted: bool
     is_direct: bool
     backfill_lock: SimpleLock
+    _relay_user: Optional['br.BaseUser']
 
     @abstractmethod
     async def save(self) -> None:
@@ -48,21 +49,23 @@ async def handle_matrix_message(self, sender: br.BaseUser, message: MessageEvent
     async def has_relay(self) -> bool:
         pass
 
+
+    @property
     @abstractmethod
-    async def set_relay_user(self, user: Optional[br.BaseUser]) -> None:
+    async def get_relay_user(self) -> Optional['br.BaseUser']:
         pass
 
     @abstractmethod
-    async def get_relay_user(self) -> Optional[br.BaseUser]:
+    async def set_relay_user(self, user: Optional['br.BaseUser']) -> None:
         pass
 
     @abstractmethod
-    async def apply_msg_format(self, sender: br.BaseUser, content: MessageEventContent) -> None:
+    async def get_relay_sender(self, sender: br.BaseUser, evt_identifier: str
+                                ) -> Tuple[Optional['br.BaseUser'], bool]:
         pass
 
     @abstractmethod
-    async def get_relay_sender(self, sender: br.BaseUser, evt_identifier: str
-                                ) -> Tuple[Optional[br.BaseUser], bool]:
+    async def apply_msg_format(self, sender: br.BaseUser, content: MessageEventContent) -> None:
         pass
 
     async def get_displayname(self, user: br.BaseUser) -> str:

From 5c1d801df395a06a3a0ca845698699329a617b80 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 30 Nov 2021 13:40:50 -0500
Subject: [PATCH 05/16] Working in relay mode

---
 mautrix/bridge/portal.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index c286c55e..c8336858 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -49,7 +49,6 @@ async def handle_matrix_message(self, sender: br.BaseUser, message: MessageEvent
     async def has_relay(self) -> bool:
         pass
 
-
     @property
     @abstractmethod
     async def get_relay_user(self) -> Optional['br.BaseUser']:

From 2b207ecf1f42ff14181f671d8a72be3765f2b813 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 30 Nov 2021 14:34:54 -0500
Subject: [PATCH 06/16] Remove word instagram

---
 mautrix/bridge/commands/relay.py | 8 ++++----
 mautrix/bridge/portal.py         | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/mautrix/bridge/commands/relay.py b/mautrix/bridge/commands/relay.py
index 18dfbb66..9f79d094 100644
--- a/mautrix/bridge/commands/relay.py
+++ b/mautrix/bridge/commands/relay.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2020 Tulir Asokan
+# Copyright (c) 2021 Tulir Asokan
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,7 +9,7 @@
 from .handler import (command_handler, CommandEvent, SECTION_CONNECTION)
 
 @command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
-                 help_text="Relay messages in this room through your Instagram account.")
+                 help_text="Relay messages in this room through your account.")
 async def set_relay(evt: CommandEvent) -> EventID:
     if not evt.config["bridge.relay.enabled"]:
         return await evt.reply("Relay mode is not enable in this instance of the bridge.")
@@ -17,7 +17,7 @@ async def set_relay(evt: CommandEvent) -> EventID:
         return await evt.reply("This is not a portal room.")
     await evt.portal.set_relay_user(evt.sender)
     return await evt.reply("Messages from non-logged-in users in this room will now be bridged "
-                           "through your Instagram account.")
+                           "through your account.")
 
 @command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
                  help_text="Stop relaying messages in this room.")
@@ -29,4 +29,4 @@ async def unset_relay(evt: CommandEvent) -> EventID:
     elif not evt.portal.has_relay:
         return await evt.reply("This room does not have a relay user set.")
     await evt.portal.set_relay_user(None)
-    return await evt.reply("Messages from non-logged-in users will no longer be bridged.")
\ No newline at end of file
+    return await evt.reply("Messages from non-logged-in users will no longer be bridged.")
diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index c8336858..3af17582 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -4,7 +4,7 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 from __future__ import annotations
-from typing import Optional, Dict, Any, List
+from typing import Optional, Dict, Any, List, Tuple
 from collections import defaultdict
 from abc import ABC, abstractmethod
 import asyncio

From 5fae371e09809d6aebb5ba96e5c7f57b76af2ef7 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 30 Nov 2021 15:17:05 -0500
Subject: [PATCH 07/16] Working in relay mode

---
 mautrix/bridge/commands/handler.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/mautrix/bridge/commands/handler.py b/mautrix/bridge/commands/handler.py
index 8152a2b4..a9d70df4 100644
--- a/mautrix/bridge/commands/handler.py
+++ b/mautrix/bridge/commands/handler.py
@@ -29,6 +29,7 @@
 SECTION_ADMIN = HelpSection("Administration", 50, "")
 SECTION_CONNECTION = HelpSection("Connection management", 15, "")
 
+
 def ensure_trailing_newline(s: str) -> str:
     """Returns the passed string, but with a guaranteed trailing newline."""
     return s + ("" if s[-1] == "\n" else "\n")

From cc7b9ee6f61a44be433467a2356f219a2d9d30d7 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Tue, 30 Nov 2021 15:22:14 -0500
Subject: [PATCH 08/16] Working in relay mode

---
 mautrix/bridge/portal.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index 3af17582..61071034 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -60,7 +60,7 @@ async def set_relay_user(self, user: Optional['br.BaseUser']) -> None:
 
     @abstractmethod
     async def get_relay_sender(self, sender: br.BaseUser, evt_identifier: str
-                                ) -> Tuple[Optional['br.BaseUser'], bool]:
+                               ) -> Tuple[Optional['br.BaseUser'], bool]:
         pass
 
     @abstractmethod

From d517d87944e42e523fc345995568c8d4c533d131 Mon Sep 17 00:00:00 2001
From: Alejo0290 <86024997+Alejo0290@users.noreply.github.com>
Date: Tue, 30 Nov 2021 15:28:12 -0500
Subject: [PATCH 09/16] Adding relay mode (#1)

* Working in relay mode

* Fixed the import of BaseUser

* Added the relay.py file and the commands set-relay and unset-realy

* Working in relay mode

* Working in relay mode

* Remove word instagram

* Working in relay mode

* Working in relay mode
---
 mautrix/bridge/commands/handler.py |  1 +
 mautrix/bridge/commands/relay.py   | 32 ++++++++++++++++++++++++++++++
 mautrix/bridge/config.py           |  4 +++-
 mautrix/bridge/portal.py           | 29 ++++++++++++++++++++++++++-
 4 files changed, 64 insertions(+), 2 deletions(-)
 create mode 100644 mautrix/bridge/commands/relay.py

diff --git a/mautrix/bridge/commands/handler.py b/mautrix/bridge/commands/handler.py
index b0e0a695..a9d70df4 100644
--- a/mautrix/bridge/commands/handler.py
+++ b/mautrix/bridge/commands/handler.py
@@ -27,6 +27,7 @@
 SECTION_GENERAL = HelpSection("General", 0, "")
 SECTION_AUTH = HelpSection("Authentication", 10, "")
 SECTION_ADMIN = HelpSection("Administration", 50, "")
+SECTION_CONNECTION = HelpSection("Connection management", 15, "")
 
 
 def ensure_trailing_newline(s: str) -> str:
diff --git a/mautrix/bridge/commands/relay.py b/mautrix/bridge/commands/relay.py
new file mode 100644
index 00000000..9f79d094
--- /dev/null
+++ b/mautrix/bridge/commands/relay.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2021 Tulir Asokan
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+from mautrix.types import EventID
+from .handler import (command_handler, CommandEvent, SECTION_CONNECTION)
+
+@command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
+                 help_text="Relay messages in this room through your account.")
+async def set_relay(evt: CommandEvent) -> EventID:
+    if not evt.config["bridge.relay.enabled"]:
+        return await evt.reply("Relay mode is not enable in this instance of the bridge.")
+    elif not evt.is_portal:
+        return await evt.reply("This is not a portal room.")
+    await evt.portal.set_relay_user(evt.sender)
+    return await evt.reply("Messages from non-logged-in users in this room will now be bridged "
+                           "through your account.")
+
+@command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
+                 help_text="Stop relaying messages in this room.")
+async def unset_relay(evt: CommandEvent) -> EventID:
+    if not evt.config["bridge.relay.enabled"]:
+        return await evt.reply("Relay mode is not enable in this instance of the bridge.")
+    elif not evt.is_portal:
+        return await evt.reply("This is not a portal room.")
+    elif not evt.portal.has_relay:
+        return await evt.reply("This room does not have a relay user set.")
+    await evt.portal.set_relay_user(None)
+    return await evt.reply("Messages from non-logged-in users will no longer be bridged.")
diff --git a/mautrix/bridge/config.py b/mautrix/bridge/config.py
index 14664460..e5b68bf0 100644
--- a/mautrix/bridge/config.py
+++ b/mautrix/bridge/config.py
@@ -49,7 +49,7 @@ def forbidden_defaults(self) -> List[ForbiddenDefault]:
         ] if self._check_tokens else [])
 
     def do_update(self, helper: ConfigUpdateHelper) -> None:
-        copy = helper.copy
+        copy, copy_dict = helper
 
         copy("homeserver.address")
         copy("homeserver.domain")
@@ -85,6 +85,8 @@ def do_update(self, helper: ConfigUpdateHelper) -> None:
         copy("bridge.management_room_text.welcome_unconnected")
         copy("bridge.management_room_text.additional_help")
         copy("bridge.management_room_multiple_messages")
+        copy("bridge.relay.enabled")
+        copy_dict("bridge.relay.message_formats")
 
         copy("manhole.enabled")
         copy("manhole.path")
diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index 877e1e21..61071034 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -4,7 +4,7 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 from __future__ import annotations
-from typing import Optional, Dict, Any, List
+from typing import Optional, Dict, Any, List, Tuple
 from collections import defaultdict
 from abc import ABC, abstractmethod
 import asyncio
@@ -33,6 +33,7 @@ class BasePortal(ABC):
     encrypted: bool
     is_direct: bool
     backfill_lock: SimpleLock
+    _relay_user: Optional['br.BaseUser']
 
     @abstractmethod
     async def save(self) -> None:
@@ -43,6 +44,32 @@ async def handle_matrix_message(self, sender: br.BaseUser, message: MessageEvent
                                     event_id: EventID) -> None:
         pass
 
+    @property
+    @abstractmethod
+    async def has_relay(self) -> bool:
+        pass
+
+    @property
+    @abstractmethod
+    async def get_relay_user(self) -> Optional['br.BaseUser']:
+        pass
+
+    @abstractmethod
+    async def set_relay_user(self, user: Optional['br.BaseUser']) -> None:
+        pass
+
+    @abstractmethod
+    async def get_relay_sender(self, sender: br.BaseUser, evt_identifier: str
+                               ) -> Tuple[Optional['br.BaseUser'], bool]:
+        pass
+
+    @abstractmethod
+    async def apply_msg_format(self, sender: br.BaseUser, content: MessageEventContent) -> None:
+        pass
+
+    async def get_displayname(self, user: br.BaseUser) -> str:
+        return await self.main_intent.get_room_displayname(self.mxid, user.mxid) or user.mxid
+
     async def check_dm_encryption(self) -> Optional[bool]:
         try:
             evt = await self.main_intent.get_state_event(self.mxid, EventType.ROOM_ENCRYPTION)

From 7199cfeb5216dc992770b513133dc578ed0895be Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Mon, 6 Dec 2021 09:37:10 -0500
Subject: [PATCH 10/16] Blacken code

---
 mautrix/bridge/commands/relay.py | 26 +++++++++++++++++++-------
 mautrix/bridge/portal.py         | 11 ++++++-----
 2 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/mautrix/bridge/commands/relay.py b/mautrix/bridge/commands/relay.py
index 9f79d094..6b2d0e34 100644
--- a/mautrix/bridge/commands/relay.py
+++ b/mautrix/bridge/commands/relay.py
@@ -6,21 +6,33 @@
 
 
 from mautrix.types import EventID
-from .handler import (command_handler, CommandEvent, SECTION_CONNECTION)
+from .handler import command_handler, CommandEvent, SECTION_CONNECTION
 
-@command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
-                 help_text="Relay messages in this room through your account.")
+
+@command_handler(
+    needs_auth=True,
+    management_only=False,
+    help_section=SECTION_CONNECTION,
+    help_text="Relay messages in this room through your account.",
+)
 async def set_relay(evt: CommandEvent) -> EventID:
     if not evt.config["bridge.relay.enabled"]:
         return await evt.reply("Relay mode is not enable in this instance of the bridge.")
     elif not evt.is_portal:
         return await evt.reply("This is not a portal room.")
     await evt.portal.set_relay_user(evt.sender)
-    return await evt.reply("Messages from non-logged-in users in this room will now be bridged "
-                           "through your account.")
+    return await evt.reply(
+        "Messages from non-logged-in users in this room will now be bridged "
+        "through your account."
+    )
+
 
-@command_handler(needs_auth=True, management_only=False, help_section=SECTION_CONNECTION,
-                 help_text="Stop relaying messages in this room.")
+@command_handler(
+    needs_auth=True,
+    management_only=False,
+    help_section=SECTION_CONNECTION,
+    help_text="Stop relaying messages in this room.",
+)
 async def unset_relay(evt: CommandEvent) -> EventID:
     if not evt.config["bridge.relay.enabled"]:
         return await evt.reply("Relay mode is not enable in this instance of the bridge.")
diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index 9660a575..47c62a1d 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -35,7 +35,7 @@ class BasePortal(ABC):
     encrypted: bool
     is_direct: bool
     backfill_lock: SimpleLock
-    _relay_user: Optional['br.BaseUser']
+    _relay_user: Optional["br.BaseUser"]
 
     @abstractmethod
     async def save(self) -> None:
@@ -54,16 +54,17 @@ async def has_relay(self) -> bool:
 
     @property
     @abstractmethod
-    async def get_relay_user(self) -> Optional['br.BaseUser']:
+    async def get_relay_user(self) -> Optional["br.BaseUser"]:
         pass
 
     @abstractmethod
-    async def set_relay_user(self, user: Optional['br.BaseUser']) -> None:
+    async def set_relay_user(self, user: Optional["br.BaseUser"]) -> None:
         pass
 
     @abstractmethod
-    async def get_relay_sender(self, sender: br.BaseUser, evt_identifier: str
-                               ) -> Tuple[Optional['br.BaseUser'], bool]:
+    async def get_relay_sender(
+        self, sender: br.BaseUser, evt_identifier: str
+    ) -> Tuple[Optional["br.BaseUser"], bool]:
         pass
 
     @abstractmethod

From b05da5e08634c1884a5da36c4aadaf766fce9bdd Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Mon, 6 Dec 2021 10:02:46 -0500
Subject: [PATCH 11/16] Correcting imports

---
 mautrix/bridge/commands/relay.py | 3 +--
 mautrix/bridge/portal.py         | 1 +
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/mautrix/bridge/commands/relay.py b/mautrix/bridge/commands/relay.py
index 6b2d0e34..c156cc61 100644
--- a/mautrix/bridge/commands/relay.py
+++ b/mautrix/bridge/commands/relay.py
@@ -3,9 +3,8 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-
 from mautrix.types import EventID
+
 from .handler import command_handler, CommandEvent, SECTION_CONNECTION
 
 
diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index 47c62a1d..f129796d 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -4,6 +4,7 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 from __future__ import annotations
+
 from typing import Optional, Any, Tuple
 from collections import defaultdict
 from abc import ABC, abstractmethod

From a5fd725416bcde91424df1747f8e73f1713b20ce Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Mon, 6 Dec 2021 11:05:01 -0500
Subject: [PATCH 12/16] Correcting imports

---
 mautrix/bridge/commands/relay.py | 2 +-
 mautrix/bridge/portal.py         | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/mautrix/bridge/commands/relay.py b/mautrix/bridge/commands/relay.py
index c156cc61..6c837a0d 100644
--- a/mautrix/bridge/commands/relay.py
+++ b/mautrix/bridge/commands/relay.py
@@ -5,7 +5,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 from mautrix.types import EventID
 
-from .handler import command_handler, CommandEvent, SECTION_CONNECTION
+from .handler import SECTION_CONNECTION, CommandEvent, command_handler
 
 
 @command_handler(
diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index f129796d..62880de8 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -5,7 +5,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 from __future__ import annotations
 
-from typing import Optional, Any, Tuple
+from typing import Any, Optional, Tuple
 from collections import defaultdict
 from abc import ABC, abstractmethod
 from collections import defaultdict

From 60133d69ad31a8e42908a129ca6ae68cb68d9e08 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Mon, 6 Dec 2021 11:06:52 -0500
Subject: [PATCH 13/16] Correcting imports

---
 mautrix/bridge/portal.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mautrix/bridge/portal.py b/mautrix/bridge/portal.py
index 62880de8..f1384a87 100644
--- a/mautrix/bridge/portal.py
+++ b/mautrix/bridge/portal.py
@@ -6,7 +6,6 @@
 from __future__ import annotations
 
 from typing import Any, Optional, Tuple
-from collections import defaultdict
 from abc import ABC, abstractmethod
 from collections import defaultdict
 import asyncio

From 0bbdf995e17a1f6337c9ac30938b43c69775c3a4 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Fri, 10 Dec 2021 16:03:40 -0500
Subject: [PATCH 14/16] Working in the relay mode with the pr
 https://github.com/mautrix/instagram/pull/27

---
 mautrix/bridge/commands/__init__.py | 4 +++-
 mautrix/bridge/commands/relay.py    | 2 ++
 mautrix/bridge/config.py            | 2 +-
 3 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/mautrix/bridge/commands/__init__.py b/mautrix/bridge/commands/__init__.py
index 894a0e28..7ba0c458 100644
--- a/mautrix/bridge/commands/__init__.py
+++ b/mautrix/bridge/commands/__init__.py
@@ -2,6 +2,7 @@
     SECTION_ADMIN,
     SECTION_AUTH,
     SECTION_GENERAL,
+    SECTION_CONNECTION,
     CommandEvent,
     CommandHandler,
     CommandHandlerFunc,
@@ -12,7 +13,7 @@
 )
 from .meta import cancel, help_cmd, unknown_command
 
-from . import admin, clean_rooms, crypto, delete_portal, login_matrix, manhole  # isort: skip
+from . import admin, clean_rooms, crypto, delete_portal, login_matrix, manhole, relay  # isort: skip
 
 __all__ = [
     "HelpSection",
@@ -25,4 +26,5 @@
     "SECTION_GENERAL",
     "SECTION_ADMIN",
     "SECTION_AUTH",
+    "SECTION_CONNECTION",
 ]
diff --git a/mautrix/bridge/commands/relay.py b/mautrix/bridge/commands/relay.py
index 6c837a0d..31aa8c3f 100644
--- a/mautrix/bridge/commands/relay.py
+++ b/mautrix/bridge/commands/relay.py
@@ -11,6 +11,7 @@
 @command_handler(
     needs_auth=True,
     management_only=False,
+    name="set-relay",
     help_section=SECTION_CONNECTION,
     help_text="Relay messages in this room through your account.",
 )
@@ -29,6 +30,7 @@ async def set_relay(evt: CommandEvent) -> EventID:
 @command_handler(
     needs_auth=True,
     management_only=False,
+    name="unset-relay",
     help_section=SECTION_CONNECTION,
     help_text="Stop relaying messages in this room.",
 )
diff --git a/mautrix/bridge/config.py b/mautrix/bridge/config.py
index ad841322..916886d4 100644
--- a/mautrix/bridge/config.py
+++ b/mautrix/bridge/config.py
@@ -64,7 +64,7 @@ def forbidden_defaults(self) -> list[ForbiddenDefault]:
         )
 
     def do_update(self, helper: ConfigUpdateHelper) -> None:
-        copy, copy_dict = helper
+        copy, copy_dict = helper.copy, helper.copy_dict
 
         copy("homeserver.address")
         copy("homeserver.domain")

From 7f0211224369e30e802bcd787ab019cbf146f2bc Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Fri, 10 Dec 2021 16:07:10 -0500
Subject: [PATCH 15/16] Applying Black

---
 mautrix/bridge/commands/__init__.py | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/mautrix/bridge/commands/__init__.py b/mautrix/bridge/commands/__init__.py
index 7ba0c458..4fc5db7f 100644
--- a/mautrix/bridge/commands/__init__.py
+++ b/mautrix/bridge/commands/__init__.py
@@ -13,7 +13,15 @@
 )
 from .meta import cancel, help_cmd, unknown_command
 
-from . import admin, clean_rooms, crypto, delete_portal, login_matrix, manhole, relay  # isort: skip
+from . import (
+    admin,
+    clean_rooms,
+    crypto,
+    delete_portal,
+    login_matrix,
+    manhole,
+    relay,
+)  # isort: skip
 
 __all__ = [
     "HelpSection",

From 256b4c7931bafd9bdba8edb0f5f368f222bfbaa7 Mon Sep 17 00:00:00 2001
From: Alejandro Herrera <bherrera@ikono.com.co>
Date: Fri, 10 Dec 2021 16:17:48 -0500
Subject: [PATCH 16/16] Applying Black and fixed error with Black

---
 mautrix/bridge/commands/__init__.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/mautrix/bridge/commands/__init__.py b/mautrix/bridge/commands/__init__.py
index 4fc5db7f..5b558f48 100644
--- a/mautrix/bridge/commands/__init__.py
+++ b/mautrix/bridge/commands/__init__.py
@@ -1,8 +1,8 @@
 from .handler import (
     SECTION_ADMIN,
     SECTION_AUTH,
-    SECTION_GENERAL,
     SECTION_CONNECTION,
+    SECTION_GENERAL,
     CommandEvent,
     CommandHandler,
     CommandHandlerFunc,
@@ -13,7 +13,7 @@
 )
 from .meta import cancel, help_cmd, unknown_command
 
-from . import (
+from . import (  # isort: skip
     admin,
     clean_rooms,
     crypto,
@@ -21,7 +21,7 @@
     login_matrix,
     manhole,
     relay,
-)  # isort: skip
+)
 
 __all__ = [
     "HelpSection",