1{ config, lib, pkgs, ... }:
2
3let
4 cfg = config.services.transfer-sh;
5 inherit (lib)
6 mkDefault mkEnableOption mkPackageOption mkIf mkOption
7 types mapAttrs isBool getExe boolToString optionalAttrs;
8in
9{
10 options.services.transfer-sh = {
11 enable = mkEnableOption "Easy and fast file sharing from the command-line";
12
13 package = mkPackageOption pkgs "transfer-sh" { };
14
15 settings = mkOption {
16 type = types.submodule { freeformType = with types; attrsOf (oneOf [ bool int str ]); };
17 default = { };
18 example = {
19 LISTENER = ":8080";
20 BASEDIR = "/var/lib/transfer.sh";
21 TLS_LISTENER_ONLY = false;
22 };
23 description = ''
24 Additional configuration for transfer-sh, see
25 <https://github.com/dutchcoders/transfer.sh#usage-1>
26 for supported values.
27
28 For secrets use secretFile option instead.
29 '';
30 };
31
32 provider = mkOption {
33 type = types.enum [ "local" "s3" "storj" "gdrive" ];
34 default = "local";
35 description = "Storage providers to use";
36 };
37
38 secretFile = mkOption {
39 type = types.nullOr types.path;
40 default = null;
41 example = "/run/secrets/transfer-sh.env";
42 description = ''
43 Path to file containing environment variables.
44 Useful for passing down secrets.
45 Some variables that can be considered secrets are:
46 - AWS_ACCESS_KEY
47 - AWS_ACCESS_KEY
48 - TLS_PRIVATE_KEY
49 - HTTP_AUTH_HTPASSWD
50 '';
51 };
52 };
53
54 config =
55 let
56 localProvider = (cfg.provider == "local");
57 stateDirectory = "/var/lib/transfer.sh";
58 in
59 mkIf cfg.enable
60 {
61 services.transfer-sh.settings = {
62 LISTENER = mkDefault ":8080";
63 } // optionalAttrs localProvider {
64 BASEDIR = mkDefault stateDirectory;
65 };
66
67 systemd.services.transfer-sh = {
68 after = [ "network.target" ];
69 wantedBy = [ "multi-user.target" ];
70 environment = mapAttrs (_: v: if isBool v then boolToString v else toString v) cfg.settings;
71 serviceConfig = {
72 CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
73 DevicePolicy = "closed";
74 DynamicUser = true;
75 ExecStart = "${getExe cfg.package} --provider ${cfg.provider}";
76 LockPersonality = true;
77 MemoryDenyWriteExecute = true;
78 PrivateDevices = true;
79 PrivateUsers = true;
80 ProtectClock = true;
81 ProtectControlGroups = true;
82 ProtectHostname = true;
83 ProtectKernelLogs = true;
84 ProtectKernelModules = true;
85 ProtectKernelTunables = true;
86 ProtectProc = "invisible";
87 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
88 RestrictNamespaces = true;
89 RestrictRealtime = true;
90 SystemCallArchitectures = [ "native" ];
91 SystemCallFilter = [ "@system-service" ];
92 StateDirectory = baseNameOf stateDirectory;
93 } // optionalAttrs (cfg.secretFile != null) {
94 EnvironmentFile = cfg.secretFile;
95 } // optionalAttrs localProvider {
96 ReadWritePaths = cfg.settings.BASEDIR;
97 };
98 };
99 };
100
101 meta.maintainers = with lib.maintainers; [ ocfox ];
102}