1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 cfg = config.services.signald;
9 dataDir = "/var/lib/signald";
10 defaultUser = "signald";
11in
12{
13 options.services.signald = {
14 enable = lib.mkEnableOption "signald, the unofficial daemon for interacting with Signal";
15
16 user = lib.mkOption {
17 type = lib.types.str;
18 default = defaultUser;
19 description = "User under which signald runs.";
20 };
21
22 group = lib.mkOption {
23 type = lib.types.str;
24 default = defaultUser;
25 description = "Group under which signald runs.";
26 };
27
28 socketPath = lib.mkOption {
29 type = lib.types.str;
30 default = "/run/signald/signald.sock";
31 description = "Path to the signald socket";
32 };
33 };
34
35 config = lib.mkIf cfg.enable {
36 users.users = lib.optionalAttrs (cfg.user == defaultUser) {
37 ${defaultUser} = {
38 group = cfg.group;
39 isSystemUser = true;
40 };
41 };
42
43 users.groups = lib.optionalAttrs (cfg.group == defaultUser) {
44 ${defaultUser} = { };
45 };
46
47 systemd.services.signald = {
48 description = "A daemon for interacting with the Signal Private Messenger";
49 wants = [ "network.target" ];
50 wantedBy = [ "multi-user.target" ];
51 after = [ "network.target" ];
52
53 serviceConfig = {
54 User = cfg.user;
55 Group = cfg.group;
56 ExecStart = "${pkgs.signald}/bin/signald -d ${dataDir} -s ${cfg.socketPath}";
57 ExecStartPre = "${pkgs.signald}/bin/signald -d ${dataDir} -s ${cfg.socketPath} --migrate-data";
58 Restart = "on-failure";
59 StateDirectory = "signald";
60 RuntimeDirectory = "signald";
61 StateDirectoryMode = "0750";
62 RuntimeDirectoryMode = "0750";
63
64 BindReadOnlyPaths = [
65 "/nix/store"
66 "-/etc/resolv.conf"
67 "-/etc/nsswitch.conf"
68 "-/etc/hosts"
69 "-/etc/localtime"
70 ];
71 CapabilityBoundingSet = "";
72 # ProtectClock= adds DeviceAllow=char-rtc r
73 DeviceAllow = "";
74 # Use a static user so other applications can access the files
75 #DynamicUser = true;
76 LockPersonality = true;
77 # Needed for java
78 #MemoryDenyWriteExecute = true;
79 NoNewPrivileges = true;
80 PrivateDevices = true;
81 PrivateMounts = true;
82 # Needs network access
83 #PrivateNetwork = true;
84 PrivateTmp = true;
85 PrivateUsers = true;
86 ProcSubset = "pid";
87 ProtectClock = true;
88 ProtectHome = true;
89 ProtectHostname = true;
90 # Would re-mount paths ignored by temporary root
91 #ProtectSystem = "strict";
92 ProtectControlGroups = true;
93 ProtectKernelLogs = true;
94 ProtectKernelModules = true;
95 ProtectKernelTunables = true;
96 ProtectProc = "invisible";
97 RestrictAddressFamilies = [
98 "AF_INET"
99 "AF_INET6"
100 "AF_UNIX"
101 ];
102 RestrictNamespaces = true;
103 RestrictRealtime = true;
104 RestrictSUIDSGID = true;
105 SystemCallArchitectures = "native";
106 SystemCallFilter = [
107 "@system-service"
108 "~@privileged @resources @setuid @keyring"
109 ];
110 TemporaryFileSystem = "/:ro";
111 # Does not work well with the temporary root
112 #UMask = "0066";
113 };
114 };
115 };
116}