2525import yaml
2626from netaddr import AddrFormatError , IPNetwork , IPSet
2727
28+ from twisted .conch .ssh .keys import Key
29+
2830from synapse .api .room_versions import KNOWN_ROOM_VERSIONS
2931from synapse .util .module_loader import load_module
3032from synapse .util .stringutils import parse_and_validate_server_name
3133
3234from ._base import Config , ConfigError
35+ from ._util import validate_config
3336
3437logger = logging .Logger (__name__ )
3538
@@ -216,6 +219,16 @@ class ListenerConfig:
216219 http_options = attr .ib (type = Optional [HttpListenerConfig ], default = None )
217220
218221
222+ @attr .s (frozen = True )
223+ class ManholeConfig :
224+ """Object describing the configuration of the manhole"""
225+
226+ username = attr .ib (type = str , validator = attr .validators .instance_of (str ))
227+ password = attr .ib (type = str , validator = attr .validators .instance_of (str ))
228+ priv_key = attr .ib (type = Optional [Key ])
229+ pub_key = attr .ib (type = Optional [Key ])
230+
231+
219232class ServerConfig (Config ):
220233 section = "server"
221234
@@ -649,6 +662,41 @@ class LimitRemoteRoomsConfig:
649662 )
650663 )
651664
665+ manhole_settings = config .get ("manhole_settings" ) or {}
666+ validate_config (
667+ _MANHOLE_SETTINGS_SCHEMA , manhole_settings , ("manhole_settings" ,)
668+ )
669+
670+ manhole_username = manhole_settings .get ("username" , "matrix" )
671+ manhole_password = manhole_settings .get ("password" , "rabbithole" )
672+ manhole_priv_key_path = manhole_settings .get ("ssh_priv_key_path" )
673+ manhole_pub_key_path = manhole_settings .get ("ssh_pub_key_path" )
674+
675+ manhole_priv_key = None
676+ if manhole_priv_key_path is not None :
677+ try :
678+ manhole_priv_key = Key .fromFile (manhole_priv_key_path )
679+ except Exception as e :
680+ raise ConfigError (
681+ f"Failed to read manhole private key file { manhole_priv_key_path } "
682+ ) from e
683+
684+ manhole_pub_key = None
685+ if manhole_pub_key_path is not None :
686+ try :
687+ manhole_pub_key = Key .fromFile (manhole_pub_key_path )
688+ except Exception as e :
689+ raise ConfigError (
690+ f"Failed to read manhole public key file { manhole_pub_key_path } "
691+ ) from e
692+
693+ self .manhole_settings = ManholeConfig (
694+ username = manhole_username ,
695+ password = manhole_password ,
696+ priv_key = manhole_priv_key ,
697+ pub_key = manhole_pub_key ,
698+ )
699+
652700 metrics_port = config .get ("metrics_port" )
653701 if metrics_port :
654702 logger .warning (METRICS_PORT_WARNING )
@@ -715,7 +763,7 @@ class LimitRemoteRoomsConfig:
715763 if not isinstance (templates_config , dict ):
716764 raise ConfigError ("The 'templates' section must be a dictionary" )
717765
718- self .custom_template_directory = templates_config .get (
766+ self .custom_template_directory : Optional [ str ] = templates_config .get (
719767 "custom_template_directory"
720768 )
721769 if self .custom_template_directory is not None and not isinstance (
@@ -727,7 +775,13 @@ def has_tls_listener(self) -> bool:
727775 return any (listener .tls for listener in self .listeners )
728776
729777 def generate_config_section (
730- self , server_name , data_dir_path , open_private_ports , listeners , ** kwargs
778+ self ,
779+ server_name ,
780+ data_dir_path ,
781+ open_private_ports ,
782+ listeners ,
783+ config_dir_path ,
784+ ** kwargs ,
731785 ):
732786 ip_range_blacklist = "\n " .join (
733787 " # - '%s'" % ip for ip in DEFAULT_IP_RANGE_BLACKLIST
@@ -1068,6 +1122,24 @@ def generate_config_section(
10681122 # bind_addresses: ['::1', '127.0.0.1']
10691123 # type: manhole
10701124
1125+ # Connection settings for the manhole
1126+ #
1127+ manhole_settings:
1128+ # The username for the manhole. This defaults to 'matrix'.
1129+ #
1130+ #username: manhole
1131+
1132+ # The password for the manhole. This defaults to 'rabbithole'.
1133+ #
1134+ #password: mypassword
1135+
1136+ # The private and public SSH key pair used to encrypt the manhole traffic.
1137+ # If these are left unset, then hardcoded and non-secret keys are used,
1138+ # which could allow traffic to be intercepted if sent over a public network.
1139+ #
1140+ #ssh_priv_key_path: %(config_dir_path)s/id_rsa
1141+ #ssh_pub_key_path: %(config_dir_path)s/id_rsa.pub
1142+
10711143 # Forward extremities can build up in a room due to networking delays between
10721144 # homeservers. Once this happens in a large room, calculation of the state of
10731145 # that room can become quite expensive. To mitigate this, once the number of
@@ -1436,3 +1508,14 @@ def _warn_if_webclient_configured(listeners: Iterable[ListenerConfig]) -> None:
14361508 if name == "webclient" :
14371509 logger .warning (NO_MORE_WEB_CLIENT_WARNING )
14381510 return
1511+
1512+
1513+ _MANHOLE_SETTINGS_SCHEMA = {
1514+ "type" : "object" ,
1515+ "properties" : {
1516+ "username" : {"type" : "string" },
1517+ "password" : {"type" : "string" },
1518+ "ssh_priv_key_path" : {"type" : "string" },
1519+ "ssh_pub_key_path" : {"type" : "string" },
1520+ },
1521+ }
0 commit comments