]> Git — Sourcephile - sourcephile-nix.git/blob - nixpkgs/patches/transmission.diff
nix: rename flakes to inputs
[sourcephile-nix.git] / nixpkgs / patches / transmission.diff
1 diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
2 index 014a22bb5a8..6f6d5a05a2a 100644
3 --- a/nixos/modules/services/torrent/transmission.nix
4 +++ b/nixos/modules/services/torrent/transmission.nix
5 @@ -12,10 +12,15 @@ let
6 downloadsDir = "Downloads";
7 incompleteDir = ".incomplete";
8 watchDir = "watchdir";
9 - # TODO: switch to configGen.json once RFC0042 is implemented
10 settingsFile = pkgs.writeText "settings.json" (builtins.toJSON cfg.settings);
11 in
12 {
13 + imports = [
14 + (mkRenamedOptionModule ["services" "transmission" "port"]
15 + ["services" "transmission" "settings" "rpc-port"])
16 + (mkRenamedOptionModule ["services" "transmission" "openFirewall"]
17 + ["services" "transmission" "openPeerPorts"])
18 + ];
19 options = {
20 services.transmission = {
21 enable = mkEnableOption ''the headless Transmission BitTorrent daemon.
22 @@ -27,45 +32,140 @@ in
23 Torrents are downloaded to ${homeDir}/${downloadsDir} by default and are
24 accessible to users in the "transmission" group'';
25
26 - settings = mkOption rec {
27 - # TODO: switch to types.config.json as prescribed by RFC0042 once it's implemented
28 - type = types.attrs;
29 - apply = recursiveUpdate default;
30 - default =
31 - {
32 - download-dir = "${cfg.home}/${downloadsDir}";
33 - incomplete-dir = "${cfg.home}/${incompleteDir}";
34 - incomplete-dir-enabled = true;
35 - watch-dir = "${cfg.home}/${watchDir}";
36 - watch-dir-enabled = false;
37 - message-level = 1;
38 - peer-port = 51413;
39 - peer-port-random-high = 65535;
40 - peer-port-random-low = 49152;
41 - peer-port-random-on-start = false;
42 - rpc-bind-address = "127.0.0.1";
43 - rpc-port = 9091;
44 - script-torrent-done-enabled = false;
45 - script-torrent-done-filename = "";
46 - umask = 2; # 0o002 in decimal as expected by Transmission
47 - utp-enabled = true;
48 - };
49 - example =
50 - {
51 - download-dir = "/srv/torrents/";
52 - incomplete-dir = "/srv/torrents/.incomplete/";
53 - incomplete-dir-enabled = true;
54 - rpc-whitelist = "127.0.0.1,192.168.*.*";
55 - };
56 + settings = mkOption {
57 description = ''
58 - Attribute set whose fields overwrites fields in
59 + Settings whose fields overwrites fields in
60 <literal>.config/transmission-daemon/settings.json</literal>
61 - (each time the service starts). String values must be quoted, integer and
62 - boolean values must not.
63 + (each time the service starts).
64
65 See <link xlink:href="https://github.com/transmission/transmission/wiki/Editing-Configuration-Files">Transmission's Wiki</link>
66 - for documentation.
67 + for documentation of settings not explicitely covered by this module.
68 '';
69 + default = {};
70 + type = types.submodule {
71 + freeformType = with types;
72 + (attrsOf (nullOr (oneOf [str int bool]))) // {
73 + description = "setting option";
74 + };
75 + options.download-dir = mkOption {
76 + type = types.path;
77 + default = "${cfg.home}/${downloadsDir}";
78 + description = "Directory where to download torrents.";
79 + };
80 + options.incomplete-dir = mkOption {
81 + type = types.path;
82 + default = "${cfg.home}/${incompleteDir}";
83 + description = ''
84 + When enabled with
85 + <link linkend="opt-services.transmission.settings.incomplete-dir-enabled">incomplete-dir-enabled</link>,
86 + new torrents will download the files to this directory.
87 + When complete, the files will be moved to download-dir
88 + <link linkend="opt-services.transmission.settings.download-dir">download-dir</link>.
89 + '';
90 + };
91 + options.incomplete-dir-enabled = mkOption {
92 + type = types.bool;
93 + default = true;
94 + description = "";
95 + };
96 + options.message-level = mkOption {
97 + type = types.ints.between 0 2;
98 + default = 2;
99 + description = "Set verbosity of transmission messages.";
100 + };
101 + options.peer-port = mkOption {
102 + type = types.port;
103 + default = 51413;
104 + description = "The peer port to listen for incoming connections.";
105 + };
106 + options.peer-port-random-high = mkOption {
107 + type = types.port;
108 + default = 65535;
109 + description = ''
110 + The maximum peer port to listen to for incoming connections
111 + when <link linkend="opt-services.transmission.settings.peer-port-random-on-start">peer-port-random-on-start</link> is enabled.
112 + '';
113 + };
114 + options.peer-port-random-low = mkOption {
115 + type = types.port;
116 + default = 65535;
117 + description = ''
118 + The minimal peer port to listen to for incoming connections
119 + when <link linkend="opt-services.transmission.settings.peer-port-random-on-start">peer-port-random-on-start</link> is enabled.
120 + '';
121 + };
122 + options.peer-port-random-on-start = mkOption {
123 + type = types.bool;
124 + default = false;
125 + description = "Randomize the peer port.";
126 + };
127 + options.rpc-bind-address = mkOption {
128 + type = types.str;
129 + default = "127.0.0.1";
130 + example = "0.0.0.0";
131 + description = ''
132 + Where to listen for RPC connections.
133 + Use \"0.0.0.0\" to listen on all interfaces.
134 + '';
135 + };
136 + options.rpc-port = mkOption {
137 + type = types.port;
138 + default = 9091;
139 + description = "The RPC port to listen to.";
140 + };
141 + options.script-torrent-done-enabled = mkOption {
142 + type = types.bool;
143 + default = false;
144 + description = ''
145 + Whether to run
146 + <link linkend="opt-services.transmission.settings.script-torrent-done-filename">script-torrent-done-filename</link>
147 + at torrent completion.
148 + '';
149 + };
150 + options.script-torrent-done-filename = mkOption {
151 + type = types.nullOr types.path;
152 + default = null;
153 + description = "Executable to be run at torrent completion.";
154 + };
155 + options.umask = mkOption {
156 + type = types.int;
157 + default = 2;
158 + description = ''
159 + Sets transmission's file mode creation mask.
160 + See the umask(2) manpage for more information.
161 + Users who want their saved torrents to be world-writable
162 + may want to set this value to 0.
163 + Bear in mind that the json markup language only accepts numbers in base 10,
164 + so the standard umask(2) octal notation "022" is written in settings.json as 18.
165 + '';
166 + };
167 + options.utp-enabled = mkOption {
168 + type = types.bool;
169 + default = true;
170 + description = ''
171 + Whether to enable <link xlink:href="http://en.wikipedia.org/wiki/Micro_Transport_Protocol">Micro Transport Protocol (µTP)</link>.
172 + '';
173 + };
174 + options.watch-dir = mkOption {
175 + type = types.path;
176 + default = "${cfg.home}/${watchDir}";
177 + description = "Watch a directory for torrent files and add them to transmission.";
178 + };
179 + options.watch-dir-enabled = mkOption {
180 + type = types.bool;
181 + default = false;
182 + description = ''Whether to enable the
183 + <link linkend="opt-services.transmission.settings.watch-dir">watch-dir</link>.
184 + '';
185 + };
186 + options.trash-original-torrent-files = mkOption {
187 + type = types.bool;
188 + default = false;
189 + description = ''Whether to delete torrents added from the
190 + <link linkend="opt-services.transmission.settings.watch-dir">watch-dir</link>.
191 + '';
192 + };
193 + };
194 };
195
196 downloadDirPermissions = mkOption {
197 @@ -81,17 +181,6 @@ in
198 '';
199 };
200
201 - port = mkOption {
202 - type = types.port;
203 - description = ''
204 - TCP port number to run the RPC/web interface.
205 -
206 - If instead you want to change the peer port,
207 - use <link linkend="opt-services.transmission.settings">settings.peer-port</link>
208 - or <link linkend="opt-services.transmission.settings">settings.peer-port-random-on-start</link>.
209 - '';
210 - };
211 -
212 home = mkOption {
213 type = types.path;
214 default = homeDir;
215 @@ -125,7 +214,9 @@ in
216 example = "/var/lib/secrets/transmission/settings.json";
217 };
218
219 - openFirewall = mkEnableOption "opening of the peer port(s) in the firewall";
220 + openPeerPorts = mkEnableOption "opening of the peer port(s) in the firewall";
221 +
222 + openRPCPort = mkEnableOption "opening of the RPC port in the firewall";
223
224 performanceNetParameters = mkEnableOption ''tweaking of kernel parameters
225 to open many more connections at the same time.
226 @@ -152,36 +243,10 @@ in
227 install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.download-dir}'
228 '' + optionalString cfg.settings.incomplete-dir-enabled ''
229 install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.incomplete-dir}'
230 + '' + optionalString cfg.settings.watch-dir-enabled ''
231 + install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.watch-dir}'
232 '';
233
234 - assertions = [
235 - { assertion = builtins.match "^/.*" cfg.home != null;
236 - message = "`services.transmission.home' must be an absolute path.";
237 - }
238 - { assertion = types.path.check cfg.settings.download-dir;
239 - message = "`services.transmission.settings.download-dir' must be an absolute path.";
240 - }
241 - { assertion = types.path.check cfg.settings.incomplete-dir;
242 - message = "`services.transmission.settings.incomplete-dir' must be an absolute path.";
243 - }
244 - { assertion = types.path.check cfg.settings.watch-dir;
245 - message = "`services.transmission.settings.watch-dir' must be an absolute path.";
246 - }
247 - { assertion = cfg.settings.script-torrent-done-filename == "" || types.path.check cfg.settings.script-torrent-done-filename;
248 - message = "`services.transmission.settings.script-torrent-done-filename' must be an absolute path.";
249 - }
250 - { assertion = types.port.check cfg.settings.rpc-port;
251 - message = "${toString cfg.settings.rpc-port} is not a valid port number for `services.transmission.settings.rpc-port`.";
252 - }
253 - # In case both port and settings.rpc-port are explicitely defined: they must be the same.
254 - { assertion = !options.services.transmission.port.isDefined || cfg.port == cfg.settings.rpc-port;
255 - message = "`services.transmission.port' is not equal to `services.transmission.settings.rpc-port'";
256 - }
257 - ];
258 -
259 - services.transmission.settings =
260 - optionalAttrs options.services.transmission.port.isDefined { rpc-port = cfg.port; };
261 -
262 systemd.services.transmission = {
263 description = "Transmission BitTorrent Service";
264 after = [ "network.target" ] ++ optional apparmor "apparmor.service";
265 @@ -226,11 +291,9 @@ in
266 cfg.settings.download-dir
267 ] ++
268 optional cfg.settings.incomplete-dir-enabled
269 - cfg.settings.incomplete-dir
270 - ++
271 - optional cfg.settings.watch-dir-enabled
272 - cfg.settings.watch-dir
273 - ;
274 + cfg.settings.incomplete-dir ++
275 + optional (cfg.settings.watch-dir-enabled && cfg.settings.trash-original-torrent-files)
276 + cfg.settings.watch-dir;
277 BindReadOnlyPaths = [
278 # No confinement done of /nix/store here like in systemd-confinement.nix,
279 # an AppArmor profile is provided to get a confinement based upon paths and rights.
280 @@ -238,8 +301,10 @@ in
281 "/etc"
282 ] ++
283 optional (cfg.settings.script-torrent-done-enabled &&
284 - cfg.settings.script-torrent-done-filename != "")
285 - cfg.settings.script-torrent-done-filename;
286 + cfg.settings.script-torrent-done-filename != null)
287 + cfg.settings.script-torrent-done-filename ++
288 + optional (cfg.settings.watch-dir-enabled && !cfg.settings.trash-original-torrent-files)
289 + cfg.settings.watch-dir;
290 # The following options are only for optimizing:
291 # systemd-analyze security transmission
292 AmbientCapabilities = "";
293 @@ -306,25 +371,28 @@ in
294 };
295 });
296
297 - networking.firewall = mkIf cfg.openFirewall (
298 - if cfg.settings.peer-port-random-on-start
299 - then
300 - { allowedTCPPortRanges =
301 - [ { from = cfg.settings.peer-port-random-low;
302 - to = cfg.settings.peer-port-random-high;
303 - }
304 - ];
305 - allowedUDPPortRanges =
306 - [ { from = cfg.settings.peer-port-random-low;
307 - to = cfg.settings.peer-port-random-high;
308 - }
309 - ];
310 - }
311 - else
312 - { allowedTCPPorts = [ cfg.settings.peer-port ];
313 - allowedUDPPorts = [ cfg.settings.peer-port ];
314 - }
315 - );
316 + networking.firewall = mkMerge [
317 + (mkIf cfg.openPeerPorts (
318 + if cfg.settings.peer-port-random-on-start
319 + then
320 + { allowedTCPPortRanges =
321 + [ { from = cfg.settings.peer-port-random-low;
322 + to = cfg.settings.peer-port-random-high;
323 + }
324 + ];
325 + allowedUDPPortRanges =
326 + [ { from = cfg.settings.peer-port-random-low;
327 + to = cfg.settings.peer-port-random-high;
328 + }
329 + ];
330 + }
331 + else
332 + { allowedTCPPorts = [ cfg.settings.peer-port ];
333 + allowedUDPPorts = [ cfg.settings.peer-port ];
334 + }
335 + ))
336 + (mkIf cfg.openRPCPort { allowedTCPPorts = [ cfg.settings.rpc-port ]; })
337 + ];
338
339 boot.kernel.sysctl = mkMerge [
340 # Transmission uses a single UDP socket in order to implement multiple uTP sockets,
341 @@ -419,7 +487,7 @@ in
342 rw ${cfg.settings.incomplete-dir}/**,
343 ''}
344 ${optionalString cfg.settings.watch-dir-enabled ''
345 - rw ${cfg.settings.watch-dir}/**,
346 + r${optionalString cfg.settings.trash-original-torrent-files "w"} ${cfg.settings.watch-dir}/**,
347 ''}
348 profile dirs {
349 rw ${cfg.settings.download-dir}/**,
350 @@ -427,12 +495,12 @@ in
351 rw ${cfg.settings.incomplete-dir}/**,
352 ''}
353 ${optionalString cfg.settings.watch-dir-enabled ''
354 - rw ${cfg.settings.watch-dir}/**,
355 + r${optionalString cfg.settings.trash-original-torrent-files "w"} ${cfg.settings.watch-dir}/**,
356 ''}
357 }
358
359 ${optionalString (cfg.settings.script-torrent-done-enabled &&
360 - cfg.settings.script-torrent-done-filename != "") ''
361 + cfg.settings.script-torrent-done-filename != null) ''
362 # Stack transmission_directories profile on top of
363 # any existing profile for script-torrent-done-filename
364 # FIXME: to be tested as I'm not sure it works well with NoNewPrivileges=