python312Packages.dissect-extfs: 3.11 -> 3.12
[NixPkgs.git] / nixos / modules / services / home-automation / zwave-js.nix
blob4ce7926242697938a692e4eedc5cd5e95ec07389
1 {config, pkgs, lib, ...}:
2 let
3   cfg = config.services.zwave-js;
4   mergedConfigFile = "/run/zwave-js/config.json";
5   settingsFormat = pkgs.formats.json {};
6 in {
7   options.services.zwave-js = {
8     enable = lib.mkEnableOption "the zwave-js server on boot";
10     package = lib.mkPackageOption pkgs "zwave-js-server" { };
12     port = lib.mkOption {
13       type = lib.types.port;
14       default = 3000;
15       description = ''
16         Port for the server to listen on.
17       '';
18     };
20     serialPort = lib.mkOption {
21       type = lib.types.path;
22       description = ''
23         Serial port device path for Z-Wave controller.
24       '';
25       example = "/dev/ttyUSB0";
26     };
28     secretsConfigFile = lib.mkOption {
29       type = lib.types.path;
30       description = ''
31         JSON file containing secret keys. A dummy example:
33         ```
34         {
35           "securityKeys": {
36             "S0_Legacy": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
37             "S2_Unauthenticated": "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
38             "S2_Authenticated": "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC",
39             "S2_AccessControl": "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"
40           }
41         }
42         ```
44         See
45         <https://zwave-js.github.io/node-zwave-js/#/getting-started/security-s2>
46         for details. This file will be merged with the module-generated config
47         file (taking precedence).
49         Z-Wave keys can be generated with:
51           {command}`< /dev/urandom tr -dc A-F0-9 | head -c32 ;echo`
54         ::: {.warning}
55         A file in the nix store should not be used since it will be readable to
56         all users.
57         :::
58       '';
59       example = "/secrets/zwave-js-keys.json";
60     };
62     settings = lib.mkOption {
63       type = lib.types.submodule {
64         freeformType = settingsFormat.type;
66         options = {
67           storage = {
68             cacheDir = lib.mkOption {
69               type = lib.types.path;
70               default = "/var/cache/zwave-js";
71               readOnly = true;
72               description = "Cache directory";
73             };
74           };
75         };
76       };
77       default = {};
78       description = ''
79         Configuration settings for the generated config
80         file.
81       '';
82     };
84     extraFlags = lib.mkOption {
85       type = with lib.types; listOf str;
86       default = [ ];
87       example = [ "--mock-driver" ];
88       description = ''
89         Extra flags to pass to command
90       '';
91     };
92   };
94   config = lib.mkIf cfg.enable {
95     systemd.services.zwave-js = let
96       configFile = settingsFormat.generate "zwave-js-config.json" cfg.settings;
97     in {
98       wantedBy = [ "multi-user.target" ];
99       after = [ "network.target" ];
100       description = "Z-Wave JS Server";
101       serviceConfig = {
102         ExecStartPre = ''
103           /bin/sh -c "${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${configFile} ${cfg.secretsConfigFile} > ${mergedConfigFile}"
104         '';
105         ExecStart = lib.concatStringsSep " " [
106           "${cfg.package}/bin/zwave-server"
107           "--config ${mergedConfigFile}"
108           "--port ${toString cfg.port}"
109           cfg.serialPort
110           (lib.escapeShellArgs cfg.extraFlags)
111         ];
112         Restart = "on-failure";
113         User = "zwave-js";
114         SupplementaryGroups = [ "dialout" ];
115         CacheDirectory = "zwave-js";
116         RuntimeDirectory = "zwave-js";
118         # Hardening
119         CapabilityBoundingSet = "";
120         DeviceAllow = [cfg.serialPort];
121         DevicePolicy = "closed";
122         DynamicUser = true;
123         LockPersonality = true;
124         MemoryDenyWriteExecute = false;
125         NoNewPrivileges = true;
126         PrivateUsers = true;
127         PrivateTmp = true;
128         ProtectClock = true;
129         ProtectControlGroups = true;
130         ProtectHome = true;
131         ProtectHostname = true;
132         ProtectKernelLogs = true;
133         ProtectKernelModules = true;
134         RemoveIPC = true;
135         RestrictNamespaces = true;
136         RestrictRealtime = true;
137         RestrictSUIDSGID = true;
138         SystemCallArchitectures = "native";
139         SystemCallFilter = [
140           "@system-service @pkey"
141           "~@privileged @resources"
142         ];
143         UMask = "0077";
144       };
145     };
146   };
148   meta.maintainers = with lib.maintainers; [ graham33 ];