# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:sw=4:ts=4:sts=4

PortSystem          1.0

name                adblock2privoxy
version             3.0.1
revision            0
categories          www haskell
maintainers         {ieee.org:s.t.smith @essandess} openmaintainer
license             GPL-3

description         Convert adblock config files to privoxy format
long_description    {*}${description}. \
                    AdBlock Plus browser plugin has great block list \
                    files provided by big community, but it is client \
                    software and cannot work on a server as proxy. \
                    Privoxy proxy has good potential to block ads at \
                    server side, but it experiences acute shortage of \
                    updated block lists.  This software converts \
                    adblock lists to privoxy config files format. \
                    Almost all adblock features are supported \
                    including block/unblock requests (on privoxy) all \
                    syntax features are supported except for regex \
                    templates matching host name hide/unhide page \
                    elements (via CSS) all syntax features are \
                    supported all block request options except for \
                    outdated ones: Supported: script, image, \
                    stylesheet, object, xmlhttprequest, \
                    object-subrequest, subdocument, document, \
                    elemhide, other, popup, third-party, domain=..., \
                    match-case, donottrack.

homepage            https://github.com/essandess/adblock2privoxy

checksums           rmd160  e221933eddf5d99dac66ecbfe613c2a18bd43e3f \
                    sha256  5b52166ce102d9cc9f00707792c180c153399d12dae06803f5fc7a7286d7afbe \
                    size    52187

depends_lib-append  port:zlib

depends_run-append  port:bash \
                    port:nginx \
                    port:privoxy \
                    port:wget

depends_skip_archcheck \
                    privoxy

variant initialize_always \
    description {Always initialize all configuration files. Intended\
        for development and troubleshooting only. Working deployments\
        must disable this variant to prevent configuration files\
        being overwritten at the next upgrade. Existing configuration\
        files are not overwritten by default.} {
    pre-fetch {
        ui_warn \
            "All configuration files will be initialized because\
            the variant +initialize_always is set. Please disable\
            this variant for working deployments."
    }
}

# use domain or ip with port, e.g. 127.0.0.1:8119
set adblock2privoxy_css_server \
                    127.0.0.1:8119

# relative paths to ${prefix}
set ab2p_datadir    share/${name}
    
post-extract {
    # Fix for cabal data-files hardcoded path in binary
    # See:
    # https://github.com/commercialhaskell/stack/issues/848
    # https://github.com/commercialhaskell/stack/issues/4857
    # https://github.com/haskell/cabal/issues/462
    # https://github.com/haskell/cabal/issues/3586
    xinstall -m 0644 -W ${worksrcpath} \
                    ${filespath}/Paths_NAME.hs ./src/Paths_${name}.hs

    reinplace "s|@PREFIX@|${prefix}|g" \
                    ${worksrcpath}/src/Paths_${name}.hs
    reinplace "s|@NAME@|${name}|g" \
                    ${worksrcpath}/src/Paths_${name}.hs
    reinplace -E "s|(Version\[\[:space:\]\]+)\\\[\[\[:digit:\]\]+(,\[\[:digit:\]\]+){1,4}\\\]|\\1\[[join [split ${version} .] ,]\]|" \
                    ${worksrcpath}/src/Paths_${name}.hs
}

variant stack \
    description {Use stack to build.} {}

if { [variant_isset "stack"] } {
    PortGroup       haskell_stack 1.0

    post-destroot {
        xinstall -d ${destroot}${prefix}/share/${name}/templates
        # cabal's data-files datadir: ${name}_datadir from Paths_${name}.hs
        fs-traverse f ${worksrcpath}/.stack-work {
            if { [string match "ab2p.system.*" [file tail ${f}]] } {
                xinstall -m 0644 ${f} \
                    ${destroot}${prefix}/share/${name}/templates
            }
        }
    }
} else {
    PortGroup       haskell_cabal 1.0

    build.target-append \
                    --allow-newer
    
    test.run        yes
    test.target     ${name}-test \
                    --allow-newer
    
    post-destroot {
        xinstall -d ${destroot}${prefix}/share/${name}/templates
        foreach f [glob ${worksrcpath}/templates/ab2p.system.*] {
            xinstall -m 0644 ${f} \
                    ${destroot}${prefix}/share/${name}/templates
        }
    }
}

post-destroot {
    xinstall -m 0644 -W ${worksrcpath} \
        man/man1/${name}.1 \
        ${destroot}${prefix}/share/man/man1

    xinstall -d \
        ${destroot}${prefix}/etc/${name} \
        ${destroot}${prefix}/etc/${name}/bin \
        ${destroot}${prefix}/etc/${name}/css \
        ${destroot}${prefix}/etc/${name}/privoxy

    xinstall -m 0755 -W ${filespath} \
        adblock2privoxy_initialize.sh \
        ${destroot}${prefix}/etc/${name}/bin
    reinplace "s|@PREFIX@|${prefix}|g" \
        ${destroot}${prefix}/etc/${name}/bin/adblock2privoxy_initialize.sh

    xinstall -m 0644 -W ${filespath} \
        adblock2privoxy_blocklist.txt \
        ${destroot}${prefix}/etc/${name}/adblock2privoxy_blocklist.txt.macports
    xinstall -m 0644 -W ${filespath} \
        nginx.conf \
        ${destroot}${prefix}/etc/${name}/nginx.conf.macports
    xinstall -m 0644 -W ${filespath} \
        default.html \
        ${destroot}${prefix}/etc/${name}/css/default.html.macports
    reinplace "s|@PREFIX@|${prefix}|g" \
        ${destroot}${prefix}/etc/${name}/nginx.conf.macports
}

set tls_ca_dir      ${prefix}/etc/${name}/ca.macports
set tls_cert_dir    ${prefix}/etc/${name}/certs

set optional_proxy  http://localhost:8080
set proxy_message \
        "Startupitem configured to use a proxy. Please set the
environment variables http_proxy and https_proxy and
install this port variant a sudo command that sets
these variables, e.g.:

\tsudo -E port install ${name} +proxy_settings
\tsudo env http_proxy=${optional_proxy} port install ${name} +proxy_settings

or edit the startupitem:

\t${prefix}/etc/${startupitem.location}/org.macports.${name}/org.macports.${name}.plist

to change the proxy settings and reload the port."

variant proxy_settings \
    description {Include proxy settings in the startupitem plist.} {
    # Note: `sudo launchctl setenv` is no longer functional on macOS Ventura+
    notes-append ${proxy_message}
    post-activate {
        if { [info exists ::env(http_proxy)] } {
            set http_proxy $env(http_proxy)
        } else {
            set http_proxy ${optional_proxy}
        }
        if { [info exists ::env(https_proxy)] } {
            set https_proxy $env(https_proxy)
        } else {
            set https_proxy ${http_proxy}
        }
        # org.macports.adblock2privoxy
        reinplace \
            "s|^<key>ProgramArguments</key>|<key>EnvironmentVariables</key>\\
<dict>\\
	<key>http_proxy</key>\\
	<string>${http_proxy}</string>\\
	<key>https_proxy</key>\\
	<string>${https_proxy}</string>\\
</dict>\\
&|" \
        ${prefix}/etc/${startupitem.location}/org.macports.${name}/org.macports.${name}.plist
        ui_msg "${proxy_message}

The startupitem is configured to use the proxy settings:

\thttp_proxy=${http_proxy}
\thttps_proxy=${https_proxy}
"
    }
}

variant https_inspection \
    description {HTTPS CSS Server for use with 'privoxy +https_inspection'.} {
    depends_build-append \
                    port:sf-pwgen

    depends_lib-append \
                    path:bin/openssl:openssl

    # random 4-word-based passphrase
    proc correct_horse_battery_staple {} {
        # ignore errors from sf-pwgen if the password is shorter than requested
        set passphrase \
            [join [exec sh -c "sf-pwgen \
                --algorithm memorable --count 2 --length 16 \
                    2>/dev/null || true"] -]
        # set random passphrase if sf-pwgen's is too short for some reason
        if {[string length ${passphrase}] < 20} {
            set passphrase \
                [exec sh -c "openssl rand -base64 23 2>/dev/null \
                    | sed 's|=*\$||' || true"]
        }
        return ${passphrase}
    }

    post-destroot {
        # TLS Root CA configuration
        xinstall -m 0770 -d ${destroot}${tls_cert_dir}
        xinstall -m 0700 -d ${destroot}${tls_ca_dir}
        destroot.keepdirs-append \
                    ${destroot}${tls_cert_dir}
        xinstall -m 0644 -W ${filespath} \
                    openssl.cnf \
                    ${destroot}${tls_ca_dir}/openssl.cnf.macports
    }

    pre-activate {
        if { [file exists ${tls_ca_dir}] } {
            delete  ${tls_ca_dir}.previous
            move    ${tls_ca_dir} \
                    ${tls_ca_dir}.previous
        }
    }

    post-activate {
        foreach f [list \
            ${tls_ca_dir}/openssl.cnf \
            ] {
            if { [variant_isset "initialize_always"]
                 && [file exists ${f}]
                } {
                delete ${f}.previous
                move \
                    ${f} \
                    ${f}.previous
            }
            if { [variant_isset "initialize_always"]
                || ![file exists ${f}]
                } {
                if { [file isfile ${f}.macports] } {
                    xinstall -m 0644 \
                        ${f}.macports \
                        ${f}
                }
            }
        }

        # CA passphrase
        # generate a strong password, use for openssl -passin and -passout
        set tls_ca_passphrase \
            [correct_horse_battery_staple]
        set tls_ca_passphrase_fd \
            [open ${tls_ca_dir}/passphrase.txt w 0600]
        # -passin or -passout
        puts ${tls_ca_passphrase_fd} \
            ${tls_ca_passphrase}
        # -passout
        puts ${tls_ca_passphrase_fd} \
            ${tls_ca_passphrase}
        close ${tls_ca_passphrase_fd}
        # create the root CA
        system -W ${tls_ca_dir} \
            "sh <<ADBLOCK2PRIVOXY_PKI
            # initialize
            touch index.txt
            echo 1000 > serial

            # CA encrypted key
            # EC
            openssl genpkey -out ca.key.pem -algorithm EC \\
                -pkeyopt ec_paramgen_curve:P-384 -aes256 \\
                -pass file:passphrase.txt

            # RSA
            # openssl genpkey -out ca.key.pem -algorithm RSA \\
            #     -pkeyopt rsa_keygen_bits:2048 -aes256 \\
            #     -passout file:passphrase.txt

            chmod go-rw ca.key.pem

            # CA certificate
            openssl req -config openssl.cnf \\
                -new -x509 -days 1460 -sha384 \\
                -extensions v3_ca \\
                -out ca.cert.pem -key ca.key.pem \\
                -passin file:passphrase.txt -batch

            # CA certificate openssl self-verification
            openssl verify -CAfile ca.cert.pem ca.cert.pem

            # Convert to .cer DER and .p12 for other uses
            openssl x509 -outform der -in ca.cert.pem -out ca.cer

            # https://github.com/essandess/macports-ports/pull/new/privoxy
            openssl pkcs12 -legacy -export -out ca.p12 \\
                -inkey ca.key.pem -in ca.cert.pem \\
                -passin file:passphrase.txt \\
                -passout file:passphrase.txt
            # verify .p12 passphrase
            openssl pkcs12 -legacy -noout -in ca.p12 -passin file:passphrase.txt

            # Server certificates

            # Server certificate encrypted key and decrypted key
            openssl genpkey -out adblock2privoxy-nginx.key.pem \
                -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -aes256 \
                -pass file:passphrase.txt
            openssl ec -in adblock2privoxy-nginx.key.pem \
               -passin file:passphrase.txt \
               -out adblock2privoxy-nginx.key.pem.decrypted
            chmod go-rwx adblock2privoxy-nginx.key.pem.decrypted

            # Server certificate CSR
            openssl req -config openssl.cnf -new -sha384 \
                 -key adblock2privoxy-nginx.key.pem \
                 -passin file:passphrase.txt \
                 -out adblock2privoxy-nginx.csr.pem -batch

            # Server certificate (825 days maximum validity)
            # https://support.apple.com/en-us/HT210176
            openssl ca -config openssl.cnf -days 825 -notext -md sha384 \
                -extensions server_cert -in adblock2privoxy-nginx.csr.pem \
                -out adblock2privoxy-nginx.cert.pem \
                -passin file:passphrase.txt \
                -subj '/CN=adblock2privoxy-nginx' -batch

            # Server certificate chain of trust
            cat adblock2privoxy-nginx.cert.pem ca.cert.pem \
                > adblock2privoxy-nginx.chain.pem

            # Server certificate and chain validity
            openssl verify -CAfile ca.cert.pem adblock2privoxy-nginx.cert.pem
            openssl verify -CAfile ca.cert.pem adblock2privoxy-nginx.chain.pem
ADBLOCK2PRIVOXY_PKI
"

        if { ![file exists ${tls_cert_dir}/adblock2privoxy-nginx.cert.pem]
            || ![file exists ${tls_cert_dir}/adblock2privoxy-nginx.key.pem.decrypted]
            } {
            xinstall -m 0664 \
                    ${tls_ca_dir}/ca.cert.pem \
                    ${tls_cert_dir}
            xinstall -m 0664 \
                    ${tls_ca_dir}/ca.key.pem \
                    ${tls_cert_dir}
            xinstall -m 0600 \
                    ${tls_ca_dir}/passphrase.txt \
                    ${tls_cert_dir}
            xinstall -m 0664 \
                    ${tls_ca_dir}/adblock2privoxy-nginx.cert.pem \
                    ${tls_cert_dir}
            xinstall -m 0664 \
                    ${tls_ca_dir}/adblock2privoxy-nginx.chain.pem \
                    ${tls_cert_dir}
            xinstall -m 0664 \
                    ${tls_ca_dir}/adblock2privoxy-nginx.key.pem \
                    ${tls_cert_dir}
            xinstall -m 0600 \
                    ${tls_ca_dir}/adblock2privoxy-nginx.key.pem.decrypted \
                    ${tls_cert_dir}
        }

        if { ![file exists ${tls_cert_dir}/dhparam.pem]
            } {
            system -W ${tls_ca_dir} \
                "sh <<ADBLOCK2PRIVOXY_DH
                # DH params
                openssl dhparam -out dhparam.pem 2048
ADBLOCK2PRIVOXY_DH
"

            xinstall -m 0664 \
                    ${tls_ca_dir}/dhparam.pem \
                    ${tls_cert_dir}
        }

        if { ![file exists ${tls_cert_dir}/openssl.cnf]
            } {
            xinstall -m 0664 \
                    ${tls_ca_dir}/openssl.cnf \
                    ${tls_cert_dir}
        }
    }

    # check adblock2privoxy-nginx certificate validity
    # 30 days = 2592000 seconds
    post-activate {
        set ab2p_cert_valid [exec /bin/sh -c \
            "if openssl x509 -checkend 2592000 -noout \
                -in \"${tls_cert_dir}/adblock2privoxy-nginx.cert.pem\" \
                1>/dev/null 2>&1; \
                    then echo 'WONT_EXPIRE'; \
                    else echo 'WILL_EXPIRE'; fi"]
        if {[string trim ${ab2p_cert_valid}] ne {WONT_EXPIRE}} {
            ui_warn "Certificate ${tls_cert_dir}/adblock2privoxy-nginx.cert.pem expired or will expire within 30 days."
        }
    }

    notes-append \
       "Configure adblock2privoxy PKI by creating a\
        certificate from e.g. Privoxy's certificate authority (CA). As sudo:

        # Example, more likely use ${prefix}/etc/privoxy/CA
        cp -R ${prefix}/etc/privoxy/ca.macports ca.adblock2privoxy \\
          && cd ca.adblock2privoxy
        cp ${tls_cert_dir}/openssl.cnf .
        # edit openssl.cnf for your local organizationName, commonName, etc.

        # initialize
        touch index.txt
        echo 1000 > serial

        # Server certificates

        # Server certificate encrypted key and decrypted key
        openssl genpkey -out adblock2privoxy-nginx.key.pem \\
            -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -aes256 \\
            -pass file:passphrase.txt
        openssl ec -in adblock2privoxy-nginx.key.pem \\
           -passin file:passphrase.txt \\
           -out adblock2privoxy-nginx.key.pem.decrypted
        chmod go-rwx adblock2privoxy-nginx.key.pem.decrypted

        # Server certificate CSR
        openssl req -config openssl.cnf -new -sha384 \\
             -key adblock2privoxy-nginx.key.pem \\
             -passin file:passphrase.txt \\
             -out adblock2privoxy-nginx.csr.pem -batch

        # Server certificate (825 days maximum validity)
        # https://support.apple.com/en-us/HT210176
        openssl ca -config openssl.cnf -days 825 -notext -md sha384 \\
            -extensions server_cert -in adblock2privoxy-nginx.csr.pem \\
            -out adblock2privoxy-nginx.cert.pem \\
            -passin file:passphrase.txt \\
            -subj '/CN=adblock2privoxy-nginx' -batch

        # Server certificate chain of trust
        cat adblock2privoxy-nginx.cert.pem ca.cert.pem \\
            > adblock2privoxy-nginx.chain.pem

        # Server certificate and chain validity
        openssl verify -CAfile ca.cert.pem adblock2privoxy-nginx.cert.pem
        openssl verify -CAfile ca.cert.pem adblock2privoxy-nginx.chain.pem

        # Install the adblock2privoxy PKI
        cp -p ca.key.pem ca.cert.pem passphrase.txt \\
            adblock2privoxy-nginx.cert.pem adblock2privoxy-nginx.chain.pem \\
            adblock2privoxy-nginx.key.pem \\
            adblock2privoxy-nginx.key.pem.decrypted \\
            ${tls_cert_dir}
"
}

default_variants-append \
                    +https_inspection

# default: empty flag
set ab2p_use_http_flag \
                    {}

if { ![variant_isset "https_inspection"] } {
    set ab2p_use_http_flag \
                    {-u}
}

startupitem.create  yes
startupitems \
    name            ${name} \
    init [list      "if \[ -f \"\${prefix}/etc/adblock2privoxy/ADBLOCK2PRIVOXY.env\" ]; then" \
                    "\tset -a" \
                    "\t. <(grep -E -o -e '^\[\[:alnum:]_]+=\[^\[:space:]\;]+\$' \"${prefix}/etc/adblock2privoxy/ADBLOCK2PRIVOXY.env\" | grep -E -v '^\[\[:space:]]*(#|\$)|\\\$\\(|`')" \
                    "\tset +a" \
                    "fi" \
                    "ADBLOCK2PRIVOXY_CSS_SERVER=\"\${ADBLOCK2PRIVOXY_CSS_SERVER:-${adblock2privoxy_css_server}}\"" \
    ] \
    start [list     "( IFS=\$'\\n' ADBLOCK2PRIVOXY_BLOCKLIST=(\$(grep -v -e '^ *#' < \"\${prefix}/etc/${name}/adblock2privoxy_blocklist.txt\" \\" \
                    "\t| while read -r t; do if \"\${prefix}/bin/wget\" --max-redirect=0 -S --spider \"\${t}\" 2>&1 | grep -q 'HTTP/1.1 200 OK'; then echo \"\${t}\"; fi done)); \\" \
                    "/bin/test -f \"\${prefix}/etc/adblock2privoxy/privoxy/ab2p.task\" \\" \
                    "&& \"\${prefix}/bin/adblock2privoxy\" -t \"\${prefix}/etc/adblock2privoxy/privoxy/ab2p.task\" \\" \
                    "|| \"\${prefix}/bin/adblock2privoxy\" -p \"\${prefix}/etc/adblock2privoxy/privoxy\" \\" \
                    "\t-w \"\${prefix}/etc/adblock2privoxy/css\" \\" \
                    "\t-d \"\${ADBLOCK2PRIVOXY_CSS_SERVER}\" ${ab2p_use_http_flag} \\" \
                    "\t\"\${ADBLOCK2PRIVOXY_BLOCKLIST\[@]}\" \\" \
                    ") && \"\${prefix}/bin/port\" reload privoxy" \
    ] \
    stop            "\"/usr/bin/kill -SIGUSR1 \\\"\$(/usr/bin/pgrep -u root ${name})\\\" 2>/dev/null\"" \
    pidfile         none

startupitems-append \
    name            ${name}-nginx \
    init            "pidfile=\"\${prefix}/var/run/nginx/nginx-adblock2privoxy.pid\"" \
    start [list     "\"\${prefix}/sbin/nginx\" \\" \
                    "\t-c \\" \
                    "\t\"\${prefix}/etc/${name}/nginx.conf\" \\" \
                    "\t-g \"daemon off;\"" \
    ] \
    stop [list      "if \[ -f \"\${pidfile}\" \]; then" \
                    "\t/usr/bin/kill \"\$(cat \"\${pidfile}\")\" \\" \
                    "\t\t&& /bin/rm -f \"\${pidfile}\" ;" \
                    "else" \
                    "\t/usr/bin/kill -SIGUSR1 \"\$(/usr/bin/pgrep -u root nginx)\" 2>/dev/null ;" \
                    "fi" \
    ]

post-destroot {
    # org.macports.adblock2privoxy
    reinplace -E \
        "1s|^(#!\[\[:space:]]*)/bin/sh|\\1/usr/bin/env bash|" \
        ${destroot}${prefix}/etc/${startupitem.location}/org.macports.${name}/${name}.wrapper

    reinplace \
        "s|^<key>ProgramArguments</key>|<key>StartCalendarInterval</key>\\
	<array>\\
		<dict>\\
			<key>Weekday</key>\\
			<integer>7</integer>\\
			<key>Hour</key>\\
			<integer>1</integer>\\
			<key>Minute</key>\\
			<integer>30</integer>\\
		</dict>\\
	</array>\\
	<key>StandardErrorPath</key>\\
	<string>${prefix}/var/log/${name}.log</string>\\
	<key>StandardOutPath</key>\\
	<string>${prefix}/var/log/${name}.log</string>\\
&|" \
        ${destroot}${prefix}/etc/${startupitem.location}/org.macports.${name}/org.macports.${name}.plist
}

post-activate {
    foreach f [list \
        ${prefix}/etc/${name}/adblock2privoxy_blocklist.txt \
        ${prefix}/etc/${name}/nginx.conf \
        ${prefix}/etc/${name}/css/default.html \
        ] {
        if { [variant_isset "initialize_always"]
             && [file exists ${f}]
            } {
            delete ${f}.previous
            move \
                ${f} \
                ${f}.previous
        }
        if { [variant_isset "initialize_always"]
             || ![file exists ${f}]
            } {
            if { [file isfile ${f}.macports] } {
                xinstall -m 0644 \
                    ${f}.macports \
                    ${f}
            }
        }
    }
}

notes "\
After initial installation, it is necessary to kickstart this launch daemon,\
which does not run at load:

  sudo launchctl kickstart -k system/org.macports.adblock2privoxy

The blocklist URLs are specified in the file\
${prefix}/etc/${name}/adblock2privoxy_blocklist.txt.

Example production run:

  adblock2privoxy -p ${prefix}/etc/adblock2privoxy/privoxy \\
    -w ${prefix}/etc/adblock2privoxy/css -d ${adblock2privoxy_css_server} \\
    \$(< ${prefix}/etc/${name}/adblock2privoxy_blocklist.txt)

Update run:

  adblock2privoxy -t ${prefix}/etc/adblock2privoxy/privoxy/ab2p.task

The CSS web server domain name or IP address is specified by the\
environment variable ADBLOCK2PRIVOXY_CSS_SERVER (with default value):

  ADBLOCK2PRIVOXY_CSS_SERVER=${adblock2privoxy_css_server}

To change this or site-specific environment variables, set them in the\
optional file

  ${prefix}/etc/adblock2privoxy/ADBLOCK2PRIVOXY.env

Please note that the macOS command `launchctl setenv` is now prohibited by SIP.
"

if { [variant_isset "initialize_always"] } {
    if {[exists notes]} {
        # leave a blank line after the existing notes
        notes-append ""
    }
    notes-append \
        "The variant +initialize_always is set, which initializes\
        all configuration files. Please disable this variant for\
        working deployments."
}
