Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit d092e6f

Browse files
authored
Support registration_shared_secret in a file (#13614)
A new `registration_shared_secret_path` option. This is kinda handy for k8s deployments and things.
1 parent a2ce614 commit d092e6f

File tree

4 files changed

+92
-5
lines changed

4 files changed

+92
-5
lines changed

changelog.d/13614.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Support setting the registration shared secret in a file, via a new `registration_shared_secret_path` configuration option.

docs/usage/configuration/config_documentation.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,10 +2124,28 @@ registration_requires_token: true
21242124
If set, allows registration of standard or admin accounts by anyone who
21252125
has the shared secret, even if registration is otherwise disabled.
21262126

2127+
See also [`registration_shared_secret_path`](#registration_shared_secret_path).
2128+
21272129
Example configuration:
21282130
```yaml
21292131
registration_shared_secret: <PRIVATE STRING>
21302132
```
2133+
2134+
---
2135+
### `registration_shared_secret_path`
2136+
2137+
An alternative to [`registration_shared_secret`](#registration_shared_secret):
2138+
allows the shared secret to be specified in an external file.
2139+
2140+
The file should be a plain text file, containing only the shared secret.
2141+
2142+
Example configuration:
2143+
```yaml
2144+
registration_shared_secret_file: /path/to/secrets/file
2145+
```
2146+
2147+
_Added in Synapse 1.67.0._
2148+
21312149
---
21322150
### `bcrypt_rounds`
21332151

synapse/_scripts/register_new_matrix_user.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Copyright 2015, 2016 OpenMarket Ltd
22
# Copyright 2018 New Vector
3-
# Copyright 2021 The Matrix.org Foundation C.I.C.
3+
# Copyright 2021-22 The Matrix.org Foundation C.I.C.
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
66
# you may not use this file except in compliance with the License.
@@ -25,6 +25,15 @@
2525
import requests
2626
import yaml
2727

28+
_CONFLICTING_SHARED_SECRET_OPTS_ERROR = """\
29+
Conflicting options 'registration_shared_secret' and 'registration_shared_secret_path'
30+
are both defined in config file.
31+
"""
32+
33+
_NO_SHARED_SECRET_OPTS_ERROR = """\
34+
No 'registration_shared_secret' or 'registration_shared_secret_path' defined in config.
35+
"""
36+
2837
_DEFAULT_SERVER_URL = "http://localhost:8008"
2938

3039

@@ -222,9 +231,15 @@ def main() -> None:
222231
# argparse should check that we have either config or shared secret
223232
assert config
224233

225-
secret = config.get("registration_shared_secret", None)
234+
secret = config.get("registration_shared_secret")
235+
secret_file = config.get("registration_shared_secret_path")
236+
if secret_file:
237+
if secret:
238+
print(_CONFLICTING_SHARED_SECRET_OPTS_ERROR, file=sys.stderr)
239+
sys.exit(1)
240+
secret = _read_file(secret_file, "registration_shared_secret_path").strip()
226241
if not secret:
227-
print("No 'registration_shared_secret' defined in config.")
242+
print(_NO_SHARED_SECRET_OPTS_ERROR, file=sys.stderr)
228243
sys.exit(1)
229244

230245
if args.server_url:
@@ -254,6 +269,30 @@ def main() -> None:
254269
)
255270

256271

272+
def _read_file(file_path: Any, config_path: str) -> str:
273+
"""Check the given file exists, and read it into a string
274+
275+
If it does not, exit with an error indicating the problem
276+
277+
Args:
278+
file_path: the file to be read
279+
config_path: where in the configuration file_path came from, so that a useful
280+
error can be emitted if it does not exist.
281+
Returns:
282+
content of the file.
283+
"""
284+
if not isinstance(file_path, str):
285+
print(f"{config_path} setting is not a string", file=sys.stderr)
286+
sys.exit(1)
287+
288+
try:
289+
with open(file_path) as file_stream:
290+
return file_stream.read()
291+
except OSError as e:
292+
print(f"Error accessing file {file_path}: {e}", file=sys.stderr)
293+
sys.exit(1)
294+
295+
257296
def _find_client_listener(config: Dict[str, Any]) -> Optional[str]:
258297
# try to find a listener in the config. Returns a host:port pair
259298
for listener in config.get("listeners", []):

synapse/config/registration.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
import argparse
16-
from typing import Any, Optional
16+
from typing import Any, Dict, Optional
1717

1818
from synapse.api.constants import RoomCreationPreset
19-
from synapse.config._base import Config, ConfigError
19+
from synapse.config._base import Config, ConfigError, read_file
2020
from synapse.types import JsonDict, RoomAlias, UserID
2121
from synapse.util.stringutils import random_string_with_symbols, strtobool
2222

@@ -27,6 +27,11 @@
2727
remove `account_threepid_delegates.email`.
2828
"""
2929

30+
CONFLICTING_SHARED_SECRET_OPTS_ERROR = """\
31+
You have configured both `registration_shared_secret` and
32+
`registration_shared_secret_path`. These are mutually incompatible.
33+
"""
34+
3035

3136
class RegistrationConfig(Config):
3237
section = "registration"
@@ -53,7 +58,16 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
5358
self.enable_registration_token_3pid_bypass = config.get(
5459
"enable_registration_token_3pid_bypass", False
5560
)
61+
62+
# read the shared secret, either inline or from an external file
5663
self.registration_shared_secret = config.get("registration_shared_secret")
64+
registration_shared_secret_path = config.get("registration_shared_secret_path")
65+
if registration_shared_secret_path:
66+
if self.registration_shared_secret:
67+
raise ConfigError(CONFLICTING_SHARED_SECRET_OPTS_ERROR)
68+
self.registration_shared_secret = read_file(
69+
registration_shared_secret_path, ("registration_shared_secret_path",)
70+
).strip()
5771

5872
self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
5973

@@ -218,6 +232,21 @@ def generate_config_section(
218232
else:
219233
return ""
220234

235+
def generate_files(self, config: Dict[str, Any], config_dir_path: str) -> None:
236+
# if 'registration_shared_secret_path' is specified, and the target file
237+
# does not exist, generate it.
238+
registration_shared_secret_path = config.get("registration_shared_secret_path")
239+
if registration_shared_secret_path and not self.path_exists(
240+
registration_shared_secret_path
241+
):
242+
print(
243+
"Generating registration shared secret file "
244+
+ registration_shared_secret_path
245+
)
246+
secret = random_string_with_symbols(50)
247+
with open(registration_shared_secret_path, "w") as f:
248+
f.write(f"{secret}\n")
249+
221250
@staticmethod
222251
def add_arguments(parser: argparse.ArgumentParser) -> None:
223252
reg_group = parser.add_argument_group("registration")

0 commit comments

Comments
 (0)