katja's git: nixfiles

ctucx' nixfiles

1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
{ config, lib, pkgs, ... }:

let
  forEachInstance =
    f:
    lib.flip lib.mapAttrs' config.services.mautrix-bridge (
      name: cfg: lib.nameValuePair "mautrix-bridge-${name}" (f name cfg)
    );

in {

  options.services.mautrix-bridge = lib.mkOption {
    default = {};
    type    = lib.types.attrsOf (
      lib.types.submodule ({
        options = {
          package             = lib.mkOption { type = lib.types.package; };
          settings            = lib.mkOption { type = (pkgs.formats.json {}).type; default = {}; };
          environmentFile     = lib.mkOption { type = lib.types.nullOr lib.types.path; default = null; };
          serviceDependencies = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; };
        };
      })
    );
  };

  config.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 {
    description     = "mautrix-bridge-${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
      ${pkgs.yq}/bin/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  = "mautrix-bridge-${name}";
      Group = "mautrix-bridge-${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" ];
    };
  });

}