├── .envrc
├── .gitignore
├── LICENSE
├── README.md
├── example
├── devshell.nix
├── evil_build.sh
├── example.nix
└── proxy_content.nix
├── flake.lock
├── flake.nix
├── nix-buildproxy
├── build-content.nix
├── build_cache.py
├── buildproxy-capture.nix
├── buildproxy-shell.nix
├── buildproxy.nix
├── confdir
│ ├── mitmproxy-ca-cert.cer
│ ├── mitmproxy-ca-cert.p12
│ ├── mitmproxy-ca-cert.pem
│ ├── mitmproxy-ca.p12
│ ├── mitmproxy-ca.pem
│ └── mitmproxy-dhparam.pem
├── deliver.py
└── devshell.nix
└── proxy_content.nix
/.envrc:
--------------------------------------------------------------------------------
1 | use flake
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .direnv
2 | __pycache__
3 | result
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Jan Dohl
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nix Buildproxy
2 |
3 | Providing reproducible HTTP/HTTPS responders to builds that just can not live without.
4 |
5 | ## Motivation
6 |
7 | When building Nix packages in the sandbox, internet access is usually not available. However, some packages insist on loading content from the internet. The motivation to build this tool came from a CMake build that loaded additional cmake-files that, in turn, would trigger further package downloads.
8 |
9 | Unwilling to go through multi-level patching during the build, I wondered if it's possible to capture, nixify, and later serve HTTP/HTTPS requests from the Nix store to create an escape hatch when the proper solution is just too much effort. Turns out, this is possible, with some caveats.
10 |
11 | ## Usage
12 |
13 | A quick example on how this package works with the included `example/evil_build.sh` example.
14 |
15 | ### Overlay
16 |
17 | The flake provides an overlay that will make the `buildproxy-capture` package available as well as extend `lib` to contain `lib.mkBuildproxy`. It is recommended to use this overlay. For example, when importing `nixpkgs` in a flake, the overlay is applied as follows:
18 |
19 | ```nix
20 | {
21 | inputs = {
22 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
23 | nix-buildproxy.url = "github:polygon/nix-buildproxy";
24 | };
25 |
26 | outputs = inputs@{ self, nixpkgs, nix-buildproxy, ... }:
27 | let
28 | system = "x64_64-linux";
29 | pkgs = import nixpkgs {
30 | inherit system;
31 | overlays = [ nix-buildproxy.overlays.default ];
32 | };
33 | in
34 | {
35 | ...
36 | }
37 | }
38 | ```
39 |
40 | ### Capturing requests
41 |
42 | Before starting to bring in `nix-buildproxy`, you should be able to build your project (e.g. in a devShell) and downloads during the build are preventing a proper sandboxed nix build. Run `buildproxy-capture` by either adding the `buildproxy-capture` program to your environment or directly through `nix run github:polygon/nix-buildproxy#buildproxy-capture`. This will launch `mitmproxy` and a subshell that has `HTTPS_PROXY` and `HTTP_PROXY` set. This is fine for CMake, since it respects these variables and does not check certificates. Other build systems might require more convincing.
43 |
44 | Then, run your build and exit the subshell when done. This will generate a `proxy_content.nix` file with all the requests.
45 |
46 |
47 | Here is how the session might look like:
48 |
49 | ```bash
50 | nixbrett ➜ nix/nix-buildproxy/example (main ✗) buildproxy-capture
51 | Entering proxy capture shell, run your build now, exit shell when done
52 | nixbrett ➜ nix/nix-buildproxy/example (main ✗) ./evil_build.sh
53 | % Total % Received % Xferd Average Speed Time Time Time Current
54 | Dload Upload Total Spent Left Speed
55 | 100 1237 100 1237 0 0 2811 0 --:--:-- --:--:-- --:--:-- 2817
56 | % Total % Received % Xferd Average Speed Time Time Time Current
57 | Dload Upload Total Spent Left Speed
58 | 100 165 100 165 0 0 553 0 --:--:-- --:--:-- --:--:-- 551
59 | nixbrett ➜ nix/nix-buildproxy/example (main ✗)
60 | Saving captured requests to proxy_content.nix
61 | nixbrett ➜ nix/nix-buildproxy/example (main ✗) cat proxy_content.nix
62 | { fetchurl }: [
63 | {
64 | url = "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/package.nix";
65 | file = fetchurl {
66 | url = "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/package.nix";
67 | hash = "sha256-dFkeANLBJW1FWfL0d8ciS4siWP7B4z0vGsj9revgWGw=";
68 | };
69 | }
70 | {
71 | url = "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/test.nix";
72 | file = fetchurl {
73 | url = "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/test.nix";
74 | hash = "sha256-fg+tJQ4+U2G/9lqvOnakIJ2VBgKJoteewT2LHUV6sP4=";
75 | };
76 | }
77 | ]
78 | ```
79 |
80 |
81 | ### Replaying responses
82 | In order to reply to responses, you need to create a buildproxy recipe that serves your `proxy_content.nix`. You can use `lib.mkBuildproxy ` for this. To enable the buildproxy in your build, run `source ${buildproxy}` early in your build (before any downloads are attempted, `prePatch` is a good candidate). This will start `mitmproxy` in replay mode and set the `HTTP_PROXY` and `HTTPS_PROXY` variables. A basic scaffold:
83 |
84 | ```nix
85 | { stdenv, lib, ... }:
86 | let
87 | buildproxy = lib.mkBuildproxy ./proxy_content.nix;
88 | in
89 | stdenv.mkDerivation {
90 | # ...
91 | prePatch = ''
92 | source ${buildproxy}
93 | '';
94 | # ...
95 | }
96 | ```
97 |
98 | ## How it works
99 |
100 | `nix-buildproxy` uses [mitmproxy](https://mitmproxy.org/) under the hood to do the heavy lifting of providing local proxy functionality. Python addons are used to intercept requests and will either create the proxy content library or serve it. Building the proxy content library works as follows:
101 |
102 | ```mermaid
103 | sequenceDiagram
104 | participant client
105 | participant mitmproxy
106 | participant upstream
107 | participant inventory
108 | client->>mitmproxy: Request
109 | mitmproxy->>upstream: Upstream Request
110 | upstream->>mitmproxy: Response
111 | mitmproxy->>inventory: Store URL / Hash
112 | mitmproxy->>client: Response
113 | ```
114 |
115 | During replay, operation looks like this:
116 |
117 | ```mermaid
118 | sequenceDiagram
119 | participant client
120 | participant mitmproxy
121 | participant inventory
122 | client->>mitmproxy: Request
123 | mitmproxy->>inventory: Lookup
124 | inventory->>mitmproxy: Nix Store Path
125 | mitmproxy->>client: Response
126 | ```
127 |
128 | ## Compatibility / Challenges
129 |
130 | This package was originally built for and works out of the box with CMake. CMake respects the `HTTP_PROXY/HTTPS_PROXY` environment variables and by default ignores certificate errors. If you are using a different tool, you need to figure out how to configure the proxy server and how to tell the tool to accept the self-signed certificate of `mitmproxy`.
131 |
132 | `mitmproxy` will load responses full into memory, I have not yet found out if streaming from/to disk is possible. If this is being used to serve large files, expect RAM usage of at least the file size, possibly several times that.
133 |
134 | HTTP redirects are currently not properly handled. The resulting `proxy_content.nix` will contain the original request with a hash for an empty response and the redirected request with the actual hash separately. You can fix this issue by copying the final `sha256` to the entry that redirects to it. This will be properly addressed in a future update.
135 |
136 | You can modify `proxy_content.nix` to deliver different files. To make builds more stable, it is recommended to replace requests to, e.g., the moving `main` branch of a project to a concrete commit hash. Otherwise, future builds might experience checksum failures. This can also be used as an effective patching mechanism but there is currently no support built in.
137 |
138 | ## Open issues / Roadmap
139 |
140 | * [ ] Properly handle HTTP redirects: Undecided whether to replay the redirect or whether to deliver the resulting file immediately, the latter breaking in case the client modifies the request
141 | * [ ] Properly handle non-success HTTP status codes in general
142 | * [ ] Framework for patching of downloaded files
143 |
--------------------------------------------------------------------------------
/example/devshell.nix:
--------------------------------------------------------------------------------
1 | { mkShell, buildproxy-capture, curl }:
2 | mkShell {
3 | buildInputs = [
4 | curl
5 | buildproxy-capture
6 | ];
7 | }
--------------------------------------------------------------------------------
/example/evil_build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Simulate some stuff insisting on downloads
4 | curl https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/package.nix > package.txt
5 | curl https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/test.nix > test.txt
--------------------------------------------------------------------------------
/example/example.nix:
--------------------------------------------------------------------------------
1 | { stdenv, curl, buildproxy }:
2 | stdenv.mkDerivation (final: {
3 | name = "example";
4 | src = ./.;
5 |
6 | nativeBuildInputs = [ buildproxy curl ];
7 |
8 | preConfigure = ''
9 | source ${buildproxy}
10 | '';
11 |
12 | postBuild = ''
13 | mkdir -p $out
14 | cd $out
15 | bash ${final.src}/evil_build.sh
16 | '';
17 | })
--------------------------------------------------------------------------------
/example/proxy_content.nix:
--------------------------------------------------------------------------------
1 | { fetchurl }: [
2 | {
3 | url =
4 | "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/package.nix";
5 | file = fetchurl {
6 | url =
7 | "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/package.nix";
8 | hash = "sha256-dFkeANLBJW1FWfL0d8ciS4siWP7B4z0vGsj9revgWGw=";
9 | };
10 | status_code = 200;
11 | headers = {
12 | "content-type" = "text/plain; charset=utf-8";
13 | "content-length" = "1237";
14 | };
15 | }
16 | {
17 | url =
18 | "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/test.nix";
19 | file = fetchurl {
20 | url =
21 | "https://raw.githubusercontent.com/NixOS/nixpkgs/ba563a6ec1cd6b3b82ecb7787f9ea2cb4b536a1e/pkgs/by-name/he/hello/test.nix";
22 | hash = "sha256-fg+tJQ4+U2G/9lqvOnakIJ2VBgKJoteewT2LHUV6sP4=";
23 | };
24 | status_code = 200;
25 | headers = {
26 | "content-type" = "text/plain; charset=utf-8";
27 | "content-length" = "165";
28 | };
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "nixpkgs": {
4 | "locked": {
5 | "lastModified": 1708118438,
6 | "narHash": "sha256-kk9/0nuVgA220FcqH/D2xaN6uGyHp/zoxPNUmPCMmEE=",
7 | "owner": "NixOS",
8 | "repo": "nixpkgs",
9 | "rev": "5863c27340ba4de8f83e7e3c023b9599c3cb3c80",
10 | "type": "github"
11 | },
12 | "original": {
13 | "owner": "NixOS",
14 | "ref": "nixos-unstable",
15 | "repo": "nixpkgs",
16 | "type": "github"
17 | }
18 | },
19 | "root": {
20 | "inputs": {
21 | "nixpkgs": "nixpkgs"
22 | }
23 | }
24 | },
25 | "root": "root",
26 | "version": 7
27 | }
28 |
--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | description = "Nix Buildproxy";
3 |
4 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
5 |
6 | outputs = { self, nixpkgs }:
7 | let
8 | system = "x86_64-linux";
9 | pkgs = import nixpkgs {
10 | inherit system;
11 | overlays = [
12 | (prev: final: {
13 | mitmproxy = final.mitmproxy.overrideAttrs (oldAttrs: {
14 | propagatedBuildInputs = oldAttrs.propagatedBuildInputs ++ [
15 | final.python3Packages.httpx
16 | ];
17 | });
18 | })
19 | ];
20 | };
21 | mkContent = proxy-content-file: pkgs.callPackage ./nix-buildproxy/build-content.nix { proxy_content = (import proxy-content-file); };
22 | mkBuildproxy = self.lib.${system}.mkBuildproxy;
23 | mkBuildproxyShell = self.lib.${system}.mkBuildproxyShell;
24 | in
25 | {
26 | lib.${system} = {
27 | mkBuildproxy = proxy-content-file: (pkgs.callPackage ./nix-buildproxy/buildproxy.nix { inherit self; content = mkContent proxy-content-file; });
28 | mkBuildproxyShell = proxy-content-file: (pkgs.callPackage ./nix-buildproxy/buildproxy-shell.nix { inherit self; content = mkContent proxy-content-file; });
29 | };
30 | packages.${system} = {
31 | example = pkgs.callPackage ./example/example.nix { buildproxy = mkBuildproxy ./example/proxy_content.nix; };
32 | buildproxy-capture = pkgs.callPackage ./nix-buildproxy/buildproxy-capture.nix { inherit self; };
33 | };
34 |
35 | devShells.${system} = {
36 | example = pkgs.callPackage ./example/devshell.nix { buildproxy-capture = self.packages.${system}.buildproxy-capture; };
37 | nix-buildproxy = pkgs.callPackage ./nix-buildproxy/devshell.nix {
38 | inherit (self.packages.${system}) buildproxy-capture;
39 | buildproxy-shell = mkBuildproxyShell ./proxy_content.nix;
40 | };
41 | default = self.devShells.${system}.nix-buildproxy;
42 | };
43 |
44 | overlays.default = (final: prev: {
45 | buildproxy-capture = self.packages.${system}.buildproxy-capture;
46 | lib = prev.lib // {
47 | inherit mkBuildproxy;
48 | inherit mkBuildproxyShell;
49 | };
50 | });
51 | };
52 | }
53 |
--------------------------------------------------------------------------------
/nix-buildproxy/build-content.nix:
--------------------------------------------------------------------------------
1 |
2 | { fetchurl, writeTextFile, proxy_content ? [] }:
3 | let
4 | content = builtins.map (
5 | file:
6 | {
7 | inherit (file) url status_code headers;
8 | file = if (builtins.isNull) file.file then null else "${file.file}";
9 | }
10 | ) (proxy_content { inherit fetchurl; });
11 | in
12 | writeTextFile {
13 | name = "proxy_content.json";
14 | text = builtins.toJSON content;
15 | }
16 |
--------------------------------------------------------------------------------
/nix-buildproxy/build_cache.py:
--------------------------------------------------------------------------------
1 | import subprocess
2 | from io import StringIO
3 | import json
4 | import httpx
5 |
6 | from mitmproxy import http
7 |
8 |
9 | class BuildCache:
10 | CACHED_RESPONSES = [ 200, 301, 302, 307, 308 ]
11 | REDIRECT_RESPONSES = [ 301, 302, 307, 308 ]
12 | CACHED_HEADERS = [
13 | "content-type",
14 | "location",
15 | "content-length",
16 | "content-disposition"
17 | ]
18 |
19 | def __init__(self) -> None:
20 | self.cache = []
21 | pass
22 |
23 | async def response(self, flow: http.HTTPFlow) -> None:
24 | print(f"Request received - URL: {flow.request.url}, Code: {flow.response.status_code}")
25 | if flow.response.status_code in self.REDIRECT_RESPONSES:
26 | # Resolve redirects instead of storing them, currently seems like a good idea
27 | print("Redirect found, resolving")
28 | async with httpx.AsyncClient() as client:
29 | resp = await client.get(flow.request.url, follow_redirects = True)
30 | flow.response.status_code = resp.status_code
31 | flow.response.headers = http.Headers([(h[0].encode('utf-8'), h[1].encode('utf-8')) for h in resp.headers.items() if h[0] in self.CACHED_HEADERS])
32 | flow.response.content = resp.content
33 | if flow.response.status_code in self.CACHED_RESPONSES:
34 | print(f"Storing request")
35 | if flow.response.content is not None and len(flow.response.content) > 0:
36 | result = subprocess.run(["nix", "--extra-experimental-features", "nix-command", "hash", "file", "/dev/stdin"], capture_output=True, input=flow.response.content)
37 | nix_hash = result.stdout.decode('utf-8').strip()
38 | else:
39 | nix_hash = None
40 | print(f"Hash: {nix_hash}")
41 | stored_headers = [h for h in flow.response.headers.items() if h[0] in self.CACHED_HEADERS]
42 | self.cache.append({"url": flow.request.url, "hash": nix_hash, "headers": stored_headers, "status": flow.response.status_code})
43 |
44 | def done(self):
45 | f = StringIO()
46 | f.write("{ fetchurl }:")
47 | f.write("[")
48 | for file in self.cache:
49 | f.write("{")
50 | f.write(f'url = "{file["url"]}";')
51 | if file['hash'] is not None:
52 | f.write(f'file = fetchurl {{ url = "{file["url"]}"; hash = "{file["hash"]}"; }};')
53 | else:
54 | f.write(f'file = null;')
55 | f.write(f'status_code = {file["status"]};')
56 | f.write('headers = {')
57 | for header in file['headers']:
58 | f.write(f'"{header[0]}" = "{header[1]}";')
59 | f.write("};}")
60 | f.write("]")
61 | with open('proxy_content.nix', 'w') as out:
62 | subprocess.run(["nixfmt"], input=f.getvalue().encode("utf-8"), stdout=out)
63 |
64 |
65 | addons = [BuildCache()]
66 |
--------------------------------------------------------------------------------
/nix-buildproxy/buildproxy-capture.nix:
--------------------------------------------------------------------------------
1 | { self, writeShellScriptBin, mitmproxy, nix, nixfmt }:
2 | writeShellScriptBin "buildproxy-capture"
3 | ''
4 | PATH=${nix}/bin:${nixfmt}/bin:$PATH ${mitmproxy}/bin/mitmdump --set confdir=${self}/nix-buildproxy/confdir -s ${self}/nix-buildproxy/build_cache.py &
5 | MITM_PID=$!
6 | echo "Entering proxy capture shell, run your build now, exit shell when done"
7 | HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 SSL_CERT_FILE=${self}/nix-buildproxy/confdir/mitmproxy-ca-cert.pem $SHELL
8 | echo "Saving captured requests to proxy_content.nix"
9 | kill $MITM_PID
10 | ''
--------------------------------------------------------------------------------
/nix-buildproxy/buildproxy-shell.nix:
--------------------------------------------------------------------------------
1 | { self, fetchurl, writeShellScriptBin, mitmproxy, netcat, content }:
2 | writeShellScriptBin "buildproxy-shell"
3 | ''
4 | export NIX_BUILDPROXY_CONTENT=${content}
5 | ${mitmproxy}/bin/mitmdump --set confdir=${self}/nix-buildproxy/confdir --set connection_strategy=lazy -s ${self}/nix-buildproxy/deliver.py &
6 | MITM_PID=$!
7 | echo "Entering proxy replay shell, exit when done"
8 | HTTP_PROXY=http://localhost:8080 HTTPS_PROXY=http://localhost:8080 SSL_CERT_FILE=${self}/nix-buildproxy/confdir/mitmproxy-ca-cert.pem $SHELL
9 | echo "Proxy shell exit, killing mitmproxy"
10 | kill $MITM_PID
11 | ''
--------------------------------------------------------------------------------
/nix-buildproxy/buildproxy.nix:
--------------------------------------------------------------------------------
1 | { self, fetchurl, writeShellScript, mitmproxy, netcat, content }:
2 | writeShellScript "buildproxy"
3 | ''
4 | export NIX_BUILDPROXY_CONTENT=${content}
5 | ${mitmproxy}/bin/mitmdump --set confdir=${self}/nix-buildproxy/confdir --set connection_strategy=lazy -s ${self}/nix-buildproxy/deliver.py > /dev/null &
6 | export HTTP_PROXY=http://localhost:8080
7 | export HTTPS_PROXY=http://localhost:8080
8 | export SSL_CERT_FILE=${self}/nix-buildproxy/confdir/mitmproxy-ca-cert.pem
9 | while ! ${netcat}/bin/nc -z localhost 8080; do
10 | sleep 0.1 # Wait a bit
11 | done
12 | ''
--------------------------------------------------------------------------------
/nix-buildproxy/confdir/mitmproxy-ca-cert.cer:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDNTCCAh2gAwIBAgIUVNO+PDa0MTjeJ8M4JtanKLeD8lwwDQYJKoZIhvcNAQEL
3 | BQAwKDESMBAGA1UEAwwJbWl0bXByb3h5MRIwEAYDVQQKDAltaXRtcHJveHkwHhcN
4 | MjQwMjE2MjAyMzMzWhcNMzQwMjE1MjAyMzMzWjAoMRIwEAYDVQQDDAltaXRtcHJv
5 | eHkxEjAQBgNVBAoMCW1pdG1wcm94eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
6 | AQoCggEBANThfMXHZeehrShskZnespcw95CwGkqvBzgS6JOrhbN+OlRApB7CVDR/
7 | B5yahqLQo5JdAhd7tuYDycOMSSn5knu6k84jJkS6MvNGT7Vx7lRqe9gBNfYTgP/g
8 | yV5urVIUNBBKL8fOMJqzHmEcyCXn1N8fhreDZhJ83aiEan0tEeri8BWl22Qal+Tb
9 | ay74GQ9X0OEJzJPj28s0DJYY2QUMuBw9X3GD6m+bW8c0IhLkEDCC/lOR7nVbmRPb
10 | A9XwkM62YPYHkP427CZmcLCMwNzwSnuz0SPbNjxEtpss9f+4ppQG1+ZQFONRbc1A
11 | Rhdspy+R7fxI6tgeUpUqSr5gHoGL+FcCAwEAAaNXMFUwDwYDVR0TAQH/BAUwAwEB
12 | /zATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
13 | FL9ObedzkE5oshAIbvnClqCSKPLIMA0GCSqGSIb3DQEBCwUAA4IBAQBo4lcoP/gW
14 | Ou5vHbH7Y1fW6nrFeYpTkyx2sRBMiBIT4+cLuWoZs+/Qio5XiesT/rf74QDwlZ2j
15 | nK/C0Mbs8ZalJZ/7g9ik25zmHfKPU4awtEe41JRi+d9kq3hKRIv560RMFwc0/tHE
16 | +NZ2MWZmti5PHJL7YclSFSba5x88WwBZ2+XchjJfG1j1VMHatnliVuTq6BYLI5sZ
17 | pWaCNYRD6m5PYMiYp9pv4OnACvUGajAREAgJk3MOew6scL7W7RfBpyiLFY6HWQBR
18 | f+BgR7Ra0Y+GeBW2eSxRQ50/iNtionWQCq20ttB4xsmdTsUUdzfyWUozEHa3wyWY
19 | Cad0Ko7g9Vn4
20 | -----END CERTIFICATE-----
21 |
--------------------------------------------------------------------------------
/nix-buildproxy/confdir/mitmproxy-ca-cert.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/polygon/nix-buildproxy/c26d73992ddae96812501b5ae1cc45037d8b10be/nix-buildproxy/confdir/mitmproxy-ca-cert.p12
--------------------------------------------------------------------------------
/nix-buildproxy/confdir/mitmproxy-ca-cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDNTCCAh2gAwIBAgIUVNO+PDa0MTjeJ8M4JtanKLeD8lwwDQYJKoZIhvcNAQEL
3 | BQAwKDESMBAGA1UEAwwJbWl0bXByb3h5MRIwEAYDVQQKDAltaXRtcHJveHkwHhcN
4 | MjQwMjE2MjAyMzMzWhcNMzQwMjE1MjAyMzMzWjAoMRIwEAYDVQQDDAltaXRtcHJv
5 | eHkxEjAQBgNVBAoMCW1pdG1wcm94eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
6 | AQoCggEBANThfMXHZeehrShskZnespcw95CwGkqvBzgS6JOrhbN+OlRApB7CVDR/
7 | B5yahqLQo5JdAhd7tuYDycOMSSn5knu6k84jJkS6MvNGT7Vx7lRqe9gBNfYTgP/g
8 | yV5urVIUNBBKL8fOMJqzHmEcyCXn1N8fhreDZhJ83aiEan0tEeri8BWl22Qal+Tb
9 | ay74GQ9X0OEJzJPj28s0DJYY2QUMuBw9X3GD6m+bW8c0IhLkEDCC/lOR7nVbmRPb
10 | A9XwkM62YPYHkP427CZmcLCMwNzwSnuz0SPbNjxEtpss9f+4ppQG1+ZQFONRbc1A
11 | Rhdspy+R7fxI6tgeUpUqSr5gHoGL+FcCAwEAAaNXMFUwDwYDVR0TAQH/BAUwAwEB
12 | /zATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
13 | FL9ObedzkE5oshAIbvnClqCSKPLIMA0GCSqGSIb3DQEBCwUAA4IBAQBo4lcoP/gW
14 | Ou5vHbH7Y1fW6nrFeYpTkyx2sRBMiBIT4+cLuWoZs+/Qio5XiesT/rf74QDwlZ2j
15 | nK/C0Mbs8ZalJZ/7g9ik25zmHfKPU4awtEe41JRi+d9kq3hKRIv560RMFwc0/tHE
16 | +NZ2MWZmti5PHJL7YclSFSba5x88WwBZ2+XchjJfG1j1VMHatnliVuTq6BYLI5sZ
17 | pWaCNYRD6m5PYMiYp9pv4OnACvUGajAREAgJk3MOew6scL7W7RfBpyiLFY6HWQBR
18 | f+BgR7Ra0Y+GeBW2eSxRQ50/iNtionWQCq20ttB4xsmdTsUUdzfyWUozEHa3wyWY
19 | Cad0Ko7g9Vn4
20 | -----END CERTIFICATE-----
21 |
--------------------------------------------------------------------------------
/nix-buildproxy/confdir/mitmproxy-ca.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/polygon/nix-buildproxy/c26d73992ddae96812501b5ae1cc45037d8b10be/nix-buildproxy/confdir/mitmproxy-ca.p12
--------------------------------------------------------------------------------
/nix-buildproxy/confdir/mitmproxy-ca.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpAIBAAKCAQEA1OF8xcdl56GtKGyRmd6ylzD3kLAaSq8HOBLok6uFs346VECk
3 | HsJUNH8HnJqGotCjkl0CF3u25gPJw4xJKfmSe7qTziMmRLoy80ZPtXHuVGp72AE1
4 | 9hOA/+DJXm6tUhQ0EEovx84wmrMeYRzIJefU3x+Gt4NmEnzdqIRqfS0R6uLwFaXb
5 | ZBqX5NtrLvgZD1fQ4QnMk+PbyzQMlhjZBQy4HD1fcYPqb5tbxzQiEuQQMIL+U5Hu
6 | dVuZE9sD1fCQzrZg9geQ/jbsJmZwsIzA3PBKe7PRI9s2PES2myz1/7imlAbX5lAU
7 | 41FtzUBGF2ynL5Ht/Ejq2B5SlSpKvmAegYv4VwIDAQABAoIBAAD9wyLOoLhZOzZZ
8 | ebzBhIu0rtUYeimH3XI9kEyuZfMl2X1ZRwpc9Z8Vn6zzK+un1Lh9QLcS8eaUn5oO
9 | q1aL3XVAXf4okWiM2hOM68PDXIyTFFw3S+TcnA3/oiBo8TCqfGrpADD00lVzaRGj
10 | Byw6A0vorda+lg6W+0HqH+7Q82joacVl8/4A1Evn7PB+XPoTSiXFk5f+Xb3XUUyv
11 | 5afvl23UCiNms+WYnnsPxAR0oJLjfXLlwaY8aC7XeBjTVle0oZKnccAG92LGS+XN
12 | gDeZRUOHjArDrJUGlkg9K9w6Uak/Ea3saxEEFCQ9U6M5ZfQ3A1TF9ObBujRuW/NO
13 | sy5kkekCgYEA9nVDRRhsLn7BCdyKCgwaUXCRbKM3rEN6oACEPfBctLwmQnPX6HI1
14 | 8viGL1uPUbMeEBZ3k4hDJsuBd3PeKj5J4o6Aewym14wfoUoMll5Z4FGXn0Uua5Vg
15 | xC+nc5teDQSP6WY0zDyHpTSbdFkLr2aeBq3p/zPDtaymZMtMBrYeljkCgYEA3R9t
16 | laIYsuI2MW76UTJGHn8aQLPjE0DtvI3dlKZOZXPUlvVqmrIppOpvhlByOGUDVjcO
17 | /a0nMeY2Xdt8YO+FAd7GXLaowr+71H2D7JzwAt6hGSQfAkUoei+UhqvJ2GwJzIgi
18 | SG1Xs+qaBFBQmZhTN+DvM7866EZqsPW/p5Xygw8CgYEA6Cr08N0d4/riDFEl9GsM
19 | S9W4GNf0tSFoHdv+t357RoLLo+QO61jTu4wkk+4zp6oNUuhnQqKlZ6Fj18xd5/t/
20 | jJ3jKId1kC3fCgiArRI6plcWdyIrpYs1efrOSth8k9TNYPg4GoGW4qkZHFRZ7qTD
21 | jtU8Tn1MCxOWN/NPLi9XxvkCgYBDRyCsellRdApRGBcJRWaYOMvgC9t3LDYpPHDC
22 | nacUrx1roNgCoVqSVtH/59IY3oMZZD8nZ9uZDxZTkEhTpgyt+P4Zj2nhdzzK9jWB
23 | dG6CMQKLB7Z3llsucfOa1gHf219P38uuhbY9g4/A6D7dvL71LXcaI4Dk0yf7F4ps
24 | ju7ueQKBgQDXIOC0MqQOUQrkHz5OoNMpre1XZ8GH6VCodXH332jDruFZFaeA4456
25 | 6aqZeDfAjps8XKhf3VBNKa1WrNGpkyLpfJsN0I8Si3WQK0remLZvecK12ku17fGx
26 | u8KPI3dll00KuqLO+miG1xfxXRDYm+iPWTqmg4KwaoKwRaJ537lqOg==
27 | -----END RSA PRIVATE KEY-----
28 | -----BEGIN CERTIFICATE-----
29 | MIIDNTCCAh2gAwIBAgIUVNO+PDa0MTjeJ8M4JtanKLeD8lwwDQYJKoZIhvcNAQEL
30 | BQAwKDESMBAGA1UEAwwJbWl0bXByb3h5MRIwEAYDVQQKDAltaXRtcHJveHkwHhcN
31 | MjQwMjE2MjAyMzMzWhcNMzQwMjE1MjAyMzMzWjAoMRIwEAYDVQQDDAltaXRtcHJv
32 | eHkxEjAQBgNVBAoMCW1pdG1wcm94eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
33 | AQoCggEBANThfMXHZeehrShskZnespcw95CwGkqvBzgS6JOrhbN+OlRApB7CVDR/
34 | B5yahqLQo5JdAhd7tuYDycOMSSn5knu6k84jJkS6MvNGT7Vx7lRqe9gBNfYTgP/g
35 | yV5urVIUNBBKL8fOMJqzHmEcyCXn1N8fhreDZhJ83aiEan0tEeri8BWl22Qal+Tb
36 | ay74GQ9X0OEJzJPj28s0DJYY2QUMuBw9X3GD6m+bW8c0IhLkEDCC/lOR7nVbmRPb
37 | A9XwkM62YPYHkP427CZmcLCMwNzwSnuz0SPbNjxEtpss9f+4ppQG1+ZQFONRbc1A
38 | Rhdspy+R7fxI6tgeUpUqSr5gHoGL+FcCAwEAAaNXMFUwDwYDVR0TAQH/BAUwAwEB
39 | /zATBgNVHSUEDDAKBggrBgEFBQcDATAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
40 | FL9ObedzkE5oshAIbvnClqCSKPLIMA0GCSqGSIb3DQEBCwUAA4IBAQBo4lcoP/gW
41 | Ou5vHbH7Y1fW6nrFeYpTkyx2sRBMiBIT4+cLuWoZs+/Qio5XiesT/rf74QDwlZ2j
42 | nK/C0Mbs8ZalJZ/7g9ik25zmHfKPU4awtEe41JRi+d9kq3hKRIv560RMFwc0/tHE
43 | +NZ2MWZmti5PHJL7YclSFSba5x88WwBZ2+XchjJfG1j1VMHatnliVuTq6BYLI5sZ
44 | pWaCNYRD6m5PYMiYp9pv4OnACvUGajAREAgJk3MOew6scL7W7RfBpyiLFY6HWQBR
45 | f+BgR7Ra0Y+GeBW2eSxRQ50/iNtionWQCq20ttB4xsmdTsUUdzfyWUozEHa3wyWY
46 | Cad0Ko7g9Vn4
47 | -----END CERTIFICATE-----
48 |
--------------------------------------------------------------------------------
/nix-buildproxy/confdir/mitmproxy-dhparam.pem:
--------------------------------------------------------------------------------
1 |
2 | -----BEGIN DH PARAMETERS-----
3 | MIICCAKCAgEAyT6LzpwVFS3gryIo29J5icvgxCnCebcdSe/NHMkD8dKJf8suFCg3
4 | O2+dguLakSVif/t6dhImxInJk230HmfC8q93hdcg/j8rLGJYDKu3ik6H//BAHKIv
5 | j5O9yjU3rXCfmVJQic2Nne39sg3CreAepEts2TvYHhVv3TEAzEqCtOuTjgDv0ntJ
6 | Gwpj+BJBRQGG9NvprX1YGJ7WOFBP/hWU7d6tgvE6Xa7T/u9QIKpYHMIkcN/l3ZFB
7 | chZEqVlyrcngtSXCROTPcDOQ6Q8QzhaBJS+Z6rcsd7X+haiQqvoFcmaJ08Ks6LQC
8 | ZIL2EtYJw8V8z7C0igVEBIADZBI6OTbuuhDwRw//zU1uq52Oc48CIZlGxTYG/Evq
9 | o9EWAXUYVzWkDSTeBH1r4z/qLPE2cnhtMxbFxuvK53jGB0emy2y1Ei6IhKshJ5qX
10 | IB/aE7SSHyQ3MDHHkCmQJCsOd4Mo26YX61NZ+n501XjqpCBQ2+DfZCBh8Va2wDyv
11 | A2Ryg9SUz8j0AXViRNMJgJrr446yro/FuJZwnQcO3WQnXeqSBnURqKjmqkeFP+d8
12 | 6mk2tqJaY507lRNqtGlLnj7f5RNoBFJDCLBNurVgfvq9TCVWKDIFD4vZRjCrnl6I
13 | rD693XKIHUCWOjMh1if6omGXKHH40QuME2gNa50+YPn1iYDl88uDbbMCAQI=
14 | -----END DH PARAMETERS-----
15 |
--------------------------------------------------------------------------------
/nix-buildproxy/deliver.py:
--------------------------------------------------------------------------------
1 | """Deliver URIs previously requested from local cache"""
2 | import os
3 | import json
4 |
5 | from mitmproxy import http
6 |
7 |
8 | class ProxyResponder:
9 | def __init__(self) -> None:
10 | proxy_content_file = os.environ['NIX_BUILDPROXY_CONTENT']
11 | self.proxy_content = json.load(open(proxy_content_file, 'r'))
12 |
13 | def request(self, flow: http.HTTPFlow) -> None:
14 | print(f"URI requested: {flow.request.url}")
15 | for obj in self.proxy_content:
16 | if obj['url'] == flow.request.url:
17 | print(f"Object found, delivering: {obj['status_code']} : {obj['file']}")
18 | headers = [(k.encode('utf-8'), v.encode('utf-8')) for k, v in obj['headers'].items()]
19 | flow.response = http.Response.make(
20 | status_code = obj['status_code'],
21 | headers = headers,
22 | content = open(obj['file'], 'rb').read() if obj['file'] is not None else b'',
23 | )
24 | break
25 | else:
26 | flow.response = http.Response.make(
27 | 404,
28 | )
29 |
30 | addons = [ProxyResponder()]
31 |
--------------------------------------------------------------------------------
/nix-buildproxy/devshell.nix:
--------------------------------------------------------------------------------
1 | { mkShell, buildproxy-capture, buildproxy-shell, curl, mitmproxy, python3 }:
2 | mkShell {
3 | buildInputs = [
4 | curl
5 | buildproxy-capture
6 | buildproxy-shell
7 | mitmproxy
8 | (python3.withPackages (ps: with ps; [
9 | httpx
10 | ipython
11 | mitmproxy
12 | ]))
13 | ];
14 | }
--------------------------------------------------------------------------------
/proxy_content.nix:
--------------------------------------------------------------------------------
1 | { fetchurl }: [ ]
2 |
--------------------------------------------------------------------------------