at master 5.2 kB view raw
1{ lib, pkgs, ... }: 2let 3 # https://docs.mitmproxy.org/stable/concepts/certificates/#using-a-custom-certificate-authority 4 caCert = pkgs.runCommand "ca-cert" { } '' 5 touch $out 6 cat ${./common/acme/server/ca.key.pem} >> $out 7 cat ${./common/acme/server/ca.cert.pem} >> $out 8 ''; 9in 10{ 11 name = "mitmproxy"; 12 meta.maintainers = [ lib.teams.ngi.members ]; 13 14 nodes.machine = 15 { pkgs, ... }: 16 { 17 security.pki.certificateFiles = [ caCert ]; 18 19 services.getty.autologinUser = "root"; 20 21 environment.systemPackages = 22 let 23 # A counter. It has 2 functions: 24 # 1. GET /old and GET /new, to demostrate rewriting requests. 25 # 2. GET /counter and POST /counter, to demonstrate replaying requests. 26 counter = pkgs.writers.writePython3Bin "counter" { } '' 27 from http.server import BaseHTTPRequestHandler, HTTPServer 28 29 counter = 0 30 31 32 class HTTPRequestHandler(BaseHTTPRequestHandler): 33 def do_POST(self): 34 match self.path: 35 case "/counter": 36 global counter 37 counter += 1 38 self.send_response(204) 39 self.end_headers() 40 case _: 41 self.send_response(404) 42 self.end_headers() 43 44 def do_GET(self): 45 match self.path: 46 case "/counter": 47 self.send_response(200) 48 self.send_header("Content-type", "text/plain") 49 self.end_headers() 50 _ = self.wfile.write(str(counter).encode()) 51 case "/old": 52 self.send_response(200) 53 self.send_header("Content-type", "text/plain") 54 self.end_headers() 55 _ = self.wfile.write("fail".encode()) 56 case "/new": 57 self.send_response(200) 58 self.send_header("Content-type", "text/plain") 59 self.end_headers() 60 _ = self.wfile.write("success".encode()) 61 case _: 62 self.send_response(404) 63 self.end_headers() 64 65 66 server_address = ("", 8000) 67 server = HTTPServer(server_address, HTTPRequestHandler) 68 server.serve_forever() 69 ''; 70 in 71 [ 72 counter 73 pkgs.mitmproxy 74 pkgs.mitmproxy2swagger 75 ]; 76 }; 77 78 testScript = 79 let 80 addonScript = pkgs.writeText "addon-script" '' 81 def request(flow): 82 # https://docs.mitmproxy.org/stable/api/mitmproxy/http.html#Request 83 flow.request.path = "/new" 84 ''; 85 in 86 '' 87 def curl(command: str, proxy: bool = False): 88 if proxy: 89 command = "curl --proxy 127.0.0.1:8080 --cacert ~/.mitmproxy/mitmproxy-ca-cert.pem " + command 90 else: 91 command = "curl " + command 92 return machine.succeed(command) 93 94 start_all() 95 machine.wait_for_unit("default.target") 96 97 # https://docs.mitmproxy.org/stable/concepts/certificates/#using-a-custom-certificate-authority 98 machine.succeed("mkdir -p ~/.mitmproxy") 99 machine.succeed("ln -s ${caCert} ~/.mitmproxy/mitmproxy-ca.pem") 100 101 machine.succeed("counter >/dev/null &") 102 machine.wait_for_open_port(8000) 103 104 # rewrite 105 # https://docs.mitmproxy.org/stable/mitmproxytutorial-modifyrequests/ 106 107 t.assertEqual("fail", curl("http://localhost:8000/old")) 108 109 machine.send_chars("mitmdump -s ${addonScript}\n") 110 machine.wait_for_open_port(8080) 111 112 t.assertEqual("success", curl("http://localhost:8000/old", proxy=True)) 113 114 machine.send_key("ctrl-c") 115 116 # replay 117 # https://docs.mitmproxy.org/stable/mitmproxytutorial-replayrequests/ 118 # https://docs.mitmproxy.org/stable/tutorials/client-replay/ 119 120 t.assertEqual("0", curl("http://localhost:8000/counter")) 121 122 machine.send_chars("mitmdump -w replay\n") 123 machine.wait_for_open_port(8080) 124 125 curl("-X POST http://localhost:8000/counter", proxy=True) 126 127 machine.send_key("ctrl-c") 128 129 t.assertEqual("1", curl("http://localhost:8000/counter")) 130 131 machine.succeed("mitmdump -C /root/replay") 132 133 t.assertEqual("2", curl("http://localhost:8000/counter")) 134 135 # create a OpenAPI 3.0 spec from captured flow 136 # https://github.com/alufers/mitmproxy2swagger 137 138 # create a initial spec 139 machine.succeed("mitmproxy2swagger -i /root/replay -f flow -o /root/spec -p http://localhost:8000") 140 # don't ignore any endpoint 141 machine.succeed("sed -i -e 's/- ignore:/- /' /root/spec") 142 # generate the actual spec 143 machine.succeed("mitmproxy2swagger -i /root/replay -f flow -o /root/spec -p http://localhost:8000") 144 # check for endpoint /counter 145 machine.succeed("grep '/counter:' /root/spec") 146 ''; 147}