blob: 26b2c2672898b10f4a3f31d0d74e714137e4e122 [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 Grey8e32c832023-05-20 22:54:30 +020013 enable_registration = true;
14 registration_requires_token = true;
Skyler Greyd18587c2023-10-09 07:25:36 +000015 allow_public_rooms_over_federation = true;
16 allow_device_name_lookup_over_federation = true;
Skyler Grey8e32c832023-05-20 22:54:30 +020017 registration_shared_secret = "!!registration_shared_secret!!";
Skyler Grey22428b02023-11-19 13:20:56 +000018 public_baseurl = "https://matrix-backend.clicks.codes/";
Skyler Grey8e32c832023-05-20 22:54:30 +020019 max_upload_size = "100M";
20 listeners = [{
21 x_forwarded = true;
22 tls = false;
23 resources = [{
Skyler Greyfe1740c2023-10-21 01:24:18 +000024 names = [ "client" "federation" ];
Skyler Grey8e32c832023-05-20 22:54:30 +020025 compress = true;
26 }];
Skyler Grey7610ce42023-11-29 19:29:59 +000027 port = 1030;
28 bind_addresses = [ "generic" ];
Skyler Grey8e32c832023-05-20 22:54:30 +020029 }];
30 enable_metrics = true;
31 database.args.database = "synapse";
Skyler Grey22428b02023-11-19 13:20:56 +000032
33 oidc_providers = [
34 {
35 idp_id = "keycloak";
36 idp_name = "Clicks Keycloak";
37 issuer = "https://login.clicks.codes/realms/master";
38 client_id = "matrix";
39 client_secret = "!!matrix_keycloak_client_secret!!";
40 scopes = [ "openid" "profile" ];
41 user_mapping_provider = {
42 config = {
43 localpart_template = "{{ user.preferred_username }}";
44 display_name_template = "{{ user.name }}";
45 };
46 };
47 backchannel_logout_enabled = true;
48 }
49 ];
50
Skyler Greyd18587c2023-10-09 07:25:36 +000051 log_config = lib.pipe {
52 version = 1;
53 formatters = {
54 precise = {
55 format =
56 "%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
57 };
58 };
59 handlers = {
60 console = {
61 class = "logging.StreamHandler";
62 formatter = "precise";
63 };
64 };
65 loggers = { "synapse.storage.SQL" = { level = "WARNING"; }; };
66 root = {
67 level = "ERROR";
68 handlers = [ "console" ];
69 };
70 "disable_existing_loggers" = false;
Skyler Greyfe1740c2023-10-21 01:24:18 +000071 } [ builtins.toJSON (builtins.toFile "logcfg.yaml") ];
Skyler Greye6a5a912023-11-21 20:19:30 +000072
73 server_notices = {
74 system_mxid_localpart = "system";
75 system_mxid_display_name = "Clicks Administrators";
76 room_name = "Announcements";
77 };
Skyler Greya78aa672023-05-20 13:48:18 +020078 };
Skyler Grey7610ce42023-11-29 19:29:59 +000079
80 sliding-sync = {
81 enable = true;
82 settings = {
83 SYNCV3_SERVER = "https://matrix-backend.clicks.codes";
84 SYNCV3_BINDADDR = "generic:1031";
85 SYNCV3_LOG_LEVEL = "warn";
86 };
87 environmentFile = config.sops.secrets.matrix_sliding_sync_env.path;
88 createDatabase = true;
89 };
Skyler Greya78aa672023-05-20 13:48:18 +020090 };
91
Skyler Greyb64b5e92023-08-20 21:53:37 +000092 networking.firewall.allowedTCPPorts = [ 3478 5349 ];
93 networking.firewall.allowedUDPPorts = [ 3478 5349 ];
94
Skyler Grey874a2a82023-06-08 12:29:28 +020095 services.mjolnir = {
Skyler Grey083b1e32023-11-20 18:48:02 +000096 enable = true;
Skyler Grey874a2a82023-06-08 12:29:28 +020097
98 settings = {
99 autojoinOnlyIfManager = true;
Skyler Greyfe1740c2023-10-21 01:24:18 +0000100 automaticallyRedactForReasons =
101 [ "nsfw" "gore" "spam" "harassment" "hate" ];
Skyler Grey874a2a82023-06-08 12:29:28 +0200102 recordIgnoredInvites = true;
103 admin.enableMakeRoomAdminCommand = true;
104 allowNoPrefix = true;
105 protections.wordlist.words = [ ];
Skyler Grey22428b02023-11-19 13:20:56 +0000106 protectedRooms = [ "https://matrix.to/#/#global:clicks.codes" ];
Skyler Grey874a2a82023-06-08 12:29:28 +0200107 };
108
109 pantalaimon = {
110 enable = true;
111 username = "system";
112 passwordFile = config.sops.secrets.mjolnir_password.path;
113 options = {
114 ssl = false;
115 listenAddress = "127.0.0.1";
116 };
117 };
118
Skyler Grey915067d2023-12-03 13:46:53 +0000119 homeserverUrl = "http://generic:1030";
Skyler Grey874a2a82023-06-08 12:29:28 +0200120
Skyler Grey22428b02023-11-19 13:20:56 +0000121 managementRoom = "#moderation-commands:clicks.codes";
Skyler Grey874a2a82023-06-08 12:29:28 +0200122 };
123
Skyler Grey8e32c832023-05-20 22:54:30 +0200124 sops.secrets = {
Skyler Grey7610ce42023-11-29 19:29:59 +0000125 matrix_sliding_sync_env = {
126 mode = "0600";
127 owner = config.users.users.root.name;
128 group = config.users.users.root.group;
129 sopsFile = ../../secrets/matrix_sliding_sync.env.bin;
130 format = "binary";
131 };
Skyler Grey22428b02023-11-19 13:20:56 +0000132 matrix_keycloak_client_secret = {
133 mode = "0400";
134 owner = config.users.users.matrix-synapse.name;
135 group = config.users.users.matrix-synapse.group;
136 sopsFile = ../../secrets/matrix.json;
137 format = "json";
138 };
Skyler Grey8e32c832023-05-20 22:54:30 +0200139 registration_shared_secret = {
Skyler Greya78aa672023-05-20 13:48:18 +0200140 mode = "0400";
Skyler Grey8e32c832023-05-20 22:54:30 +0200141 owner = config.users.users.root.name;
Skyler Greybcb46d32023-11-10 20:48:38 +0000142 group = config.users.users.root.group;
Samuel Shuertf68685d2023-10-28 20:07:56 -0400143 sopsFile = ../../secrets/matrix.json;
Skyler Grey8e32c832023-05-20 22:54:30 +0200144 format = "json";
145 };
146 matrix_private_key = {
147 mode = "0600";
148 owner = config.users.users.matrix-synapse.name;
149 group = config.users.users.matrix-synapse.group;
Samuel Shuertf68685d2023-10-28 20:07:56 -0400150 sopsFile = ../../secrets/matrix_private_key.pem;
Skyler Greya78aa672023-05-20 13:48:18 +0200151 format = "binary";
Skyler Grey8e32c832023-05-20 22:54:30 +0200152 path = config.services.matrix-synapse.settings.signing_key_path;
Skyler Greya78aa672023-05-20 13:48:18 +0200153 };
Skyler Grey083b1e32023-11-20 18:48:02 +0000154 mjolnir_password = {
Skyler Grey874a2a82023-06-08 12:29:28 +0200155 mode = "0600";
156 owner = config.users.users.mjolnir.name;
157 group = config.users.users.mjolnir.group;
Samuel Shuertf68685d2023-10-28 20:07:56 -0400158 sopsFile = ../../secrets/matrix.json;
Skyler Grey874a2a82023-06-08 12:29:28 +0200159 format = "json";
Skyler Grey083b1e32023-11-20 18:48:02 +0000160 };
Skyler Greya78aa672023-05-20 13:48:18 +0200161 };
Skyler Greyfae88b12023-12-03 12:02:49 +0000162
Skyler Grey915067d2023-12-03 13:46:53 +0000163 systemd.services.matrix-synapse.requires = [ "postgresql.service" "nginx.service" "keycloak.service" ];
Skyler Greyfae88b12023-12-03 12:02:49 +0000164
Skyler Greyfe1740c2023-10-21 01:24:18 +0000165} (let isDerived = base != null;
166in if isDerived
167# We cannot use mkIf as both sides are evaluated no matter the condition value
168# Given we use base as an attrset, mkIf will error if base is null in here
169then
170 let synapse_cfgfile = config.services.matrix-synapse.configFile;
171 in {
172 scalpel.trafos."synapse.yaml" = {
173 source = toString synapse_cfgfile;
174 matchers."registration_shared_secret".secret =
175 config.sops.secrets.registration_shared_secret.path;
Skyler Grey22428b02023-11-19 13:20:56 +0000176 matchers."matrix_keycloak_client_secret".secret =
177 config.sops.secrets.matrix_keycloak_client_secret.path;
Skyler Greyfe1740c2023-10-21 01:24:18 +0000178 owner = config.users.users.matrix-synapse.name;
179 group = config.users.users.matrix-synapse.group;
180 mode = "0400";
181 };
182
183 systemd.services.matrix-synapse.serviceConfig.ExecStart = lib.mkForce
184 (builtins.replaceStrings [ "${synapse_cfgfile}" ]
185 [ "${config.scalpel.trafos."synapse.yaml".destination}" ]
186 "${base.config.systemd.services.matrix-synapse.serviceConfig.ExecStart}");
187
188 systemd.services.matrix-synapse.preStart = lib.mkForce
189 (builtins.replaceStrings [ "${synapse_cfgfile}" ]
190 [ "${config.scalpel.trafos."synapse.yaml".destination}" ]
191 "${base.config.systemd.services.matrix-synapse.preStart}");
192
193 systemd.services.matrix-synapse.restartTriggers = [ synapse_cfgfile ];
194
195 environment.systemPackages = with lib;
Skyler Grey874a2a82023-06-08 12:29:28 +0200196 let
Skyler Greyfe1740c2023-10-21 01:24:18 +0000197 cfg = config.services.matrix-synapse;
198 registerNewMatrixUser = let
199 isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
200 listener = lib.findFirst (listener:
201 lib.any (resource: lib.any (name: name == "client") resource.names)
202 listener.resources) (lib.last cfg.settings.listeners)
203 cfg.settings.listeners;
204 # FIXME: Handle cases with missing client listener properly,
205 # don't rely on lib.last, this will not work.
Skyler Greya78aa672023-05-20 13:48:18 +0200206
Skyler Greyfe1740c2023-10-21 01:24:18 +0000207 # add a tail, so that without any bind_addresses we still have a useable address
208 bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]);
209 listenerProtocol = if listener.tls then "https" else "http";
210 in pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
211 exec ${cfg.package}/bin/register_new_matrix_user \
212 $@ \
213 ${
214 lib.concatMapStringsSep " " (x: "-c ${x}")
215 ([ config.scalpel.trafos."synapse.yaml".destination ]
216 ++ cfg.extraConfigFiles)
217 } \
218 "${listenerProtocol}://${
219 if (isIpv6 bindAddress) then
220 "[${bindAddress}]"
221 else
222 "${bindAddress}"
223 }:${builtins.toString listener.port}/"
224 '';
225 in [ (lib.meta.hiPrio registerNewMatrixUser) ];
226 }
227else
228 { })