{ config, lib, pkgs, ... }: with lib; let cfg = config.modules.services.matrix-bridge; in { imports = [ ./_mautrix-signal-module.nix ./_mautrix-discord-module.nix ]; options.modules.services.matrix-bridge = { enable = mkEnableOption "matrix-bridge"; domain = mkOption { type = types.str; }; realHost = mkOption { type = types.str; default = "matrix.${cfg.domain}"; }; secrets = { mautrix-envs = mkOption { type = types.path; description = "path to the mautrix-* environment file"; }; matrix-appservice-discord-envs = mkOption { type = types.path; description = "path to the matrix-appservice-discord environment file"; }; }; }; config = mkIf cfg.enable { sops.secrets.double-puppet-as-token = { }; sops.secrets.double-puppet-hs-token = { }; sops.templates."double-puppet-registration.yaml".content = '' id: doublepuppet url: as_token: ${config.sops.placeholder.double-puppet-as-token} hs_token: ${config.sops.placeholder.double-puppet-hs-token} sender_localpart: 55e126746dad19e50d9c4e646b6f5ac9ba21b346a24b840330cd8d8a1d65ce80 rate_limited: false namespaces: users: - regex: '@.*:exotic\.sh' exclusive: false ''; services.mautrix-telegram = { enable = true; environmentFile = cfg.secrets.mautrix-envs; serviceDependencies = [ "matrix-synapse.service" ]; settings = { homeserver.address = "https://${cfg.realHost}"; homeserver.domain = cfg.domain; homeserver.verify_ssl = true; appservice = { address = "http://localhost:29317"; hostname = "localhost"; port = 29317; database = "postgres:///mautrix-telegram?host=/run/postgresql"; bot_avatar = "mxc://maunium.net/tJCRmUyJDsgRNgqhOgoiHWbX"; id = "telegram"; max_body_size = 1; provisioning.enabled = false; }; bridge = { alias_template = "tg_{groupname}"; username_templace = "tg_{userid}"; allow_matrix_login = true; bot_messages_as_notices = true; catch_up = true; plaintext_highlights = true; startup_sync = true; animated_stickers = { target = "webp"; convert_from_webm = true; }; encryption = { allow = true; default = true; require = true; allow_key_sharing = true; }; # NOTE: python bridge - managed via env variable # login_shared_secret_map = { # "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN"; # }; permissions = { "@sef:exotic.sh" = "admin"; "exotic.sh" = "full"; }; }; }; }; services.mautrix-signal = { enable = true; package = pkgs.mautrix-signal; environmentFile = cfg.secrets.mautrix-envs; serviceDependencies = [ "matrix-synapse.service" ]; settings = { homeserver.address = "https://${cfg.realHost}"; homeserver.domain = cfg.domain; homeserver.verify_ssl = true; appservice = { address = "http://localhost:29318"; port = 29318; database = "postgres:///mautrix-signal?host=/run/postgresql"; bot_avatar = "mxc://maunium.net/wPJgTQbZOtpBFmDNkiNEMDUp"; id = "signal"; max_body_size = 1; provisioning.enabled = false; }; signal = { avatar_dir = "/var/lib/signald/avatars"; data_dir = "/var/lib/signald/data"; }; bridge = { alias_template = "sig_{groupname}"; username_templace = "sig_{userid}"; allow_matrix_login = true; catch_up = true; plaintext_highlights = true; startup_sync = true; animated_stickers = { target = "webp"; convert_from_webm = true; }; encryption = { allow = true; default = true; require = true; allow_key_sharing = true; }; login_shared_secret_map = { "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN"; }; permissions = { "@sef:exotic.sh" = "admin"; "exotic.sh" = "full"; }; }; }; }; services.mautrix-whatsapp = { enable = true; environmentFile = cfg.secrets.mautrix-envs; serviceDependencies = [ "matrix-synapse.service" ]; settings = { homeserver.address = "https://${cfg.realHost}"; homeserver.domain = cfg.domain; homeserver.verify_ssl = true; appservice = { address = "http://localhost:29319"; hostname = "localhost"; port = 29319; database = { type = "postgres"; uri = "postgres://mautrix-whatsapp:@/mautrix-whatsapp?host=/run/postgresql"; }; bot_avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr"; id = "whatsapp"; max_body_size = 1; provisioning.enabled = false; }; bridge = { alias_template = "wa_{groupname}"; username_templace = "wa_{userid}"; personal_filtering_spaces = true; delivery_receipts = true; identity_change_notices = true; history_sync = { backfill = false; # MSC2716 request_full_sync = true; }; send_presence_on_typing = true; double_puppet_server_map = { }; login_shared_secret_map = { "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN"; }; private_chat_portal_meta = true; mute_bridging = true; pinned_tag = "m.favourite"; archive_tag = "m.lowpriority"; allow_user_invite = true; disappearing_messages_in_groups = true; url_previews = true; encryption = { allow = true; default = true; require = true; allow_key_sharing = true; }; sync_manual_marked_unread = true; force_active_delivery_receipts = true; parallel_member_sync = true; extev_polls = true; send_whatsapp_edits = true; permissions = { "@sef:exotic.sh" = "admin"; "exotic.sh" = "full"; }; }; }; }; services.mautrix-discord = { enable = true; environmentFile = cfg.secrets.mautrix-envs; serviceDependencies = [ "matrix-synapse.service" ]; settings = { homeserver.address = "https://${cfg.realHost}"; homeserver.domain = cfg.domain; homeserver.verify_ssl = true; appservice = { address = "http://localhost:29320"; port = 29320; database = { type = "postgres"; uri = "postgres://mautrix-discord:@/mautrix-discord?host=/run/postgresql"; }; bot_avatar = "mxc://maunium.net/nIdEykemnwdisvHbpxflpDlC"; id = "discord"; max_body_size = 1; provisioning.enabled = false; }; bridge = { username_template = "dsc_{{.}}"; delivery_receipts = true; encryption = { allow = true; default = true; require = true; allow_key_sharing = true; }; login_shared_secret_map = { "${cfg.domain}" = "as_token:$DOUBLE_PUPPET_AS_TOKEN"; }; permissions = { "@sef:exotic.sh" = "admin"; "exotic.sh" = "full"; }; }; }; }; services.matrix-appservice-irc = { enable = true; registrationUrl = "http://localhost:29321"; port = 29321; settings = { homeserver.url = "https://${cfg.realHost}"; homeserver.domain = cfg.domain; homeserver.dropMatrixMessagesAfterSecs = 600; # 10 minutes database.engine = "postgres"; database.connectionString = "postgres://matrix-appservice-irc:@/matrix-appservice-irc?host=/run/postgresql"; ircService.servers = let # nix-community/nur-combined/repos/colinsane/hosts/by-name/servo/services/matrix/irc.nix@b2e96d5 ircServer = { name, additionalAddresses ? [], sasl ? true, port ? 6697}: let lowerName = lib.toLower name; in { inherit name additionalAddresses sasl port; ssl = true; # Disable bridging of Matrix bots botConfig.enabled = false; dynamicChannels = { enabled = true; aliasTemplate = "#irc_${lowerName}_$CHANNEL"; published = false; federate = false; }; ircClients = { nickTemplate = "$DISPLAY[m]"; allowNickChanges = true; realNameFormat = "reverse-mxid"; lineLimit = 20; # Safeguard: don't flood servers maxClients = 2; idleTimeout = 0; concurrentReconnectLimit = 2; reconnectIntervalMs = 60000; kickOn = { # only kick Matrix user from room when user quits channelJoinFailure = false; ircConnectionFailure = false; userQuit = true; }; }; matrixClients.userTemplate = "@irc_${lowerName}_$NICK"; "@sef:exotic.sh" = "admin"; memberShipLists = { enabled = true; # NOTE: when serving lots of Matrix users, these configs should # be changed to reduce strain on IRC servers global = { ircToMatrix = { initial = true; incremental = true; requireMatrixJoined = false; }; matrixToIrc = { initial = true; incremental = true; }; # always bridge users, even if idle ignoreIdleUsersOnStartup.enabled = false; }; bridgeInfoState = { enabled = true; initial = true; }; }; }; in { "irc.libera.chat" = ircServer { name = "libera"; # sasl = false; }; "irc.oftc.net" = ircServer { name = "oftc"; # sasl = false; }; }; }; }; services.matrix-appservice-discord = { enable = true; port = 29322; # NOTE: broken # localpart = ""; environmentFile = cfg.secrets.matrix-appservice-discord-envs; settings = { # NOTE: Specified in environmentFile # auth = { # botToken = ""; # clientID = ""; # }; auth.usePrivilegedIntents = true; database = { connString = "postgresql://matrix-appservice-discord?host=/run/postgresql"; filename = ""; }; bridge = { domain = cfg.domain; homeserverUrl = "https://${cfg.realHost}"; adminMxid = "@sef:exotic.sh"; enableSelfServiceBridging = true; disablePortalBridging = true; }; }; }; # HACK: https://github.com/NixOS/nixpkgs/issues/273929 systemd.services.matrix-appservice-irc.serviceConfig.SystemCallFilter = lib.mkForce '' @system-service @pkey ~@privileged @resources @chown ''; modules.persistence.directories = [ "/var/lib/private/mautrix-telegram" "/var/lib/private/mautrix-signal" "/var/lib/private/mautrix-whatsapp" "/var/lib/private/mautrix-discord" "/var/lib/matrix-appservice-irc" "/var/lib/matrix-appservice-discord" "/var/lib/signald" ]; modules.services.postgresql.enable = true; services.postgresql.ensureDatabases = [ "mautrix-telegram" "mautrix-signal" "mautrix-whatsapp" "mautrix-discord" "matrix-appservice-irc" "matrix-appservice-discord" ]; services.postgresql.ensureUsers = [ { name = "mautrix-telegram"; ensureDBOwnership = true; } { name = "mautrix-signal"; ensureDBOwnership = true; } { name = "mautrix-whatsapp"; ensureDBOwnership = true; } { name = "mautrix-discord"; ensureDBOwnership = true; } { name = "matrix-appservice-irc"; ensureDBOwnership = true; } { name = "matrix-appservice-discord"; ensureDBOwnership = true; } ]; systemd.services.matrix-synapse.serviceConfig.LoadCredential = [ "mautrix-telegram:/var/lib/mautrix-telegram/telegram-registration.yaml" "mautrix-signal:/var/lib/mautrix-signal/signal-registration.yaml" "mautrix-whatsapp:/var/lib/mautrix-whatsapp/whatsapp-registration.yaml" "mautrix-discord:/var/lib/mautrix-discord/discord-registration.yaml" "double-puppet:${config.sops.templates."double-puppet-registration.yaml".path}" "appservice-irc:/var/lib/matrix-appservice-irc/registration.yml" "appservice-discord:/var/lib/matrix-appservice-discord/discord-registration.yaml" ]; services.matrix-synapse.settings.app_service_config_files = [ "/run/credentials/matrix-synapse.service/mautrix-telegram" "/run/credentials/matrix-synapse.service/mautrix-signal" "/run/credentials/matrix-synapse.service/mautrix-whatsapp" "/run/credentials/matrix-synapse.service/mautrix-discord" "/run/credentials/matrix-synapse.service/double-puppet" "/run/credentials/matrix-synapse.service/appservice-irc" "/run/credentials/matrix-synapse.service/appservice-discord" ]; }; }