privoxy-tls/service.nix

205 lines
5.5 KiB
Nix

{ config, pkgs, lib, ... }:
with lib;
let
cfgPrivoxy = config.services.privoxy;
cfg = cfgPrivoxy.tls-wrapper;
package = ./.;
action = pkgs.writeText "privoxy-tls.action" ''
{ +client-header-tagger{privoxy-tls-tagger} }
/
{ +forward-override{forward localhost:${toString cfg.rearPort}} }
TAG:.*?privoxy-tls
'';
filter = pkgs.writeText "privoxy-tls.filter" ''
CLIENT-HEADER-TAGGER: privoxy-tls-tagger
s@Tagged: privoxy-tls front@$0@i
'';
dataDir = "/var/lib/privoxy";
# make attributes only a default
mkDefaultAttrs = mapAttrs (n: v: mkDefault v);
# INI format with sections that may also contains a list
toSpecialINI = with lib; {
mkSectionName ? (name: escape [ "[" "]" ] name),
mkKeyValue ? generators.mkKeyValueDefault {} "="
}: attrsOfAttrs:
let
# map function to string for each key val
mapAttrsToStringsSep = sep: mapFn: attrs:
concatStringsSep sep (mapAttrsToList mapFn attrs);
stripPriority = val:
if val ? priority then val.content else val;
mkSectionVal = val:
if isList val
then concatMapStringsSep "\n" toString val
else generators.toKeyValue
{ inherit mkKeyValue; } val;
# handle both list and attributes
mkSection = sectName: sectValues: ''
[${mkSectionName sectName}]
${mkSectionVal (stripPriority sectValues)}
'';
in
# map input to ini sections
mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;
configFile = pkgs.writeText "config.ini"
(toSpecialINI {} cfg.settings);
python = pkgs.python3.withPackages (p: [ p.urllib3 ]);
in
{
###### interface
options = {
services.privoxy.tls-wrapper = {
enable = mkEnableOption ''
TLS proxy wrapper to allow privoxy to
inspect and modify HTTPS traffic.
'';
caCert = mkOption {
type = types.path;
description = ''
The CA certificate, in PEM format, that will be used
to reencrypt the traffic. This will be installed in
the local trust store.
'';
};
caKey = mkOption {
type = types.path;
description = ''
The CA key, in PEM format, associated to the certificate.
This will be copied to the privoxy-owned state directory
but not in the nix-store.
'';
};
frontPort = mkOption {
type = types.port;
default = 8117;
description = ''
The port the privoxy-tls front proxy will bind to.
This will replace the standard privoxy HTTP proxy in your settings.
'';
};
rearPort = mkOption {
type = types.port;
default = 8119;
description = ''
The port the privoxy-tls rear proxy will bind to.
This will be the proxy privoxy will forward TLS-stripped
HTTP traffic for reencryption.
'';
};
passthru = mkOption {
type = types.listOf types.str;
default = [];
example = [ "*.local" ];
description = ''
List of URLs configured for passthrough, meaning
the proxy will directly connect skipping privoxy.
'';
};
noVerify = mkOption {
type = types.listOf types.str;
default = [];
example = [ "localhost" ];
description = ''
List of URLs configured that the TLS verification
will ignore. For example use it for self-signed certs.
'';
};
logLevel = mkOption {
type = types.enum [ "DEBUG" "INFO" "WARNING" "ERROR" "CRITICAL" ];
default = "WARNING";
example = "The level of logging of privoxy-tls";
};
settings = mkOption {
type = types.attrs;
default = { };
example = literalExample ''
{
bypassURL = [ "example.com" ];
}
'';
description = ''
Privoxy-TLS settings. Use this option to configure not exposed in
a NixOS option or to bypass one. See the documentation at
<link xlink:href="https://maxwell.ydns.eu/git/rnhmjoj/privoxy-tls"/>
for the available options.
'';
};
};
};
###### implementation
config = mkIf cfg.enable {
# install custom CA
security.pki.certificateFiles = [ cfg.caCert ];
# tag traffic for the rear proxy server
services.privoxy.actionsFiles = [ (toString action) ];
services.privoxy.filterFiles = [ (toString filter) ];
users.users.privoxy-tls = {
group = "privoxy";
home = dataDir;
};
# default configuration
services.privoxy.tls-wrapper.settings = mkDefaultAttrs {
general = {
proxAddr = "http://${cfgPrivoxy.listenAddress}";
frontPort = cfg.frontPort;
rearPort = cfg.rearPort;
caCert = "${dataDir}/ca.crt";
certdir = "/tmp";
logLevel = cfg.logLevel;
};
noVerify = cfg.noVerify;
passthru = cfg.passthru;
};
systemd.services.privoxy-tls = {
description = "Privoxy TLS proxy wrapper.";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
User = "privoxy-tls";
PrivateTmp = true;
PermissionsStartOnly = true;
ExecStart = "${python}/bin/python ${package}/src/main.py -c ${configFile}";
};
preStart = ''
if ! test -f ${dataDir}/ca.crt; then
cat ${toString cfg.caCert} ${toString cfg.caKey} > ${dataDir}/ca.crt
fi
'';
};
};
}