blob: 26b2c2672898b10f4a3f31d0d74e714137e4e122 [file] [log] [blame]
{ base, config, lib, pkgs, ... }:
lib.recursiveUpdate {
services.matrix-synapse = {
enable = true;
withJemalloc = true;
plugins = with config.services.matrix-synapse.package.plugins;
[ matrix-synapse-mjolnir-antispam ];
settings = rec {
server_name = "clicks.codes";
auto_join_rooms = [ "#general:${server_name}" ];
enable_registration = true;
registration_requires_token = true;
allow_public_rooms_over_federation = true;
allow_device_name_lookup_over_federation = true;
registration_shared_secret = "!!registration_shared_secret!!";
public_baseurl = "https://matrix-backend.clicks.codes/";
max_upload_size = "100M";
listeners = [{
x_forwarded = true;
tls = false;
resources = [{
names = [ "client" "federation" ];
compress = true;
}];
port = 1030;
bind_addresses = [ "generic" ];
}];
enable_metrics = true;
database.args.database = "synapse";
oidc_providers = [
{
idp_id = "keycloak";
idp_name = "Clicks Keycloak";
issuer = "https://login.clicks.codes/realms/master";
client_id = "matrix";
client_secret = "!!matrix_keycloak_client_secret!!";
scopes = [ "openid" "profile" ];
user_mapping_provider = {
config = {
localpart_template = "{{ user.preferred_username }}";
display_name_template = "{{ user.name }}";
};
};
backchannel_logout_enabled = true;
}
];
log_config = lib.pipe {
version = 1;
formatters = {
precise = {
format =
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
};
};
handlers = {
console = {
class = "logging.StreamHandler";
formatter = "precise";
};
};
loggers = { "synapse.storage.SQL" = { level = "WARNING"; }; };
root = {
level = "ERROR";
handlers = [ "console" ];
};
"disable_existing_loggers" = false;
} [ builtins.toJSON (builtins.toFile "logcfg.yaml") ];
server_notices = {
system_mxid_localpart = "system";
system_mxid_display_name = "Clicks Administrators";
room_name = "Announcements";
};
};
sliding-sync = {
enable = true;
settings = {
SYNCV3_SERVER = "https://matrix-backend.clicks.codes";
SYNCV3_BINDADDR = "generic:1031";
SYNCV3_LOG_LEVEL = "warn";
};
environmentFile = config.sops.secrets.matrix_sliding_sync_env.path;
createDatabase = true;
};
};
networking.firewall.allowedTCPPorts = [ 3478 5349 ];
networking.firewall.allowedUDPPorts = [ 3478 5349 ];
services.mjolnir = {
enable = true;
settings = {
autojoinOnlyIfManager = true;
automaticallyRedactForReasons =
[ "nsfw" "gore" "spam" "harassment" "hate" ];
recordIgnoredInvites = true;
admin.enableMakeRoomAdminCommand = true;
allowNoPrefix = true;
protections.wordlist.words = [ ];
protectedRooms = [ "https://matrix.to/#/#global:clicks.codes" ];
};
pantalaimon = {
enable = true;
username = "system";
passwordFile = config.sops.secrets.mjolnir_password.path;
options = {
ssl = false;
listenAddress = "127.0.0.1";
};
};
homeserverUrl = "http://generic:1030";
managementRoom = "#moderation-commands:clicks.codes";
};
sops.secrets = {
matrix_sliding_sync_env = {
mode = "0600";
owner = config.users.users.root.name;
group = config.users.users.root.group;
sopsFile = ../../secrets/matrix_sliding_sync.env.bin;
format = "binary";
};
matrix_keycloak_client_secret = {
mode = "0400";
owner = config.users.users.matrix-synapse.name;
group = config.users.users.matrix-synapse.group;
sopsFile = ../../secrets/matrix.json;
format = "json";
};
registration_shared_secret = {
mode = "0400";
owner = config.users.users.root.name;
group = config.users.users.root.group;
sopsFile = ../../secrets/matrix.json;
format = "json";
};
matrix_private_key = {
mode = "0600";
owner = config.users.users.matrix-synapse.name;
group = config.users.users.matrix-synapse.group;
sopsFile = ../../secrets/matrix_private_key.pem;
format = "binary";
path = config.services.matrix-synapse.settings.signing_key_path;
};
mjolnir_password = {
mode = "0600";
owner = config.users.users.mjolnir.name;
group = config.users.users.mjolnir.group;
sopsFile = ../../secrets/matrix.json;
format = "json";
};
};
systemd.services.matrix-synapse.requires = [ "postgresql.service" "nginx.service" "keycloak.service" ];
} (let isDerived = base != null;
in if isDerived
# We cannot use mkIf as both sides are evaluated no matter the condition value
# Given we use base as an attrset, mkIf will error if base is null in here
then
let synapse_cfgfile = config.services.matrix-synapse.configFile;
in {
scalpel.trafos."synapse.yaml" = {
source = toString synapse_cfgfile;
matchers."registration_shared_secret".secret =
config.sops.secrets.registration_shared_secret.path;
matchers."matrix_keycloak_client_secret".secret =
config.sops.secrets.matrix_keycloak_client_secret.path;
owner = config.users.users.matrix-synapse.name;
group = config.users.users.matrix-synapse.group;
mode = "0400";
};
systemd.services.matrix-synapse.serviceConfig.ExecStart = lib.mkForce
(builtins.replaceStrings [ "${synapse_cfgfile}" ]
[ "${config.scalpel.trafos."synapse.yaml".destination}" ]
"${base.config.systemd.services.matrix-synapse.serviceConfig.ExecStart}");
systemd.services.matrix-synapse.preStart = lib.mkForce
(builtins.replaceStrings [ "${synapse_cfgfile}" ]
[ "${config.scalpel.trafos."synapse.yaml".destination}" ]
"${base.config.systemd.services.matrix-synapse.preStart}");
systemd.services.matrix-synapse.restartTriggers = [ synapse_cfgfile ];
environment.systemPackages = with lib;
let
cfg = config.services.matrix-synapse;
registerNewMatrixUser = let
isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
listener = lib.findFirst (listener:
lib.any (resource: lib.any (name: name == "client") resource.names)
listener.resources) (lib.last cfg.settings.listeners)
cfg.settings.listeners;
# FIXME: Handle cases with missing client listener properly,
# don't rely on lib.last, this will not work.
# add a tail, so that without any bind_addresses we still have a useable address
bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]);
listenerProtocol = if listener.tls then "https" else "http";
in pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
exec ${cfg.package}/bin/register_new_matrix_user \
$@ \
${
lib.concatMapStringsSep " " (x: "-c ${x}")
([ config.scalpel.trafos."synapse.yaml".destination ]
++ cfg.extraConfigFiles)
} \
"${listenerProtocol}://${
if (isIpv6 bindAddress) then
"[${bindAddress}]"
else
"${bindAddress}"
}:${builtins.toString listener.port}/"
'';
in [ (lib.meta.hiPrio registerNewMatrixUser) ];
}
else
{ })