From 6e415d2b58f9821d79c75fce29796da06c723c46 Mon Sep 17 00:00:00 2001 From: Austin Seipp Date: Fri, 21 Feb 2014 13:05:12 -0600 Subject: [PATCH] nixos: add BitTorrent Sync service module Signed-off-by: Austin Seipp --- nixos/modules/misc/ids.nix | 1 + nixos/modules/module-list.nix | 1 + nixos/modules/services/networking/btsync.nix | 280 +++++++++++++++++++ 3 files changed, 282 insertions(+) create mode 100644 nixos/modules/services/networking/btsync.nix diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 07ec5c8c2c4..fc05584e256 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -121,6 +121,7 @@ systemd-journal-gateway = 110; notbit = 111; ngircd = 112; + btsync = 113; # When adding a uid, make sure it doesn't match an existing gid. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 706f3da60b3..e59b0ff5ac2 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -155,6 +155,7 @@ ./services/networking/avahi-daemon.nix ./services/networking/bind.nix ./services/networking/bitlbee.nix + ./services/networking/btsync.nix ./services/networking/connman.nix ./services/networking/cntlm.nix ./services/networking/chrony.nix diff --git a/nixos/modules/services/networking/btsync.nix b/nixos/modules/services/networking/btsync.nix new file mode 100644 index 00000000000..e7fb471ccf4 --- /dev/null +++ b/nixos/modules/services/networking/btsync.nix @@ -0,0 +1,280 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.btsync; + listenAddr = cfg.httpListenAddr + ":" + (toString cfg.httpListenPort); + + boolStr = x: if x then "true" else "false"; + optionalEmptyStr = b: v: optionalString (b != "") v; + + webUIConfig = optionalString cfg.enableWebUI + '' + "webui": + { + ${optionalEmptyStr cfg.httpLogin "\"login\": \"${cfg.httpLogin}\","} + ${optionalEmptyStr cfg.httpPass "\"password\": \"${cfg.httpPass}\","} + ${optionalEmptyStr cfg.apiKey "\"api_key\": \"${cfg.apiKey}\","} + "listen": "${listenAddr}" + } + ''; + + knownHosts = e: + optionalString (e ? "knownHosts") + (concatStringsSep "," (map (v: "\"${v}\"") e."knownHosts")); + + sharedFoldersRecord = with pkgs.lib; + concatStringsSep "," (map (entry: + let helper = attr: v: + if (entry ? attr) then boolStr entry.attr else boolStr v; + in + '' + { + "secret": "${entry.secret}", + "dir": "${entry.directory}", + + "use_relay_server": ${helper "useRelayServer" true}, + "use_tracker": ${helper "useTracker" true}, + "use_dht": ${helper "useDHT" false}, + + "search_lan": ${helper "searchLAN" true}, + "use_sync_trash": ${helper "useSyncTrash" true}, + + "known_hosts": [${knownHosts entry}] + } + '') cfg.sharedFolders); + + sharedFoldersConfig = optionalString (cfg.sharedFolders != []) + '' + "shared_folders": + [ + ${sharedFoldersRecord} + ] + ''; + + configFile = pkgs.writeText "btsync.config" + '' + { + "device_name": "${cfg.deviceName}", + "storage_path": "/var/lib/btsync", + "listening_port": ${toString cfg.listeningPort}, + "use_gui": false, + + "check_for_updates": ${boolStr cfg.checkForUpdates}, + "use_upnp": ${boolStr cfg.useUpnp}, + "download_limit": ${toString cfg.downloadLimit}, + "upload_limit": ${toString cfg.uploadLimit}, + "lan_encrypt_data": ${boolStr cfg.encryptLAN}, + + ${webUIConfig} + ${sharedFoldersConfig} + } + ''; +in +{ + options = { + services.btsync = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + If enabled, start the Bittorrent Sync daemon. Once enabled, + you can interact with the service through the Web UI, or + configure it in your NixOS configuration. Enabling the + btsync service also installs a + multi-instance systemd unit which can be used to start + user-specific copies of the daemon. Once installed, you can + use systemctl start btsync@user to start + the daemon only for user user, using the + configuration file located at + $HOME/.config/btsync.conf + ''; + }; + + deviceName = mkOption { + type = types.str; + example = "Voltron"; + description = '' + Name of the Bittorrent Sync device. + ''; + }; + + listeningPort = mkOption { + type = types.int; + default = 0; + example = 44444; + description = '' + Listening port. Defaults to 0 which randomizes the port. + ''; + }; + + checkForUpdates = mkOption { + type = types.bool; + default = true; + description = '' + Determines whether to check for updates and alert the user + about them in the UI. + ''; + }; + + useUpnp = mkOption { + type = types.bool; + default = true; + description = '' + Use Universal Plug-n-Play (UPnP) + ''; + }; + + downloadLimit = mkOption { + type = types.int; + default = 0; + example = 1024; + description = '' + Download speed limit. 0 is unlimited (default). + ''; + }; + + uploadLimit = mkOption { + type = types.int; + default = 0; + example = 1024; + description = '' + Upload speed limit. 0 is unlimited (default). + ''; + }; + + httpListenAddr = mkOption { + type = types.str; + default = "0.0.0.0"; + example = "1.2.3.4"; + description = '' + HTTP address to bind to. + ''; + }; + + httpListenPort = mkOption { + type = types.int; + default = 9000; + description = '' + HTTP port to bind on. + ''; + }; + + httpLogin = mkOption { + type = types.str; + example = "allyourbase"; + description = '' + HTTP web login username. + ''; + }; + + httpPass = mkOption { + type = types.str; + example = "arebelongtous"; + description = '' + HTTP web login password. + ''; + }; + + encryptLAN = mkOption { + type = types.bool; + default = true; + description = "Encrypt LAN data."; + }; + + enableWebUI = mkOption { + type = types.bool; + default = false; + description = '' + Enable Web UI for administration. Bound to the specified + httpListenAddress and + httpListenPort. + ''; + }; + + apiKey = mkOption { + type = types.str; + default = ""; + description = "API key, which enables the developer API."; + }; + + sharedFolders = mkOption { + default = []; + example = + [ { secret = "AHMYFPCQAHBM7LQPFXQ7WV6Y42IGUXJ5Y"; + directory = "/home/user/sync_test"; + useRelayServer = true; + useTracker = true; + useDHT = false; + searchLAN = true; + useSyncTrash = true; + knownHosts = + [ "192.168.1.2:4444" + "192.168.1.3:4444" + ]; + } + ]; + description = '' + Shared folder list. If enabled, web UI must be + disabled. Secrets can be generated using btsync + --generate-secret. Note that this secret will be + put inside the Nix store, so it is realistically not very + secret. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = + [ { assertion = cfg.deviceName != ""; + message = "Device name cannot be empty."; + } + { assertion = cfg.enableWebUI -> cfg.sharedFolders == []; + message = "If using shared folders, the web UI cannot be enabled."; + } + { assertion = cfg.apiKey != "" -> cfg.enableWebUI; + message = "If you're using an API key, you must enable the web server."; + } + # TODO FIXME: the README says not specifying the login/pass means it + # should disable authentication, but apparently it doesn't? + { assertion = cfg.enableWebUI -> cfg.httpLogin != "" && cfg.httpPass != ""; + message = "If using the web UI, you must configure a login/password."; + } + # TODO FIXME: assert the existence of sharedFolder directories? + ]; + + users.extraUsers.btsync = { + description = "Bittorrent Sync Service user"; + home = "/var/lib/btsync"; + createHome = true; + uid = config.ids.uids.btsync; + }; + + systemd.services.btsync = with pkgs; { + description = "Bittorrent Sync Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + Restart = "on-abort"; + User = "btsync"; + ExecStart = + "${bittorrentSync}/bin/btsync --nodaemon --config ${configFile}"; + }; + }; + + systemd.services."btsync@" = with pkgs; { + description = "Bittorrent Sync Service for %i"; + after = [ "network.target" ]; + serviceConfig = { + Restart = "on-abort"; + User = "%i"; + ExecStart = + "${bittorrentSync}/bin/btsync --nodaemon --config %h/.config/btsync.conf"; + }; + }; + + environment.systemPackages = [ pkgs.bittorrentSync ]; + }; +}