···
7
+
cfg = config.services.mautrix-signal;
8
+
dataDir = "/var/lib/mautrix-signal";
9
+
registrationFile = "${dataDir}/signal-registration.yaml";
10
+
settingsFile = "${dataDir}/config.yaml";
11
+
settingsFileUnsubstituted = settingsFormat.generate "mautrix-signal-config-unsubstituted.json" cfg.settings;
12
+
settingsFormat = pkgs.formats.json { };
13
+
appservicePort = 29328;
15
+
# to be used with a list of lib.mkIf values
16
+
optOneOf = lib.lists.findFirst (value: value.condition) (lib.mkIf false null);
17
+
mkDefaults = lib.mapAttrsRecursive (n: v: lib.mkDefault v);
19
+
homeserver.address = "http://localhost:8448";
22
+
port = appservicePort;
23
+
database.type = "sqlite3";
24
+
database.uri = "file:${dataDir}/mautrix-signal.db?_txlock=immediate";
27
+
username = "signalbot";
28
+
displayname = "Signal Bridge Bot";
34
+
username_template = "signal_{{.}}";
35
+
displayname_template = "{{or .ProfileName .PhoneNumber \"Unknown user\"}}";
36
+
double_puppet_server_map = { };
37
+
login_shared_secret_map = { };
38
+
command_prefix = "!signal";
39
+
permissions."*" = "relay";
40
+
relay.enabled = true;
44
+
writers = lib.singleton {
46
+
format = "pretty-colored";
54
+
options.services.mautrix-signal = {
55
+
enable = lib.mkEnableOption "mautrix-signal, a Matrix-Signal puppeting bridge.";
57
+
settings = lib.mkOption {
58
+
apply = lib.recursiveUpdate defaultConfig;
59
+
type = settingsFormat.type;
60
+
default = defaultConfig;
62
+
{file}`config.yaml` configuration as a Nix attribute set.
63
+
Configuration options should match those described in
64
+
[example-config.yaml](https://github.com/mautrix/signal/blob/master/example-config.yaml).
65
+
Secret tokens should be specified using {option}`environmentFile`
66
+
instead of this world-readable attribute set.
72
+
uri = "postgresql:///mautrix_signal?host=/run/postgresql";
75
+
ephemeral_events = false;
79
+
request_full_sync = true;
81
+
private_chat_portal_meta = true;
82
+
mute_bridging = true;
89
+
shared_secret = "disable";
92
+
"example.com" = "user";
98
+
environmentFile = lib.mkOption {
99
+
type = lib.types.nullOr lib.types.path;
102
+
File containing environment variables to be passed to the mautrix-signal service.
103
+
If an environment variable `MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET` is set,
104
+
then its value will be used in the configuration file for the option
105
+
`login_shared_secret_map` without leaking it to the store, using the configured
106
+
`homeserver.domain` as key.
107
+
See [here](https://github.com/mautrix/signal/blob/main/example-config.yaml)
108
+
for the documentation of `login_shared_secret_map`.
112
+
serviceDependencies = lib.mkOption {
113
+
type = with lib.types; listOf str;
114
+
default = (lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit)
115
+
++ (lib.optional config.services.matrix-conduit.enable "conduit.service");
116
+
defaultText = lib.literalExpression ''
117
+
(optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit)
118
+
++ (optional config.services.matrix-conduit.enable "conduit.service")
121
+
List of systemd units to require and wait for when starting the application service.
125
+
registerToSynapse = lib.mkOption {
126
+
type = lib.types.bool;
127
+
default = config.services.matrix-synapse.enable;
128
+
defaultText = lib.literalExpression ''
129
+
config.services.matrix-synapse.enable
132
+
Whether to add the bridge's app service registration file to
133
+
`services.matrix-synapse.settings.app_service_config_files`.
138
+
config = lib.mkIf cfg.enable {
140
+
users.users.mautrix-signal = {
141
+
isSystemUser = true;
142
+
group = "mautrix-signal";
144
+
description = "Mautrix-Signal bridge user";
147
+
users.groups.mautrix-signal = { };
149
+
services.matrix-synapse = lib.mkIf cfg.registerToSynapse {
150
+
settings.app_service_config_files = [ registrationFile ];
152
+
systemd.services.matrix-synapse = lib.mkIf cfg.registerToSynapse {
153
+
serviceConfig.SupplementaryGroups = [ "mautrix-signal" ];
156
+
# Note: this is defined here to avoid the docs depending on `config`
157
+
services.mautrix-signal.settings.homeserver = optOneOf (with config.services; [
158
+
(lib.mkIf matrix-synapse.enable (mkDefaults {
159
+
domain = matrix-synapse.settings.server_name;
161
+
(lib.mkIf matrix-conduit.enable (mkDefaults {
162
+
domain = matrix-conduit.settings.global.server_name;
163
+
address = "http://localhost:${toString matrix-conduit.settings.global.port}";
167
+
systemd.services.mautrix-signal = {
168
+
description = "mautrix-signal, a Matrix-Signal puppeting bridge.";
170
+
wantedBy = [ "multi-user.target" ];
171
+
wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
172
+
after = [ "network-online.target" ] ++ cfg.serviceDependencies;
173
+
# ffmpeg is required for conversion of voice messages
174
+
path = [ pkgs.ffmpeg-headless ];
177
+
# substitute the settings file by environment variables
178
+
# in this case read from EnvironmentFile
179
+
test -f '${settingsFile}' && rm -f '${settingsFile}'
182
+
${pkgs.envsubst}/bin/envsubst \
183
+
-o '${settingsFile}' \
184
+
-i '${settingsFileUnsubstituted}'
187
+
# generate the appservice's registration file if absent
188
+
if [ ! -f '${registrationFile}' ]; then
189
+
${pkgs.mautrix-signal}/bin/mautrix-signal \
190
+
--generate-registration \
191
+
--config='${settingsFile}' \
192
+
--registration='${registrationFile}'
194
+
chmod 640 ${registrationFile}
197
+
# 1. Overwrite registration tokens in config
198
+
# 2. If environment variable MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET
199
+
# is set, set it as the login shared secret value for the configured
200
+
# homeserver domain.
201
+
${pkgs.yq}/bin/yq -s '.[0].appservice.as_token = .[1].as_token
202
+
| .[0].appservice.hs_token = .[1].hs_token
204
+
| if env.MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET then .bridge.login_shared_secret_map.[.homeserver.domain] = env.MAUTRIX_SIGNAL_BRIDGE_LOGIN_SHARED_SECRET else . end' \
205
+
'${settingsFile}' '${registrationFile}' > '${settingsFile}.tmp'
206
+
mv '${settingsFile}.tmp' '${settingsFile}'
211
+
User = "mautrix-signal";
212
+
Group = "mautrix-signal";
213
+
EnvironmentFile = cfg.environmentFile;
214
+
StateDirectory = baseNameOf dataDir;
215
+
WorkingDirectory = dataDir;
217
+
${pkgs.mautrix-signal}/bin/mautrix-signal \
218
+
--config='${settingsFile}' \
219
+
--registration='${registrationFile}'
221
+
LockPersonality = true;
222
+
MemoryDenyWriteExecute = true;
223
+
NoNewPrivileges = true;
224
+
PrivateDevices = true;
226
+
PrivateUsers = true;
227
+
ProtectClock = true;
228
+
ProtectControlGroups = true;
229
+
ProtectHome = true;
230
+
ProtectHostname = true;
231
+
ProtectKernelLogs = true;
232
+
ProtectKernelModules = true;
233
+
ProtectKernelTunables = true;
234
+
ProtectSystem = "strict";
235
+
Restart = "on-failure";
236
+
RestartSec = "30s";
237
+
RestrictRealtime = true;
238
+
RestrictSUIDSGID = true;
239
+
SystemCallArchitectures = "native";
240
+
SystemCallErrorNumber = "EPERM";
241
+
SystemCallFilter = [ "@system-service" ];
245
+
restartTriggers = [ settingsFileUnsubstituted ];
248
+
meta.maintainers = with lib.maintainers; [ niklaskorz ];