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