vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / networking / resilio.nix
blob02773d78b13285b7eca18bc30a492d032f3f58a7
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.resilio;
8   resilioSync = pkgs.resilio-sync;
10   sharedFoldersRecord = map (entry: {
11     dir = entry.directory;
13     use_relay_server = entry.useRelayServer;
14     use_tracker = entry.useTracker;
15     use_dht = entry.useDHT;
17     search_lan = entry.searchLAN;
18     use_sync_trash = entry.useSyncTrash;
19     known_hosts = entry.knownHosts;
20   }) cfg.sharedFolders;
22   configFile = pkgs.writeText "config.json" (builtins.toJSON ({
23     device_name = cfg.deviceName;
24     storage_path = cfg.storagePath;
25     listening_port = cfg.listeningPort;
26     use_gui = false;
27     check_for_updates = cfg.checkForUpdates;
28     use_upnp = cfg.useUpnp;
29     download_limit = cfg.downloadLimit;
30     upload_limit = cfg.uploadLimit;
31     lan_encrypt_data = cfg.encryptLAN;
32   } // optionalAttrs (cfg.directoryRoot != "") { directory_root = cfg.directoryRoot; }
33     // optionalAttrs cfg.enableWebUI {
34     webui = { listen = "${cfg.httpListenAddr}:${toString cfg.httpListenPort}"; } //
35       (optionalAttrs (cfg.httpLogin != "") { login = cfg.httpLogin; }) //
36       (optionalAttrs (cfg.httpPass != "") { password = cfg.httpPass; }) //
37       (optionalAttrs (cfg.apiKey != "") { api_key = cfg.apiKey; });
38   } // optionalAttrs (sharedFoldersRecord != []) {
39     shared_folders = sharedFoldersRecord;
40   }));
42   sharedFoldersSecretFiles = map (entry: {
43     dir = entry.directory;
44     secretFile = if builtins.hasAttr "secret" entry then
45       toString (pkgs.writeTextFile {
46         name = "secret-file";
47         text = entry.secret;
48       })
49     else
50       entry.secretFile;
51   }) cfg.sharedFolders;
53   runConfigPath = "/run/rslsync/config.json";
55   createConfig = pkgs.writeShellScriptBin "create-resilio-config" (
56     if cfg.sharedFolders != [ ] then ''
57       ${pkgs.jq}/bin/jq \
58         '.shared_folders |= map(.secret = $ARGS.named[.dir])' \
59         ${
60           lib.concatMapStringsSep " \\\n  "
61           (entry: ''--arg '${entry.dir}' "$(cat '${entry.secretFile}')"'')
62           sharedFoldersSecretFiles
63         } \
64         <${configFile} \
65         >${runConfigPath}
66     '' else ''
67       # no secrets, passing through config
68       cp ${configFile} ${runConfigPath};
69     ''
70   );
74   options = {
75     services.resilio = {
76       enable = mkOption {
77         type = types.bool;
78         default = false;
79         description = ''
80           If enabled, start the Resilio Sync daemon. Once enabled, you can
81           interact with the service through the Web UI, or configure it in your
82           NixOS configuration.
83         '';
84       };
86       deviceName = mkOption {
87         type = types.str;
88         example = "Voltron";
89         default = config.networking.hostName;
90         defaultText = literalExpression "config.networking.hostName";
91         description = ''
92           Name of the Resilio Sync device.
93         '';
94       };
96       listeningPort = mkOption {
97         type = types.int;
98         default = 0;
99         example = 44444;
100         description = ''
101           Listening port. Defaults to 0 which randomizes the port.
102         '';
103       };
105       checkForUpdates = mkOption {
106         type = types.bool;
107         default = true;
108         description = ''
109           Determines whether to check for updates and alert the user
110           about them in the UI.
111         '';
112       };
114       useUpnp = mkOption {
115         type = types.bool;
116         default = true;
117         description = ''
118           Use Universal Plug-n-Play (UPnP)
119         '';
120       };
122       downloadLimit = mkOption {
123         type = types.int;
124         default = 0;
125         example = 1024;
126         description = ''
127           Download speed limit. 0 is unlimited (default).
128         '';
129       };
131       uploadLimit = mkOption {
132         type = types.int;
133         default = 0;
134         example = 1024;
135         description = ''
136           Upload speed limit. 0 is unlimited (default).
137         '';
138       };
140       httpListenAddr = mkOption {
141         type = types.str;
142         default = "[::1]";
143         example = "0.0.0.0";
144         description = ''
145           HTTP address to bind to.
146         '';
147       };
149       httpListenPort = mkOption {
150         type = types.int;
151         default = 9000;
152         description = ''
153           HTTP port to bind on.
154         '';
155       };
157       httpLogin = mkOption {
158         type = types.str;
159         example = "allyourbase";
160         default = "";
161         description = ''
162           HTTP web login username.
163         '';
164       };
166       httpPass = mkOption {
167         type = types.str;
168         example = "arebelongtous";
169         default = "";
170         description = ''
171           HTTP web login password.
172         '';
173       };
175       encryptLAN = mkOption {
176         type = types.bool;
177         default = true;
178         description = "Encrypt LAN data.";
179       };
181       enableWebUI = mkOption {
182         type = types.bool;
183         default = false;
184         description = ''
185           Enable Web UI for administration. Bound to the specified
186           `httpListenAddress` and
187           `httpListenPort`.
188           '';
189       };
191       storagePath = mkOption {
192         type = types.path;
193         default = "/var/lib/resilio-sync/";
194         description = ''
195           Where BitTorrent Sync will store it's database files (containing
196           things like username info and licenses). Generally, you should not
197           need to ever change this.
198         '';
199       };
201       apiKey = mkOption {
202         type = types.str;
203         default = "";
204         description = "API key, which enables the developer API.";
205       };
207       directoryRoot = mkOption {
208         type = types.str;
209         default = "";
210         example = "/media";
211         description = "Default directory to add folders in the web UI.";
212       };
214       sharedFolders = mkOption {
215         default = [];
216         type = types.listOf (types.attrsOf types.anything);
217         example =
218           [ { secretFile     = "/run/resilio-secret";
219               directory      = "/home/user/sync_test";
220               useRelayServer = true;
221               useTracker     = true;
222               useDHT         = false;
223               searchLAN      = true;
224               useSyncTrash   = true;
225               knownHosts     = [
226                 "192.168.1.2:4444"
227                 "192.168.1.3:4444"
228               ];
229             }
230           ];
231         description = ''
232           Shared folder list. If enabled, web UI must be
233           disabled. Secrets can be generated using `rslsync --generate-secret`.
235           If you would like to be able to modify the contents of this
236           directories, it is recommended that you make your user a
237           member of the `rslsync` group.
239           Directories in this list should be in the
240           `rslsync` group, and that group must have
241           write access to the directory. It is also recommended that
242           `chmod g+s` is applied to the directory
243           so that any sub directories created will also belong to
244           the `rslsync` group. Also,
245           `setfacl -d -m group:rslsync:rwx` and
246           `setfacl -m group:rslsync:rwx` should also
247           be applied so that the sub directories are writable by
248           the group.
249         '';
250       };
251     };
252   };
254   config = mkIf cfg.enable {
255     assertions =
256       [ { assertion = cfg.deviceName != "";
257           message   = "Device name cannot be empty.";
258         }
259         { assertion = cfg.enableWebUI -> cfg.sharedFolders == [];
260           message   = "If using shared folders, the web UI cannot be enabled.";
261         }
262         { assertion = cfg.apiKey != "" -> cfg.enableWebUI;
263           message   = "If you're using an API key, you must enable the web server.";
264         }
265       ];
267     users.users.rslsync = {
268       description     = "Resilio Sync Service user";
269       home            = cfg.storagePath;
270       createHome      = true;
271       uid             = config.ids.uids.rslsync;
272       group           = "rslsync";
273     };
275     users.groups.rslsync = {};
277     systemd.services.resilio = with pkgs; {
278       description = "Resilio Sync Service";
279       wantedBy    = [ "multi-user.target" ];
280       after       = [ "network.target" ];
281       serviceConfig = {
282         Restart   = "on-abort";
283         UMask     = "0002";
284         User      = "rslsync";
285         RuntimeDirectory = "rslsync";
286         ExecStartPre = "${createConfig}/bin/create-resilio-config";
287         ExecStart = ''
288           ${resilioSync}/bin/rslsync --nodaemon --config ${runConfigPath}
289         '';
290       };
291     };
292   };
294   meta.maintainers = [ ];