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 LISTENER = mkDefault ":8080";
90 }
91 // optionalAttrs localProvider {
92 BASEDIR = mkDefault stateDirectory;
93 };
94
95 systemd.services.transfer-sh = {
96 after = [ "network.target" ];
97 wantedBy = [ "multi-user.target" ];
98 environment = mapAttrs (_: v: if isBool v then boolToString v else toString v) cfg.settings;
99 serviceConfig = {
100 DevicePolicy = "closed";
101 DynamicUser = true;
102 ExecStart = "${getExe cfg.package} --provider ${cfg.provider}";
103 LockPersonality = true;
104 MemoryDenyWriteExecute = true;
105 PrivateDevices = true;
106 PrivateUsers = true;
107 ProtectClock = true;
108 ProtectControlGroups = true;
109 ProtectHostname = true;
110 ProtectKernelLogs = true;
111 ProtectKernelModules = true;
112 ProtectKernelTunables = true;
113 ProtectProc = "invisible";
114 RestrictAddressFamilies = [
115 "AF_INET"
116 "AF_INET6"
117 ];
118 RestrictNamespaces = true;
119 RestrictRealtime = true;
120 SystemCallArchitectures = [ "native" ];
121 SystemCallFilter = [ "@system-service" ];
122 StateDirectory = baseNameOf stateDirectory;
123 }
124 // optionalAttrs (cfg.secretFile != null) {
125 EnvironmentFile = cfg.secretFile;
126 }
127 // optionalAttrs localProvider {
128 ReadWritePaths = cfg.settings.BASEDIR;
129 };
130 };
131 };
132
133 meta.maintainers = with lib.maintainers; [ ocfox ];
134}