This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

services.matrix: add MatrixZulipBridge

Bridge Matrix to Zulip via GearKite/MatrixZulipBridge (packaged in nixpkgs
as matrix-zulip-bridge). No upstream NixOS module exists, so the systemd
service mirrors the heisenbridge module it is forked from: generate the
registration, merge in the tokens, and wire it into Synapse. Zulip orgs
(e.g. zulip.geninf.io) are configured at runtime via the bridge admin room.

Assisted-by: Claude Code (claude-opus-4-8[1m])

+139
+1
machines/neoprism/config.nix
··· 20 20 ../../2configs/services/matrix/bridges/heisenbridge.nix 21 21 ../../2configs/services/matrix/bridges/mautrix-telegram.nix 22 22 ../../2configs/services/matrix/bridges/mautrix-discord.nix 23 + ../../2configs/services/matrix/bridges/matrix-zulip-bridge.nix 23 24 24 25 ../../2configs/services/pad 25 26
+138
2configs/services/matrix/bridges/matrix-zulip-bridge.nix
··· 1 + { pkgs, lib, ... }: 2 + let 3 + pkg = pkgs.matrix-zulip-bridge; 4 + bin = lib.getExe pkg; 5 + 6 + address = "127.0.0.1"; 7 + port = 28464; 8 + homeserver = "http://[::1]:8008"; 9 + owner = "@lassulus:lassul.us"; 10 + 11 + registrationFile = "/var/lib/matrix-zulip-bridge/registration.yml"; 12 + 13 + # JSON is a proper subset of YAML. We render our desired registration and 14 + # merge in the tokens from the bridge-generated file in preStart, mirroring 15 + # the upstream heisenbridge module (this bridge shares its architecture). 16 + bridgeConfig = builtins.toFile "matrix-zulip-bridge-registration.yml" ( 17 + builtins.toJSON { 18 + id = "zulipbridge"; 19 + url = "http://${address}:${toString port}"; 20 + rate_limited = false; 21 + sender_localpart = "zulipbridge"; 22 + namespaces = { 23 + users = [ 24 + { 25 + regex = "@zulip_.*:lassul\\.us"; 26 + exclusive = true; 27 + } 28 + { 29 + regex = "@zulipbridge:lassul\\.us"; 30 + exclusive = true; 31 + } 32 + ]; 33 + aliases = [ ]; 34 + rooms = [ ]; 35 + }; 36 + } 37 + ); 38 + in 39 + { 40 + systemd.services.matrix-zulip-bridge = { 41 + description = "Matrix<->Zulip bridge"; 42 + before = [ "matrix-synapse.service" ]; # So the registration file can be used by Synapse 43 + wantedBy = [ "multi-user.target" ]; 44 + 45 + preStart = '' 46 + umask 077 47 + set -e -u -o pipefail 48 + 49 + if ! [ -f "${registrationFile}" ]; then 50 + # Generate registration file if not present (we only care about the tokens in it) 51 + ${bin} --generate --config ${registrationFile} 52 + fi 53 + 54 + # Overwrite the registration file with our generated one (the config may have 55 + # changed since then), but keep the tokens. Two step procedure to be failure safe. 56 + ${pkgs.yq}/bin/yq --slurp \ 57 + '.[0] + (.[1] | {as_token, hs_token})' \ 58 + ${bridgeConfig} \ 59 + ${registrationFile} \ 60 + > ${registrationFile}.new 61 + mv -f ${registrationFile}.new ${registrationFile} 62 + 63 + # Grant Synapse access to the registration 64 + if ${pkgs.getent}/bin/getent group matrix-synapse > /dev/null; then 65 + chgrp -v matrix-synapse ${registrationFile} 66 + chmod -v g+r ${registrationFile} 67 + fi 68 + ''; 69 + 70 + serviceConfig = { 71 + Type = "simple"; 72 + ExecStart = lib.concatStringsSep " " [ 73 + bin 74 + "-v" 75 + "--config" 76 + registrationFile 77 + "--listen-address" 78 + (lib.escapeShellArg address) 79 + "--listen-port" 80 + (toString port) 81 + "--owner" 82 + (lib.escapeShellArg owner) 83 + (lib.escapeShellArg homeserver) 84 + ]; 85 + 86 + # Hardening options (mirrors upstream heisenbridge module) 87 + User = "matrix-zulip-bridge"; 88 + Group = "matrix-zulip-bridge"; 89 + RuntimeDirectory = "matrix-zulip-bridge"; 90 + RuntimeDirectoryMode = "0700"; 91 + StateDirectory = "matrix-zulip-bridge"; 92 + StateDirectoryMode = "0755"; 93 + 94 + ProtectSystem = "strict"; 95 + ProtectHome = true; 96 + PrivateTmp = true; 97 + PrivateDevices = true; 98 + ProtectKernelTunables = true; 99 + ProtectControlGroups = true; 100 + RestrictSUIDSGID = true; 101 + PrivateMounts = true; 102 + ProtectKernelModules = true; 103 + ProtectKernelLogs = true; 104 + ProtectHostname = true; 105 + ProtectClock = true; 106 + ProtectProc = "invisible"; 107 + ProcSubset = "pid"; 108 + RestrictNamespaces = true; 109 + RemoveIPC = true; 110 + UMask = "0077"; 111 + 112 + CapabilityBoundingSet = [ "CAP_CHOWN" ]; 113 + AmbientCapabilities = [ "CAP_CHOWN" ]; 114 + NoNewPrivileges = true; 115 + LockPersonality = true; 116 + RestrictRealtime = true; 117 + SystemCallFilter = [ 118 + "@system-service" 119 + "~@privileged" 120 + "@chown" 121 + ]; 122 + SystemCallArchitectures = "native"; 123 + RestrictAddressFamilies = "AF_INET AF_INET6"; 124 + }; 125 + }; 126 + 127 + # Wire the registration into Synapse (merges with the other bridges' lists). 128 + services.matrix-synapse.settings.app_service_config_files = [ 129 + registrationFile 130 + ]; 131 + 132 + users.groups.matrix-zulip-bridge = { }; 133 + users.users.matrix-zulip-bridge = { 134 + description = "Service user for the Matrix Zulip bridge"; 135 + group = "matrix-zulip-bridge"; 136 + isSystemUser = true; 137 + }; 138 + }