summaryrefslogtreecommitdiff
path: root/synapse/util/manhole.py
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/util/manhole.py')
-rw-r--r--synapse/util/manhole.py57
1 files changed, 41 insertions, 16 deletions
diff --git a/synapse/util/manhole.py b/synapse/util/manhole.py
index 522daa32..f8b2d7be 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,33 +65,45 @@ EddTrx3TNpr1D5m/f+6mnXWrc8u9y1+GNx9yz889xMjIBTBI9KqaaOs=
-----END RSA PRIVATE KEY-----"""
-def manhole(username, password, 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``
"""
- if not isinstance(password, bytes):
- password = password.encode("ascii")
+ username = settings.username
+ password = settings.password.encode("ascii")
+ priv_key = settings.priv_key
+ if priv_key is None:
+ priv_key = Key.fromString(PRIVATE_KEY)
+ pub_key = settings.pub_key
+ if pub_key is None:
+ pub_key = Key.fromString(PUBLIC_KEY)
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.publicKeys[b"ssh-rsa"] = Key.fromString(PUBLIC_KEY)
- factory.privateKeys[b"ssh-rsa"] = Key.fromString(PRIVATE_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
@@ -95,7 +111,7 @@ def manhole(username, password, 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
@@ -105,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
@@ -129,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
@@ -137,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,