zaphyra's git: tgcNUR

fork of https://git.transgirl.cafe/zaphoid/tgc-nix-user-repository

commit cbe37317aaa73bda49bd7194b226beda1fd06a8b
parent 7bf2e9c19c8633a06f0d035a4867feebc99af1fb
Author: Katja Ramona Sophie Kwast (zaphyra) <git@zaphyra.eu>
Date: Tue, 19 Aug 2025 13:28:12 +0200

nixosModules: add `mautrixBridge`
1 file changed, 155 insertions(+), 0 deletions(-)
A
nixosModules/services/mautrixBridge/default.nix
|
155
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/nixosModules/services/mautrixBridge/default.nix b/nixosModules/services/mautrixBridge/default.nix
@@ -0,0 +1,155 @@
+{ ... }:
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+
+let
+  inherit (lib) types;
+  cfg = config.tgc.services.mautrixBridge;
+  forEachInstance =
+    f: lib.flip lib.mapAttrs' cfg (name: cfg: lib.nameValuePair "mautrixBridge-${name}" (f name cfg));
+
+in
+{
+
+  # todo: add some documentation
+  options.tgc.services.mautrixBridge = lib.mkOption {
+    default = { };
+    type = types.attrsOf (
+      types.submodule {
+        options = {
+          enable = lib.mkOption {
+            type = types.bool;
+            default = false;
+          };
+          package = lib.mkOption {
+            type = types.package;
+          };
+          settings = lib.mkOption {
+            type = (pkgs.formats.json { }).type;
+            default = { };
+          };
+          environmentFile = lib.mkOption {
+            type = with types; nullOr path;
+            default = null;
+          };
+          serviceDependencies = lib.mkOption {
+            type = with types; listOf str;
+            default = [ ];
+          };
+        };
+      }
+    );
+  };
+
+  config = {
+    modules.filesystem.impermanence.system.dirs = (
+      (lib.attrNames cfg) |> lib.map (element: "/var/lib/private/mautrix-${element}")
+    );
+
+    systemd.services = forEachInstance (
+      name: cfg:
+      let
+        dataDir = "/var/lib/mautrix-${name}";
+        registrationFile = "${dataDir}/registration.yaml";
+        settingsFile = "${dataDir}/config.yaml";
+        settingsFileUnsubstituted =
+          (pkgs.formats.json { }).generate "mautrix-${name}-config-unsubstituted.json"
+            cfg.settings;
+      in
+      {
+        enable = cfg.enable;
+        description = "mautrixBridge-${name}, a matrix puppeting bridge.";
+        restartTriggers = [ settingsFileUnsubstituted ];
+
+        wantedBy = [ "multi-user.target" ];
+        wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
+        after = [ "network-online.target" ] ++ cfg.serviceDependencies;
+
+        path = [ pkgs.ffmpeg-headless ];
+
+        preStart = ''
+          # substitute the settings file by environment variables
+          # in this case read from EnvironmentFile
+          test -f '${settingsFile}' && rm -f '${settingsFile}'
+          old_umask=$(umask)
+          umask 0177
+          ${pkgs.envsubst}/bin/envsubst \
+            -o '${settingsFile}' \
+            -i '${settingsFileUnsubstituted}'
+          umask $old_umask
+
+          # generate the appservice's registration file if absent
+          if [ ! -f '${registrationFile}' ]; then
+            ${lib.getExe cfg.package} \
+              --generate-registration \
+              --config='${settingsFile}' \
+              --registration='${registrationFile}'
+          fi
+          chmod 640 ${registrationFile}
+
+          umask 0177
+          #todo: switch to `yq-go`
+          ${lib.getExe pkgs.yq} -s '
+              .[0].appservice.as_token = (.[0].appservice.as_token // .[1].as_token)
+            | .[0].appservice.hs_token = (.[0].appservice.hs_token // .[1].hs_token)
+          ${lib.optionalString (
+            name == "telegram"
+          ) "
+          | .[0].network.api_id = (.[0].network.api_id | tonumber)
+        "}
+            | .[0]' \
+            '${settingsFile}' '${registrationFile}' > '${settingsFile}.tmp'
+          mv '${settingsFile}.tmp' '${settingsFile}'
+          umask $old_umask
+        '';
+
+        serviceConfig = {
+          Type = "exec";
+
+          DynamicUser = true;
+          User = "mautrixBridge-${name}";
+          Group = "mautrixBridge-${name}";
+
+          EnvironmentFile = cfg.environmentFile;
+          StateDirectory = baseNameOf dataDir;
+          WorkingDirectory = dataDir;
+          UMask = 27;
+
+          ExecStart = "${lib.getExe cfg.package} --no-update --config='${settingsFile}'";
+
+          Restart = "on-failure";
+          RestartSec = "30s";
+
+          LockPersonality = true;
+          NoNewPrivileges = true;
+          MemoryDenyWriteExecute = lib.mkIf (name != "signal") true;
+
+          PrivateDevices = true;
+          PrivateTmp = true;
+          PrivateUsers = true;
+
+          ProtectSystem = "strict";
+          ProtectClock = true;
+          ProtectHome = true;
+          ProtectHostname = true;
+          ProtectKernelLogs = true;
+          ProtectKernelModules = true;
+          ProtectKernelTunables = true;
+          ProtectControlGroups = true;
+
+          RestrictRealtime = true;
+          RestrictSUIDSGID = true;
+
+          SystemCallArchitectures = "native";
+          SystemCallErrorNumber = "EPERM";
+          SystemCallFilter = [ "@system-service" ];
+        };
+      }
+    );
+  };
+
+}