import ./make-test-python.nix ({ lib, pkgs, ... }:

let
  # Note: For some reason Privoxy can't issue valid
  # certificates if the CA is generated using gnutls :(
  certs = pkgs.runCommand "example-certs"
    { buildInputs = [ pkgs.openssl ]; }
    ''
      mkdir $out

      # generate CA keypair
      openssl req -new -nodes -x509 \
        -extensions v3_ca -keyout $out/ca.key \
        -out $out/ca.crt -days 365 \
        -subj "/O=Privoxy CA/CN=Privoxy CA"

      # generate server key/signing request
      openssl genrsa -out $out/server.key 3072
      openssl req -new -key $out/server.key \
        -out server.csr -sha256 \
        -subj "/O=An unhappy server./CN=example.com"

      # sign the request/generate the certificate
      openssl x509 -req -in server.csr -CA $out/ca.crt \
      -CAkey $out/ca.key -CAcreateserial -out $out/server.crt \
      -days 500 -sha256
    '';
in

{
  name = "privoxy";
  meta = with lib.maintainers; {
    maintainers = [ rnhmjoj ];
  };

  nodes.machine = { ... }: {
    services.nginx.enable = true;
    services.nginx.virtualHosts."example.com" = {
      addSSL = true;
      sslCertificate = "${certs}/server.crt";
      sslCertificateKey = "${certs}/server.key";
      locations."/".root = pkgs.writeTextFile
        { name = "bad-day";
          destination = "/how-are-you/index.html";
          text = "I've had a bad day!\n";
        };
      locations."/ads".extraConfig = ''
        return 200 "Hot Nixpkgs PRs in your area. Click here!\n";
      '';
    };

    services.privoxy = {
      enable = true;
      inspectHttps = true;
      settings = {
        ca-cert-file = "${certs}/ca.crt";
        ca-key-file  = "${certs}/ca.key";
        debug = 65536;
      };
      userActions = ''
        {+filter{positive}}
        example.com

        {+block{Fake ads}}
        example.com/ads
      '';
      userFilters = ''
        FILTER: positive This is a filter example.
        s/bad/great/ig
      '';
    };

    security.pki.certificateFiles = [ "${certs}/ca.crt" ];

    networking.hosts."::1" = [ "example.com" ];
    networking.proxy.httpProxy = "http://localhost:8118";
    networking.proxy.httpsProxy = "http://localhost:8118";
  };

  nodes.machine_socks4  = { ... }: { services.privoxy = { enable = true; settings.forward-socks4  = "/ 127.0.0.1:9050 ."; }; };
  nodes.machine_socks4a = { ... }: { services.privoxy = { enable = true; settings.forward-socks4a = "/ 127.0.0.1:9050 ."; }; };
  nodes.machine_socks5  = { ... }: { services.privoxy = { enable = true; settings.forward-socks5  = "/ 127.0.0.1:9050 ."; }; };
  nodes.machine_socks5t = { ... }: { services.privoxy = { enable = true; settings.forward-socks5t = "/ 127.0.0.1:9050 ."; }; };

  testScript =
    ''
      with subtest("Privoxy is running"):
          machine.wait_for_unit("privoxy")
          machine.wait_for_open_port(8118)
          machine.succeed("curl -f http://config.privoxy.org")

      with subtest("Privoxy can filter http requests"):
          machine.wait_for_open_port(80)
          assert "great day" in machine.succeed(
              "curl -sfL http://example.com/how-are-you? | tee /dev/stderr"
          )

      with subtest("Privoxy can filter https requests"):
          machine.wait_for_open_port(443)
          assert "great day" in machine.succeed(
              "curl -sfL https://example.com/how-are-you? | tee /dev/stderr"
          )

      with subtest("Blocks are working"):
          machine.wait_for_open_port(443)
          machine.fail("curl -f https://example.com/ads 1>&2")
          machine.succeed("curl -f https://example.com/PRIVOXY-FORCE/ads 1>&2")

      with subtest("Temporary certificates are cleaned"):
          # Count current certificates
          machine.succeed("test $(ls /run/privoxy/certs | wc -l) -gt 0")
          # Forward in time 12 days, trigger the timer..
          machine.succeed("date -s \"$(date --date '12 days')\"")
          machine.systemctl("start systemd-tmpfiles-clean")
          # ...and count again
          machine.succeed("test $(ls /run/privoxy/certs | wc -l) -eq 0")

      with subtest("Privoxy supports socks upstream proxies"):
          for m in [machine_socks4, machine_socks4a, machine_socks5, machine_socks5t]:
              m.wait_for_unit("privoxy")
              m.wait_for_open_port(8118)
              # We expect a 503 error because the dummy upstream proxy is not reachable.
              # In issue #265654, instead privoxy segfaulted causing curl to exit with "Empty reply from server".
              m.succeed("http_proxy=http://localhost:8118 curl -v http://does-not-exist/ 2>&1 | grep 'HTTP/1.1 503'")
    '';
})
