summary refs log tree commit diff
path: root/synapse/util/manhole.py
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/util/manhole.py')
-rw-r--r--synapse/util/manhole.py52
1 files changed, 34 insertions, 18 deletions
diff --git a/synapse/util/manhole.py b/synapse/util/manhole.py
index cfb5b94ca9..f8b2d7bea9 100644
--- a/synapse/util/manhole.py
+++ b/synapse/util/manhole.py
@@ -15,6 +15,7 @@
 import inspect
 import sys
 import traceback
+from typing import Any, Dict, Optional
 
 from twisted.conch import manhole_ssh
 from twisted.conch.insults import insults
@@ -22,6 +23,9 @@ from twisted.conch.manhole import ColoredManhole, ManholeInterpreter
 from twisted.conch.ssh.keys import Key
 from twisted.cred import checkers, portal
 from twisted.internet import defer
+from twisted.internet.protocol import Factory
+
+from synapse.config.server import ManholeConfig
 
 PUBLIC_KEY = (
     "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHhGATaW4KhE23+7nrH4jFx3yLq9OjaEs5"
@@ -61,22 +65,22 @@ EddTrx3TNpr1D5m/f+6mnXWrc8u9y1+GNx9yz889xMjIBTBI9KqaaOs=
 -----END RSA PRIVATE KEY-----"""
 
 
-def manhole(settings, globals):
+def manhole(settings: ManholeConfig, globals: Dict[str, Any]) -> Factory:
     """Starts a ssh listener with password authentication using
     the given username and password. Clients connecting to the ssh
     listener will find themselves in a colored python shell with
     the supplied globals.
 
     Args:
-        username(str): The username ssh clients should auth with.
-        password(str): The password ssh clients should auth with.
-        globals(dict): The variables to expose in the shell.
+        username: The username ssh clients should auth with.
+        password: The password ssh clients should auth with.
+        globals: The variables to expose in the shell.
 
     Returns:
-        twisted.internet.protocol.Factory: A factory to pass to ``listenTCP``
+        A factory to pass to ``listenTCP``
     """
     username = settings.username
-    password = settings.password
+    password = settings.password.encode("ascii")
     priv_key = settings.priv_key
     if priv_key is None:
         priv_key = Key.fromString(PRIVATE_KEY)
@@ -84,19 +88,22 @@ def manhole(settings, globals):
     if pub_key is None:
         pub_key = Key.fromString(PUBLIC_KEY)
 
-    if not isinstance(password, bytes):
-        password = password.encode("ascii")
-
     checker = checkers.InMemoryUsernamePasswordDatabaseDontUse(**{username: password})
 
     rlm = manhole_ssh.TerminalRealm()
-    rlm.chainedProtocolFactory = lambda: insults.ServerProtocol(
+    # mypy ignored here because:
+    # - can't deduce types of lambdas
+    # - variable is Type[ServerProtocol], expr is Callable[[], ServerProtocol]
+    rlm.chainedProtocolFactory = lambda: insults.ServerProtocol(  # type: ignore[misc,assignment]
         SynapseManhole, dict(globals, __name__="__console__")
     )
 
     factory = manhole_ssh.ConchFactory(portal.Portal(rlm, [checker]))
-    factory.privateKeys[b"ssh-rsa"] = priv_key
-    factory.publicKeys[b"ssh-rsa"] = pub_key
+
+    # conch has the wrong type on these dicts (says bytes to bytes,
+    # should be bytes to Keys judging by how it's used).
+    factory.privateKeys[b"ssh-rsa"] = priv_key  # type: ignore[assignment]
+    factory.publicKeys[b"ssh-rsa"] = pub_key  # type: ignore[assignment]
 
     return factory
 
@@ -104,7 +111,7 @@ def manhole(settings, globals):
 class SynapseManhole(ColoredManhole):
     """Overrides connectionMade to create our own ManholeInterpreter"""
 
-    def connectionMade(self):
+    def connectionMade(self) -> None:
         super().connectionMade()
 
         # replace the manhole interpreter with our own impl
@@ -114,13 +121,14 @@ class SynapseManhole(ColoredManhole):
 
 
 class SynapseManholeInterpreter(ManholeInterpreter):
-    def showsyntaxerror(self, filename=None):
+    def showsyntaxerror(self, filename: Optional[str] = None) -> None:
         """Display the syntax error that just occurred.
 
         Overrides the base implementation, ignoring sys.excepthook. We always want
         any syntax errors to be sent to the terminal, rather than sentry.
         """
         type, value, tb = sys.exc_info()
+        assert value is not None
         sys.last_type = type
         sys.last_value = value
         sys.last_traceback = tb
@@ -138,7 +146,7 @@ class SynapseManholeInterpreter(ManholeInterpreter):
         lines = traceback.format_exception_only(type, value)
         self.write("".join(lines))
 
-    def showtraceback(self):
+    def showtraceback(self) -> None:
         """Display the exception that just occurred.
 
         Overrides the base implementation, ignoring sys.excepthook. We always want
@@ -146,14 +154,22 @@ class SynapseManholeInterpreter(ManholeInterpreter):
         """
         sys.last_type, sys.last_value, last_tb = ei = sys.exc_info()
         sys.last_traceback = last_tb
+        assert last_tb is not None
+
         try:
             # We remove the first stack item because it is our own code.
             lines = traceback.format_exception(ei[0], ei[1], last_tb.tb_next)
             self.write("".join(lines))
         finally:
-            last_tb = ei = None
-
-    def displayhook(self, obj):
+            # On the line below, last_tb and ei appear to be dead.
+            # It's unclear whether there is a reason behind this line.
+            # It conceivably could be because an exception raised in this block
+            # will keep the local frame (containing these local variables) around.
+            # This was adapted taken from CPython's Lib/code.py; see here:
+            # https://github.com/python/cpython/blob/4dc4300c686f543d504ab6fa9fe600eaf11bb695/Lib/code.py#L131-L150
+            last_tb = ei = None  # type: ignore
+
+    def displayhook(self, obj: Any) -> None:
         """
         We override the displayhook so that we automatically convert coroutines
         into Deferreds. (Our superclass' displayhook will take care of the rest,