nixpkgs/nixos/modules/services/networking/resilio.nix
Silvan Mosberger 374e6bcc40 treewide: Format all Nix files
Format all Nix files using the officially approved formatter,
making the CI check introduced in the previous commit succeed:

  nix-build ci -A fmt.check

This is the next step of the of the [implementation](https://github.com/NixOS/nixfmt/issues/153)
of the accepted [RFC 166](https://github.com/NixOS/rfcs/pull/166).

This commit will lead to merge conflicts for a number of PRs,
up to an estimated ~1100 (~33%) among the PRs with activity in the past 2
months, but that should be lower than what it would be without the previous
[partial treewide format](https://github.com/NixOS/nixpkgs/pull/322537).

Merge conflicts caused by this commit can now automatically be resolved while rebasing using the
[auto-rebase script](8616af08d9/maintainers/scripts/auto-rebase).

If you run into any problems regarding any of this, please reach out to the
[formatting team](https://nixos.org/community/teams/formatting/) by
pinging @NixOS/nix-formatting.
2025-04-01 20:10:43 +02:00

319 lines
8.5 KiB
Nix

{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.resilio;
sharedFoldersRecord = map (entry: {
dir = entry.directory;
use_relay_server = entry.useRelayServer;
use_tracker = entry.useTracker;
use_dht = entry.useDHT;
search_lan = entry.searchLAN;
use_sync_trash = entry.useSyncTrash;
known_hosts = entry.knownHosts;
}) cfg.sharedFolders;
configFile = pkgs.writeText "config.json" (
builtins.toJSON (
{
device_name = cfg.deviceName;
storage_path = cfg.storagePath;
listening_port = cfg.listeningPort;
use_gui = false;
check_for_updates = cfg.checkForUpdates;
use_upnp = cfg.useUpnp;
download_limit = cfg.downloadLimit;
upload_limit = cfg.uploadLimit;
lan_encrypt_data = cfg.encryptLAN;
}
// optionalAttrs (cfg.directoryRoot != "") { directory_root = cfg.directoryRoot; }
// optionalAttrs cfg.enableWebUI {
webui =
{
listen = "${cfg.httpListenAddr}:${toString cfg.httpListenPort}";
}
// (optionalAttrs (cfg.httpLogin != "") { login = cfg.httpLogin; })
// (optionalAttrs (cfg.httpPass != "") { password = cfg.httpPass; })
// (optionalAttrs (cfg.apiKey != "") { api_key = cfg.apiKey; });
}
// optionalAttrs (sharedFoldersRecord != [ ]) {
shared_folders = sharedFoldersRecord;
}
)
);
sharedFoldersSecretFiles = map (entry: {
dir = entry.directory;
secretFile =
if builtins.hasAttr "secret" entry then
toString (
pkgs.writeTextFile {
name = "secret-file";
text = entry.secret;
}
)
else
entry.secretFile;
}) cfg.sharedFolders;
runConfigPath = "/run/rslsync/config.json";
createConfig = pkgs.writeShellScriptBin "create-resilio-config" (
if cfg.sharedFolders != [ ] then
''
${pkgs.jq}/bin/jq \
'.shared_folders |= map(.secret = $ARGS.named[.dir])' \
${
lib.concatMapStringsSep " \\\n " (
entry: ''--arg '${entry.dir}' "$(cat '${entry.secretFile}')"''
) sharedFoldersSecretFiles
} \
<${configFile} \
>${runConfigPath}
''
else
''
# no secrets, passing through config
cp ${configFile} ${runConfigPath};
''
);
in
{
options = {
services.resilio = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
If enabled, start the Resilio Sync daemon. Once enabled, you can
interact with the service through the Web UI, or configure it in your
NixOS configuration.
'';
};
package = mkPackageOption pkgs "resilio-sync" { };
deviceName = mkOption {
type = types.str;
example = "Voltron";
default = config.networking.hostName;
defaultText = literalExpression "config.networking.hostName";
description = ''
Name of the Resilio 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 = "[::1]";
example = "0.0.0.0";
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";
default = "";
description = ''
HTTP web login username.
'';
};
httpPass = mkOption {
type = types.str;
example = "arebelongtous";
default = "";
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`.
'';
};
storagePath = mkOption {
type = types.path;
default = "/var/lib/resilio-sync/";
description = ''
Where BitTorrent Sync will store it's database files (containing
things like username info and licenses). Generally, you should not
need to ever change this.
'';
};
apiKey = mkOption {
type = types.str;
default = "";
description = "API key, which enables the developer API.";
};
directoryRoot = mkOption {
type = types.str;
default = "";
example = "/media";
description = "Default directory to add folders in the web UI.";
};
sharedFolders = mkOption {
default = [ ];
type = types.listOf (types.attrsOf types.anything);
example = [
{
secretFile = "/run/resilio-secret";
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 `rslsync --generate-secret`.
If you would like to be able to modify the contents of this
directories, it is recommended that you make your user a
member of the `rslsync` group.
Directories in this list should be in the
`rslsync` group, and that group must have
write access to the directory. It is also recommended that
`chmod g+s` is applied to the directory
so that any sub directories created will also belong to
the `rslsync` group. Also,
`setfacl -d -m group:rslsync:rwx` and
`setfacl -m group:rslsync:rwx` should also
be applied so that the sub directories are writable by
the group.
'';
};
};
};
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.";
}
];
users.users.rslsync = {
description = "Resilio Sync Service user";
home = cfg.storagePath;
createHome = true;
uid = config.ids.uids.rslsync;
group = "rslsync";
};
users.groups.rslsync.gid = config.ids.gids.rslsync;
systemd.services.resilio = with pkgs; {
description = "Resilio Sync Service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
Restart = "on-abort";
UMask = "0002";
User = "rslsync";
RuntimeDirectory = "rslsync";
ExecStartPre = "${createConfig}/bin/create-resilio-config";
ExecStart = ''
${lib.getExe cfg.package} --nodaemon --config ${runConfigPath}
'';
};
};
};
meta.maintainers = [ ];
}