blob: b87190063ba4f1623c5264f490f27bfbe166fb72 [file] [log] [blame]
Skyler Greya78aa672023-05-20 13:48:18 +02001{ base, config, lib, pkgs, ... }:
Skyler Greyfe1740c2023-10-21 01:24:18 +00002lib.recursiveUpdate {
Skyler Grey8e32c832023-05-20 22:54:30 +02003 services.matrix-synapse = {
Skyler Greya78aa672023-05-20 13:48:18 +02004 enable = true;
Skyler Grey8e32c832023-05-20 22:54:30 +02005 withJemalloc = true;
Skyler Greya78aa672023-05-20 13:48:18 +02006
Skyler Greyfe1740c2023-10-21 01:24:18 +00007 plugins = with config.services.matrix-synapse.package.plugins;
8 [ matrix-synapse-mjolnir-antispam ];
Skyler Grey874a2a82023-06-08 12:29:28 +02009
Skyler Grey1144d002023-05-21 00:17:29 +020010 settings = rec {
Skyler Grey22428b02023-11-19 13:20:56 +000011 server_name = "clicks.codes";
Skyler Grey1144d002023-05-21 00:17:29 +020012 auto_join_rooms = [ "#general:${server_name}" ];
Skyler Grey896e9282023-12-22 23:49:10 +000013 suppress_key_server_warning = true;
Skyler Grey8e32c832023-05-20 22:54:30 +020014 enable_registration = true;
15 registration_requires_token = true;
Skyler Greyd18587c2023-10-09 07:25:36 +000016 allow_public_rooms_over_federation = true;
17 allow_device_name_lookup_over_federation = true;
Skyler Grey8e32c832023-05-20 22:54:30 +020018 registration_shared_secret = "!!registration_shared_secret!!";
Skyler Grey22428b02023-11-19 13:20:56 +000019 public_baseurl = "https://matrix-backend.clicks.codes/";
Skyler Grey8e32c832023-05-20 22:54:30 +020020 max_upload_size = "100M";
21 listeners = [{
22 x_forwarded = true;
23 tls = false;
24 resources = [{
Skyler Greyfe1740c2023-10-21 01:24:18 +000025 names = [ "client" "federation" ];
Skyler Grey8e32c832023-05-20 22:54:30 +020026 compress = true;
27 }];
Skyler Grey7610ce42023-11-29 19:29:59 +000028 port = 1030;
29 bind_addresses = [ "generic" ];
Skyler Grey8e32c832023-05-20 22:54:30 +020030 }];
31 enable_metrics = true;
32 database.args.database = "synapse";
Skyler Grey22428b02023-11-19 13:20:56 +000033
34 oidc_providers = [
35 {
36 idp_id = "keycloak";
37 idp_name = "Clicks Keycloak";
38 issuer = "https://login.clicks.codes/realms/master";
39 client_id = "matrix";
40 client_secret = "!!matrix_keycloak_client_secret!!";
41 scopes = [ "openid" "profile" ];
42 user_mapping_provider = {
43 config = {
44 localpart_template = "{{ user.preferred_username }}";
45 display_name_template = "{{ user.name }}";
46 };
47 };
48 backchannel_logout_enabled = true;
49 }
50 ];
51
Skyler Greyd18587c2023-10-09 07:25:36 +000052 log_config = lib.pipe {
53 version = 1;
54 formatters = {
55 precise = {
56 format =
57 "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
58 };
59 };
60 handlers = {
61 console = {
62 class = "logging.StreamHandler";
63 formatter = "precise";
64 };
65 };
66 loggers = { "synapse.storage.SQL" = { level = "WARNING"; }; };
67 root = {
68 level = "ERROR";
69 handlers = [ "console" ];
70 };
71 "disable_existing_loggers" = false;
Skyler Greyfe1740c2023-10-21 01:24:18 +000072 } [ builtins.toJSON (builtins.toFile "logcfg.yaml") ];
Skyler Greye6a5a912023-11-21 20:19:30 +000073
74 server_notices = {
75 system_mxid_localpart = "system";
76 system_mxid_display_name = "Clicks Administrators";
77 room_name = "Announcements";
78 };
Skyler Greya78aa672023-05-20 13:48:18 +020079 };
Skyler Grey7610ce42023-11-29 19:29:59 +000080
81 sliding-sync = {
82 enable = true;
83 settings = {
84 SYNCV3_SERVER = "https://matrix-backend.clicks.codes";
85 SYNCV3_BINDADDR = "generic:1031";
86 SYNCV3_LOG_LEVEL = "warn";
87 };
88 environmentFile = config.sops.secrets.matrix_sliding_sync_env.path;
89 createDatabase = true;
90 };
Skyler Greya78aa672023-05-20 13:48:18 +020091 };
92
Skyler Greyb64b5e92023-08-20 21:53:37 +000093 networking.firewall.allowedTCPPorts = [ 3478 5349 ];
94 networking.firewall.allowedUDPPorts = [ 3478 5349 ];
95
Skyler Grey874a2a82023-06-08 12:29:28 +020096 services.mjolnir = {
Skyler Grey083b1e32023-11-20 18:48:02 +000097 enable = true;
Skyler Grey874a2a82023-06-08 12:29:28 +020098
99 settings = {
100 autojoinOnlyIfManager = true;
Skyler Greyfe1740c2023-10-21 01:24:18 +0000101 automaticallyRedactForReasons =
102 [ "nsfw" "gore" "spam" "harassment" "hate" ];
Skyler Grey874a2a82023-06-08 12:29:28 +0200103 recordIgnoredInvites = true;
104 admin.enableMakeRoomAdminCommand = true;
105 allowNoPrefix = true;
106 protections.wordlist.words = [ ];
Skyler Grey22428b02023-11-19 13:20:56 +0000107 protectedRooms = [ "https://matrix.to/#/#global:clicks.codes" ];
Skyler Grey874a2a82023-06-08 12:29:28 +0200108 };
109
110 pantalaimon = {
111 enable = true;
112 username = "system";
113 passwordFile = config.sops.secrets.mjolnir_password.path;
114 options = {
115 ssl = false;
116 listenAddress = "127.0.0.1";
117 };
118 };
119
Skyler Grey915067d2023-12-03 13:46:53 +0000120 homeserverUrl = "http://generic:1030";
Skyler Grey874a2a82023-06-08 12:29:28 +0200121
Skyler Grey22428b02023-11-19 13:20:56 +0000122 managementRoom = "#moderation-commands:clicks.codes";
Skyler Grey874a2a82023-06-08 12:29:28 +0200123 };
124
Skyler Grey8e32c832023-05-20 22:54:30 +0200125 sops.secrets = {
Skyler Grey7610ce42023-11-29 19:29:59 +0000126 matrix_sliding_sync_env = {
127 mode = "0600";
128 owner = config.users.users.root.name;
129 group = config.users.users.root.group;
130 sopsFile = ../../secrets/matrix_sliding_sync.env.bin;
131 format = "binary";
132 };
Skyler Grey22428b02023-11-19 13:20:56 +0000133 matrix_keycloak_client_secret = {
134 mode = "0400";
135 owner = config.users.users.matrix-synapse.name;
136 group = config.users.users.matrix-synapse.group;
137 sopsFile = ../../secrets/matrix.json;
138 format = "json";
139 };
Skyler Grey8e32c832023-05-20 22:54:30 +0200140 registration_shared_secret = {
Skyler Greya78aa672023-05-20 13:48:18 +0200141 mode = "0400";
Skyler Grey8e32c832023-05-20 22:54:30 +0200142 owner = config.users.users.root.name;
Skyler Greybcb46d32023-11-10 20:48:38 +0000143 group = config.users.users.root.group;
Samuel Shuertf68685d2023-10-28 20:07:56 -0400144 sopsFile = ../../secrets/matrix.json;
Skyler Grey8e32c832023-05-20 22:54:30 +0200145 format = "json";
146 };
147 matrix_private_key = {
148 mode = "0600";
149 owner = config.users.users.matrix-synapse.name;
150 group = config.users.users.matrix-synapse.group;
Samuel Shuertf68685d2023-10-28 20:07:56 -0400151 sopsFile = ../../secrets/matrix_private_key.pem;
Skyler Greya78aa672023-05-20 13:48:18 +0200152 format = "binary";
Skyler Grey8e32c832023-05-20 22:54:30 +0200153 path = config.services.matrix-synapse.settings.signing_key_path;
Skyler Greya78aa672023-05-20 13:48:18 +0200154 };
Skyler Grey083b1e32023-11-20 18:48:02 +0000155 mjolnir_password = {
Skyler Grey874a2a82023-06-08 12:29:28 +0200156 mode = "0600";
157 owner = config.users.users.mjolnir.name;
158 group = config.users.users.mjolnir.group;
Samuel Shuertf68685d2023-10-28 20:07:56 -0400159 sopsFile = ../../secrets/matrix.json;
Skyler Grey874a2a82023-06-08 12:29:28 +0200160 format = "json";
Skyler Grey083b1e32023-11-20 18:48:02 +0000161 };
Skyler Greya78aa672023-05-20 13:48:18 +0200162 };
Skyler Greyfae88b12023-12-03 12:02:49 +0000163
Skyler Grey6f9047d2023-12-23 00:03:53 +0000164 systemd.services.matrix-synapse.requires = [ "postgresql.service" ];
165 systemd.services.matrix-synapse.after = [ "nginx.service" "keycloak.service" ];
Skyler Greyfae88b12023-12-03 12:02:49 +0000166
Skyler Greyfe1740c2023-10-21 01:24:18 +0000167} (let isDerived = base != null;
168in if isDerived
169# We cannot use mkIf as both sides are evaluated no matter the condition value
170# Given we use base as an attrset, mkIf will error if base is null in here
171then
172 let synapse_cfgfile = config.services.matrix-synapse.configFile;
173 in {
174 scalpel.trafos."synapse.yaml" = {
175 source = toString synapse_cfgfile;
176 matchers."registration_shared_secret".secret =
177 config.sops.secrets.registration_shared_secret.path;
Skyler Grey22428b02023-11-19 13:20:56 +0000178 matchers."matrix_keycloak_client_secret".secret =
179 config.sops.secrets.matrix_keycloak_client_secret.path;
Skyler Greyfe1740c2023-10-21 01:24:18 +0000180 owner = config.users.users.matrix-synapse.name;
181 group = config.users.users.matrix-synapse.group;
182 mode = "0400";
183 };
184
185 systemd.services.matrix-synapse.serviceConfig.ExecStart = lib.mkForce
186 (builtins.replaceStrings [ "${synapse_cfgfile}" ]
187 [ "${config.scalpel.trafos."synapse.yaml".destination}" ]
188 "${base.config.systemd.services.matrix-synapse.serviceConfig.ExecStart}");
189
190 systemd.services.matrix-synapse.preStart = lib.mkForce
Skyler Grey6f9047d2023-12-23 00:03:53 +0000191 ("while [[ \"$(${pkgs.curl}/bin/curl -s -o /dev/null -w ''%{http_code}'' https://login.clicks.codes)\" != \"200\" ]]; do sleep 5; done; " +
Skyler Greyfe1740c2023-10-21 01:24:18 +0000192 (builtins.replaceStrings [ "${synapse_cfgfile}" ]
193 [ "${config.scalpel.trafos."synapse.yaml".destination}" ]
Skyler Grey6f9047d2023-12-23 00:03:53 +0000194 "${base.config.systemd.services.matrix-synapse.preStart}"));
Skyler Greyfe1740c2023-10-21 01:24:18 +0000195
196 systemd.services.matrix-synapse.restartTriggers = [ synapse_cfgfile ];
197
198 environment.systemPackages = with lib;
Skyler Grey874a2a82023-06-08 12:29:28 +0200199 let
Skyler Greyfe1740c2023-10-21 01:24:18 +0000200 cfg = config.services.matrix-synapse;
201 registerNewMatrixUser = let
202 isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
203 listener = lib.findFirst (listener:
204 lib.any (resource: lib.any (name: name == "client") resource.names)
205 listener.resources) (lib.last cfg.settings.listeners)
206 cfg.settings.listeners;
207 # FIXME: Handle cases with missing client listener properly,
208 # don't rely on lib.last, this will not work.
Skyler Greya78aa672023-05-20 13:48:18 +0200209
Skyler Greyfe1740c2023-10-21 01:24:18 +0000210 # add a tail, so that without any bind_addresses we still have a useable address
211 bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]);
212 listenerProtocol = if listener.tls then "https" else "http";
213 in pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
214 exec ${cfg.package}/bin/register_new_matrix_user \
215 $@ \
216 ${
217 lib.concatMapStringsSep " " (x: "-c ${x}")
218 ([ config.scalpel.trafos."synapse.yaml".destination ]
219 ++ cfg.extraConfigFiles)
220 } \
221 "${listenerProtocol}://${
222 if (isIpv6 bindAddress) then
223 "[${bindAddress}]"
224 else
225 "${bindAddress}"
226 }:${builtins.toString listener.port}/"
227 '';
228 in [ (lib.meta.hiPrio registerNewMatrixUser) ];
229 }
230else
231 { })