anchor.diff:  
     ###### interface
   
  -  options = {
  -
  -    services.privoxy = {
  -
  -      enable = mkOption {
  -        type = types.bool;
  -        default = false;
  -        description = ''
  -          Whether to enable the Privoxy non-caching filtering proxy.
  -        '';
  +  options.services.privoxy = {
  +
  +    enable = mkEnableOption "Privoxy, non-caching filtering proxy";
  +
  +    enableTor = mkOption {
  +      type = types.bool;
  +      default = false;
  +      description = ''
  +        Whether to configure Privoxy to use Tor's faster SOCKS port,
  +        suitable for HTTP.
  +      '';
  +    };
  +
  +    inspectHttps = mkOption {
  +      type = types.bool;
  +      default = false;
  +      description = ''
  +        Whether to configure Privoxy to inspect HTTPS requests, meaning all
  +        encrypted traffic will be filtered as well. This works by decrypting
  +        and re-encrypting the requests using a per-domain generated certificate.
  +
  +        To issue per-domain certificates, Privoxy must be provided with a CA
  +        certificate, using the <literal>ca-cert-file</literal>,
  +        <literal>ca-key-file</literal> settings.
  +
  +        <warning><para>
  +          The CA certificate must also be added to the system trust roots,
  +          otherwise browsers will reject all Privoxy certificates as invalid.
  +          You can do so by using the option
  +          <option>security.pki.certificateFiles</option>.
  +        </para></warning>
  +      '';
  +    };
  +
  +    certsLifetime = mkOption {
  +      type = ageType;
  +      default = "10d";
  +      example = "12h";
  +      description = ''
  +        If <literal>inspectHttps</literal> is enabled, the time generated HTTPS
  +        certificates will be stored in a temporary directory for reuse. Once
  +        the lifetime has expired the directory will cleared and the certificate
  +        will have to be generated again, on-demand.
  +
  +        Depending on the traffic, you may want to reduce the lifetime to limit
  +        the disk usage, since Privoxy itself never deletes the certificates.
  +
  +        <note><para>The format is that of the <literal>tmpfiles.d(5)</literal>
  +        Age parameter.</para></note>
  +      '';
  +    };
  +
  +    userActions = mkOption {
  +      type = types.lines;
  +      default = "";
  +      description = ''
  +        Actions to be included in a <literal>user.action</literal> file. This
  +        will have a higher priority and can be used to override all other
  +        actions.
  +      '';
  +    };
  +
  +    userFilters = mkOption {
  +      type = types.lines;
  +      default = "";
  +      description = ''
  +        Filters to be included in a <literal>user.filter</literal> file. This
  +        will have a higher priority and can be used to override all other
  +        filters definitions.
  +      '';
  +    };
  +
  +    settings = mkOption {
  +      type = types.submodule {
  +        freeformType = configType;
  +
  +        options.listen-address = mkOption {
  +          type = types.str;
  +          default = "127.0.0.1:8118";
  +          description = "Pair of address:port the proxy server is listening to.";
  +        };
  +
  +        options.enable-edit-actions = mkOption {
  +          type = types.bool;
  +          default = false;
  +          description = "Whether the web-based actions file editor may be used.";
  +        };
  +
  +        options.actionsfile = mkOption {
  +          type = types.listOf types.str;
  +          # This must come after all other entries, in order to override the
  +          # other actions/filters installed by Privoxy or the user.
  +          apply = x: x ++ optional (cfg.userActions != "")
  +            (toString (pkgs.writeText "user.actions" cfg.userActions));
  +          default = [ "match-all.action" "default.action" ];
  +          description = ''
  +            List of paths to Privoxy action files. These paths may either be
  +            absolute or relative to the privoxy configuration directory.
  +          '';
  +        };
  +
  +        options.filterfile = mkOption {
  +          type = types.listOf types.str;
  +          default = [ "default.filter" ];
  +          apply = x: x ++ optional (cfg.userFilters != "")
  +            (toString (pkgs.writeText "user.filter" cfg.userFilters));
  +          description = ''
  +            List of paths to Privoxy filter files. These paths may either be
  +            absolute or relative to the privoxy configuration directory.
  +          '';
  +        };
         };
  -
  -      listenAddress = mkOption {
  -        type = types.str;
  -        default = "127.0.0.1:8118";
  -        description = ''
  -          Address the proxy server is listening to.
  -        '';
  -      };
  -
  -      actionsFiles = mkOption {
  -        type = types.listOf types.str;
  -        example = [ "match-all.action" "default.action" "/etc/privoxy/user.action" ];
  -        default = [ "match-all.action" "default.action" ];
  -        description = ''
  -          List of paths to Privoxy action files.
  -          These paths may either be absolute or relative to the privoxy configuration directory.
  -        '';
  -      };
  -
  -      filterFiles = mkOption {
  -        type = types.listOf types.str;
  -        example = [ "default.filter" "/etc/privoxy/user.filter" ];
  -        default = [ "default.filter" ];
  -        description = ''
  -          List of paths to Privoxy filter files.
  -          These paths may either be absolute or relative to the privoxy configuration directory.
  -        '';
  -      };
  -
  -      enableEditActions = mkOption {
  -        type = types.bool;
  -        default = false;
  -        description = ''
  -          Whether or not the web-based actions file editor may be used.
  -        '';
  -      };
  -
  -      enableTor = mkOption {
  -        type = types.bool;
  -        default = false;
  -        description = ''
  -          Whether to configure Privoxy to use Tor's faster SOCKS port,
  -          suitable for HTTP.
  -        '';
  -      };
  -
  -      extraConfig = mkOption {
  -        type = types.lines;
  -        default = "" ;
  -        description = ''
  -          Extra configuration. Contents will be added verbatim to the configuration file.
  -        '';
  -      };
  +      default = {};
  +      example = literalExample ''
  +        { listen-address = "[::]:8118";               # listen on IPv6 only
  +          forward-socks5 = ".onion localhost:9050 ."; # forward .onion requests to Tor
  +        }
  +      '';
  +      description = ''
  +        This option is mapped to the main Privoxy configuration file.
  +        Check out the Privoxy user manual at
  +        <link xlink:href="file://${pkgs.privoxy}/share/doc/privoxy/user-manual/config.html"/>
  +        for available settings and documentation.
  +      '';
       };
   
     };
  
positive.code:   config = mkIf cfg.enable {
  
      users.users.privoxy = {
        isSystemUser = true;
        home = "/var/empty";
        group = "privoxy";
      };
  
      users.groups.privoxy = {};
  
      systemd.services.privoxy = {
        description = "Filtering web proxy";
        after = [ "network.target" "nss-lookup.target" ];
        wantedBy = [ "multi-user.target" ];
        serviceConfig.ExecStart = "${privoxy}/bin/privoxy --no-daemon --user privoxy ${confFile}";
  
        serviceConfig.PrivateDevices = true;
        serviceConfig.PrivateTmp = true;
        serviceConfig.ProtectHome = true;
        serviceConfig.ProtectSystem = "full";
      };
  
      services.tor.settings.SOCKSPort = mkIf cfg.enableTor [
  
negative.code: 
  let
  
    cfg = config.services.privoxy;
  
    serialise = name: val:
           if isList val then concatMapStrings (serialise name) val
      else if isBool val then serialise name (if val then "1" else "0")
      else "${name} ${toString val}\n";
  
    configType = with types;
      let atom = oneOf [ int bool string path ];
      in attrsOf (either atom (listOf atom))
      // { description = ''
            privoxy configuration type. The format consists of an attribute
            set of settings. Each setting can be either a value (integer, string,
            boolean or path) or a list of such values.
          '';
         };
  
    ageType = types.str // {
      check = x:
        isString x &&
        (builtins.match "([0-9]+([smhdw]|min|ms|us)*)+" x != null);
      description = "tmpfiles.d(5) age format";
    };
  
    configFile = pkgs.writeText "privoxy.conf"
      (concatStrings (
        # Relative paths in some options are relative to confdir. Privoxy seems
        # to parse the options in order of appearance, so this must come first.
        # Nix however doesn't preserve the order in attrsets, so we have to
        # hardcode confdir here.
        [ "confdir ${pkgs.privoxy}/etc\n" ]
        ++ mapAttrsToList serialise cfg.settings
      ));
  
    inspectAction = pkgs.writeText "inspect-all-https.action"
      ''
        # Enable HTTPS inspection for all requests
        {+https-inspection}
        /
      '';
  
  in
  
  