This repository has no description
4.1 kB
138 lines
1{ pkgs, lib, ... }:
2let
3 pkg = pkgs.matrix-zulip-bridge;
4 bin = lib.getExe pkg;
5
6 address = "127.0.0.1";
7 port = 28464;
8 homeserver = "http://[::1]:8008";
9 owner = "@lassulus:lassul.us";
10
11 registrationFile = "/var/lib/matrix-zulip-bridge/registration.yml";
12
13 # JSON is a proper subset of YAML. We render our desired registration and
14 # merge in the tokens from the bridge-generated file in preStart, mirroring
15 # the upstream heisenbridge module (this bridge shares its architecture).
16 bridgeConfig = builtins.toFile "matrix-zulip-bridge-registration.yml" (
17 builtins.toJSON {
18 id = "zulipbridge";
19 url = "http://${address}:${toString port}";
20 rate_limited = false;
21 sender_localpart = "zulipbridge";
22 namespaces = {
23 users = [
24 {
25 regex = "@zulip_.*:lassul\\.us";
26 exclusive = true;
27 }
28 {
29 regex = "@zulipbridge:lassul\\.us";
30 exclusive = true;
31 }
32 ];
33 aliases = [ ];
34 rooms = [ ];
35 };
36 }
37 );
38in
39{
40 systemd.services.matrix-zulip-bridge = {
41 description = "Matrix<->Zulip bridge";
42 before = [ "matrix-synapse.service" ]; # So the registration file can be used by Synapse
43 wantedBy = [ "multi-user.target" ];
44
45 preStart = ''
46 umask 077
47 set -e -u -o pipefail
48
49 if ! [ -f "${registrationFile}" ]; then
50 # Generate registration file if not present (we only care about the tokens in it)
51 ${bin} --generate --config ${registrationFile}
52 fi
53
54 # Overwrite the registration file with our generated one (the config may have
55 # changed since then), but keep the tokens. Two step procedure to be failure safe.
56 ${pkgs.yq}/bin/yq --slurp \
57 '.[0] + (.[1] | {as_token, hs_token})' \
58 ${bridgeConfig} \
59 ${registrationFile} \
60 > ${registrationFile}.new
61 mv -f ${registrationFile}.new ${registrationFile}
62
63 # Grant Synapse access to the registration
64 if ${pkgs.getent}/bin/getent group matrix-synapse > /dev/null; then
65 chgrp -v matrix-synapse ${registrationFile}
66 chmod -v g+r ${registrationFile}
67 fi
68 '';
69
70 serviceConfig = {
71 Type = "simple";
72 ExecStart = lib.concatStringsSep " " [
73 bin
74 "-v"
75 "--config"
76 registrationFile
77 "--listen-address"
78 (lib.escapeShellArg address)
79 "--listen-port"
80 (toString port)
81 "--owner"
82 (lib.escapeShellArg owner)
83 (lib.escapeShellArg homeserver)
84 ];
85
86 # Hardening options (mirrors upstream heisenbridge module)
87 User = "matrix-zulip-bridge";
88 Group = "matrix-zulip-bridge";
89 RuntimeDirectory = "matrix-zulip-bridge";
90 RuntimeDirectoryMode = "0700";
91 StateDirectory = "matrix-zulip-bridge";
92 StateDirectoryMode = "0755";
93
94 ProtectSystem = "strict";
95 ProtectHome = true;
96 PrivateTmp = true;
97 PrivateDevices = true;
98 ProtectKernelTunables = true;
99 ProtectControlGroups = true;
100 RestrictSUIDSGID = true;
101 PrivateMounts = true;
102 ProtectKernelModules = true;
103 ProtectKernelLogs = true;
104 ProtectHostname = true;
105 ProtectClock = true;
106 ProtectProc = "invisible";
107 ProcSubset = "pid";
108 RestrictNamespaces = true;
109 RemoveIPC = true;
110 UMask = "0077";
111
112 CapabilityBoundingSet = [ "CAP_CHOWN" ];
113 AmbientCapabilities = [ "CAP_CHOWN" ];
114 NoNewPrivileges = true;
115 LockPersonality = true;
116 RestrictRealtime = true;
117 SystemCallFilter = [
118 "@system-service"
119 "~@privileged"
120 "@chown"
121 ];
122 SystemCallArchitectures = "native";
123 RestrictAddressFamilies = "AF_INET AF_INET6";
124 };
125 };
126
127 # Wire the registration into Synapse (merges with the other bridges' lists).
128 services.matrix-synapse.settings.app_service_config_files = [
129 registrationFile
130 ];
131
132 users.groups.matrix-zulip-bridge = { };
133 users.users.matrix-zulip-bridge = {
134 description = "Service user for the Matrix Zulip bridge";
135 group = "matrix-zulip-bridge";
136 isSystemUser = true;
137 };
138}