python312Packages.aiohomeconnect: 0.10.0 -> 0.11.0 (#374011)
[NixPkgs.git] / nixos / modules / services / networking / privoxy.nix
blob145eee919736e23e1c28e962447fccbeefa14b0a
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
8 with lib;
10 let
12   cfg = config.services.privoxy;
14   serialise =
15     name: val:
16     if isList val then
17       concatMapStrings (serialise name) val
18     else if isBool val then
19       serialise name (if val then "1" else "0")
20     else
21       "${name} ${toString val}\n";
23   configType =
24     with types;
25     let
26       atom = oneOf [
27         int
28         bool
29         str
30         path
31       ];
32     in
33     attrsOf (either atom (listOf atom))
34     // {
35       description = ''
36         privoxy configuration type. The format consists of an attribute
37         set of settings. Each setting can be either a value (integer, string,
38         boolean or path) or a list of such values.
39       '';
40     };
42   ageType = types.str // {
43     check = x: isString x && (builtins.match "([0-9]+([smhdw]|min|ms|us)*)+" x != null);
44     description = "tmpfiles.d(5) age format";
45   };
47   configFile = pkgs.writeText "privoxy.conf" (
48     concatStrings (
49       # Relative paths in some options are relative to confdir. Privoxy seems
50       # to parse the options in order of appearance, so this must come first.
51       # Nix however doesn't preserve the order in attrsets, so we have to
52       # hardcode confdir here.
53       [ "confdir ${pkgs.privoxy}/etc\n" ] ++ mapAttrsToList serialise cfg.settings
54     )
55   );
57   inspectAction = pkgs.writeText "inspect-all-https.action" ''
58     # Enable HTTPS inspection for all requests
59     {+https-inspection}
60     /
61   '';
67   ###### interface
69   options.services.privoxy = {
71     enable = mkEnableOption "Privoxy, non-caching filtering proxy";
73     enableTor = mkOption {
74       type = types.bool;
75       default = false;
76       description = ''
77         Whether to configure Privoxy to use Tor's faster SOCKS port,
78         suitable for HTTP.
79       '';
80     };
82     inspectHttps = mkOption {
83       type = types.bool;
84       default = false;
85       description = ''
86         Whether to configure Privoxy to inspect HTTPS requests, meaning all
87         encrypted traffic will be filtered as well. This works by decrypting
88         and re-encrypting the requests using a per-domain generated certificate.
90         To issue per-domain certificates, Privoxy must be provided with a CA
91         certificate, using the `ca-cert-file`,
92         `ca-key-file` settings.
94         ::: {.warning}
95         The CA certificate must also be added to the system trust roots,
96         otherwise browsers will reject all Privoxy certificates as invalid.
97         You can do so by using the option
98         {option}`security.pki.certificateFiles`.
99         :::
100       '';
101     };
103     certsLifetime = mkOption {
104       type = ageType;
105       default = "10d";
106       example = "12h";
107       description = ''
108         If `inspectHttps` is enabled, the time generated HTTPS
109         certificates will be stored in a temporary directory for reuse. Once
110         the lifetime has expired the directory will cleared and the certificate
111         will have to be generated again, on-demand.
113         Depending on the traffic, you may want to reduce the lifetime to limit
114         the disk usage, since Privoxy itself never deletes the certificates.
116         ::: {.note}
117         The format is that of the `tmpfiles.d(5)`
118         Age parameter.
119         :::
120       '';
121     };
123     userActions = mkOption {
124       type = types.lines;
125       default = "";
126       description = ''
127         Actions to be included in a `user.action` file. This
128         will have a higher priority and can be used to override all other
129         actions.
130       '';
131     };
133     userFilters = mkOption {
134       type = types.lines;
135       default = "";
136       description = ''
137         Filters to be included in a `user.filter` file. This
138         will have a higher priority and can be used to override all other
139         filters definitions.
140       '';
141     };
143     settings = mkOption {
144       type = types.submodule {
145         freeformType = configType;
147         options.listen-address = mkOption {
148           type = types.str;
149           default = "127.0.0.1:8118";
150           description = "Pair of address:port the proxy server is listening to.";
151         };
153         options.enable-edit-actions = mkOption {
154           type = types.bool;
155           default = false;
156           description = "Whether the web-based actions file editor may be used.";
157         };
159         options.actionsfile = mkOption {
160           type = types.listOf types.str;
161           # This must come after all other entries, in order to override the
162           # other actions/filters installed by Privoxy or the user.
163           apply =
164             x: x ++ optional (cfg.userActions != "") (toString (pkgs.writeText "user.actions" cfg.userActions));
165           default = [
166             "match-all.action"
167             "default.action"
168           ];
169           description = ''
170             List of paths to Privoxy action files. These paths may either be
171             absolute or relative to the privoxy configuration directory.
172           '';
173         };
175         options.filterfile = mkOption {
176           type = types.listOf types.str;
177           default = [ "default.filter" ];
178           apply =
179             x: x ++ optional (cfg.userFilters != "") (toString (pkgs.writeText "user.filter" cfg.userFilters));
180           description = ''
181             List of paths to Privoxy filter files. These paths may either be
182             absolute or relative to the privoxy configuration directory.
183           '';
184         };
185       };
186       default = { };
187       example = literalExpression ''
188         { # Listen on IPv6 only
189           listen-address = "[::]:8118";
191           # Forward .onion requests to Tor
192           forward-socks5 = ".onion localhost:9050 .";
194           # Log redirects and filters
195           debug = [ 128 64 ];
196           # This is equivalent to writing these lines
197           # in the Privoxy configuration file:
198           # debug 128
199           # debug 64
200         }
201       '';
202       description = ''
203         This option is mapped to the main Privoxy configuration file.
204         Check out the Privoxy user manual at
205         <https://www.privoxy.org/user-manual/config.html>
206         for available settings and documentation.
208         ::: {.note}
209         Repeated settings can be represented by using a list.
210         :::
211       '';
212     };
214   };
216   ###### implementation
218   config = mkIf cfg.enable {
220     users.users.privoxy = {
221       description = "Privoxy daemon user";
222       isSystemUser = true;
223       group = "privoxy";
224     };
226     users.groups.privoxy = { };
228     systemd.tmpfiles.rules = optional cfg.inspectHttps "d ${cfg.settings.certificate-directory} 0770 privoxy privoxy ${cfg.certsLifetime}";
230     systemd.services.privoxy = {
231       description = "Filtering web proxy";
232       after = [
233         "network.target"
234         "nss-lookup.target"
235       ];
236       wantedBy = [ "multi-user.target" ];
237       serviceConfig = {
238         User = "privoxy";
239         Group = "privoxy";
240         ExecStart = "${pkgs.privoxy}/bin/privoxy --no-daemon ${configFile}";
241         PrivateDevices = true;
242         PrivateTmp = true;
243         ProtectHome = true;
244         ProtectSystem = "full";
245       };
246       unitConfig = mkIf cfg.inspectHttps {
247         ConditionPathExists = with cfg.settings; [
248           ca-cert-file
249           ca-key-file
250         ];
251       };
252     };
254     services.tor.settings.SOCKSPort = mkIf cfg.enableTor [
255       # Route HTTP traffic over a faster port (without IsolateDestAddr).
256       {
257         addr = "127.0.0.1";
258         port = 9063;
259         IsolateDestAddr = false;
260       }
261     ];
263     services.privoxy.settings =
264       {
265         user-manual = "${pkgs.privoxy}/share/doc/privoxy/user-manual";
266         # This is needed for external filters
267         temporary-directory = "/tmp";
268         filterfile = [ "default.filter" ];
269         actionsfile = [
270           "match-all.action"
271           "default.action"
272         ] ++ optional cfg.inspectHttps (toString inspectAction);
273       }
274       // (optionalAttrs cfg.enableTor {
275         forward-socks5 = "/ 127.0.0.1:9063 .";
276         toggle = true;
277         enable-remote-toggle = false;
278         enable-edit-actions = false;
279         enable-remote-http-toggle = false;
280       })
281       // (optionalAttrs cfg.inspectHttps {
282         # This allows setting absolute key/crt paths
283         ca-directory = "/var/empty";
284         certificate-directory = "/run/privoxy/certs";
285         trusted-cas-file = "/etc/ssl/certs/ca-certificates.crt";
286       });
288   };
290   imports =
291     let
292       top = x: [
293         "services"
294         "privoxy"
295         x
296       ];
297       setting = x: [
298         "services"
299         "privoxy"
300         "settings"
301         x
302       ];
303     in
304     [
305       (mkRenamedOptionModule (top "enableEditActions") (setting "enable-edit-actions"))
306       (mkRenamedOptionModule (top "listenAddress") (setting "listen-address"))
307       (mkRenamedOptionModule (top "actionsFiles") (setting "actionsfile"))
308       (mkRenamedOptionModule (top "filterFiles") (setting "filterfile"))
309       (mkRemovedOptionModule (top "extraConfig") ''
310         Use services.privoxy.settings instead.
311         This is part of the general move to use structured settings instead of raw
312         text for config as introduced by RFC0042:
313         https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md
314       '')
315     ];
317   meta.maintainers = with lib.maintainers; [ rnhmjoj ];