blob: 015c3f4eddce643ddccb0f0f5443f00cba764cd1 [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 Grey6f9047d2023-12-23 00:03:53 +0000163 systemd.services.matrix-synapse.requires = [ "postgresql.service" ];
164 systemd.services.matrix-synapse.after = [ "nginx.service" "keycloak.service" ];
Skyler Greyfae88b12023-12-03 12:02:49 +0000165
Skyler Greyfe1740c2023-10-21 01:24:18 +0000166} (let isDerived = base != null;
167in if isDerived
168# We cannot use mkIf as both sides are evaluated no matter the condition value
169# Given we use base as an attrset, mkIf will error if base is null in here
170then
171 let synapse_cfgfile = config.services.matrix-synapse.configFile;
172 in {
173 scalpel.trafos."synapse.yaml" = {
174 source = toString synapse_cfgfile;
175 matchers."registration_shared_secret".secret =
176 config.sops.secrets.registration_shared_secret.path;
Skyler Grey22428b02023-11-19 13:20:56 +0000177 matchers."matrix_keycloak_client_secret".secret =
178 config.sops.secrets.matrix_keycloak_client_secret.path;
Skyler Greyfe1740c2023-10-21 01:24:18 +0000179 owner = config.users.users.matrix-synapse.name;
180 group = config.users.users.matrix-synapse.group;
181 mode = "0400";
182 };
183
184 systemd.services.matrix-synapse.serviceConfig.ExecStart = lib.mkForce
185 (builtins.replaceStrings [ "${synapse_cfgfile}" ]
186 [ "${config.scalpel.trafos."synapse.yaml".destination}" ]
187 "${base.config.systemd.services.matrix-synapse.serviceConfig.ExecStart}");
188
189 systemd.services.matrix-synapse.preStart = lib.mkForce
Skyler Grey6f9047d2023-12-23 00:03:53 +0000190 ("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 +0000191 (builtins.replaceStrings [ "${synapse_cfgfile}" ]
192 [ "${config.scalpel.trafos."synapse.yaml".destination}" ]
Skyler Grey6f9047d2023-12-23 00:03:53 +0000193 "${base.config.systemd.services.matrix-synapse.preStart}"));
Skyler Greyfe1740c2023-10-21 01:24:18 +0000194
195 systemd.services.matrix-synapse.restartTriggers = [ synapse_cfgfile ];
196
197 environment.systemPackages = with lib;
Skyler Grey874a2a82023-06-08 12:29:28 +0200198 let
Skyler Greyfe1740c2023-10-21 01:24:18 +0000199 cfg = config.services.matrix-synapse;
200 registerNewMatrixUser = let
201 isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
202 listener = lib.findFirst (listener:
203 lib.any (resource: lib.any (name: name == "client") resource.names)
204 listener.resources) (lib.last cfg.settings.listeners)
205 cfg.settings.listeners;
206 # FIXME: Handle cases with missing client listener properly,
207 # don't rely on lib.last, this will not work.
Skyler Greya78aa672023-05-20 13:48:18 +0200208
Skyler Greyfe1740c2023-10-21 01:24:18 +0000209 # add a tail, so that without any bind_addresses we still have a useable address
210 bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]);
211 listenerProtocol = if listener.tls then "https" else "http";
212 in pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
213 exec ${cfg.package}/bin/register_new_matrix_user \
214 $@ \
215 ${
216 lib.concatMapStringsSep " " (x: "-c ${x}")
217 ([ config.scalpel.trafos."synapse.yaml".destination ]
218 ++ cfg.extraConfigFiles)
219 } \
220 "${listenerProtocol}://${
221 if (isIpv6 bindAddress) then
222 "[${bindAddress}]"
223 else
224 "${bindAddress}"
225 }:${builtins.toString listener.port}/"
226 '';
227 in [ (lib.meta.hiPrio registerNewMatrixUser) ];
228 }
229else
230 { })