Switch to httptoolkit

Summary: switch to httptoolkit

Reviewers: kuba-orlik

Reviewed By: kuba-orlik

Differential Revision: https://hub.sealcode.org/D1578
This commit is contained in:
Andrii Dokhniak 2025-04-06 14:04:21 +02:00
parent ff7e32a3d5
commit 18541a6647
27 changed files with 3444 additions and 194 deletions

3
.gitignore vendored
View File

@ -7,3 +7,6 @@ images
bundleTrafficLog.js bundleTrafficLog.js
/http_server/code/dist/ /http_server/code/dist/
log log
dist
/httptoolkit_server/proxy_thing/dist/
shared_buffer

View File

@ -1,5 +1,30 @@
FROM pre_android/ready FROM pre_android/ready
EXPOSE 3000 # Set up node
RUN npm install -g n && n install 22.14.0 && n use 22.14.0 && hash -r
CMD bash /conf/docker-entrypoint.sh # Set up httptoolkit-server
RUN git clone https://github.com/httptoolkit/httptoolkit-server /httptoolkit-server
WORKDIR /httptoolkit-server
RUN git checkout 5c60a70b08d30126639484314f5b5619a388b026 \
&& npm i && npm run build:src
# Set up proxy_cache_thing
ADD proxy_cache_thing /proxy_cache_thing
WORKDIR /proxy_cache_thing
RUN npm i && npm run build
ADD entrypoint.sh /entrypoint.sh
ARG PROXY_PORT
ARG SERVER_PORT
ARG MONITORING_API_PORT
ARG LOOPBACK_PORT
ENV PROXY_PORT=${PROXY_PORT}
ENV SERVER_PORT=${SERVER_PORT}
ENV MONITORING_API_PORT=${MONITORING_API_PORT}
ENV LOOPBACK_PORT=${LOOPBACK_PORT}
ENTRYPOINT /entrypoint.sh

View File

@ -31,6 +31,8 @@ wss.on("connection", (ws) => {
await spawnPromise("bash", ["/conf/back.sh"]); await spawnPromise("bash", ["/conf/back.sh"]);
} else if (data === "home") { } else if (data === "home") {
await spawnPromise("bash", ["/conf/home.sh"]); await spawnPromise("bash", ["/conf/home.sh"]);
} else if (data === "install") {
await spawnPromise("bash", ["/conf/install.sh"]);
} else if (data.includes("drag")) { } else if (data.includes("drag")) {
const dataSplit = data.split(" "); const dataSplit = data.split(" ");

View File

@ -1,7 +1,5 @@
bash /conf/start_culebra.sh bash /conf/start_culebra.sh
npm i -C /code npm i -C /code
bash /conf/iptables_conf.sh
redsocks -c /conf/redsocks.conf &
bash /conf/wait_for_sd.sh bash /conf/wait_for_sd.sh
node /code/index.mjs node /code/index.mjs

4
android/conf/install.sh Normal file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -e
# -r to replace an existing application if any
/opt/android-sdk-linux/platform-tools/adb install -r /shared_buffer/app.apk

View File

@ -1,42 +0,0 @@
#!/bin/bash
#reserved ip addresses taken from https://en.wikipedia.org/wiki/Reserved_IP_addresses#Reserved_IPv4_addresses
iptables -t nat -N REDSOCKS
iptables -t nat -A REDSOCKS -d 0.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 0.0.0.0/32 -j RETURN
iptables -t nat -A REDSOCKS -d 10.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 100.64.0.0/10 -j RETURN
iptables -t nat -A REDSOCKS -d 127.0.0.0/8 -j RETURN
iptables -t nat -A REDSOCKS -d 169.254.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 172.16.0.0/12 -j RETURN
iptables -t nat -A REDSOCKS -d 192.0.0.0/24 -j RETURN
iptables -t nat -A REDSOCKS -d 192.0.2.0/24 -j RETURN
iptables -t nat -A REDSOCKS -d 192.168.0.0/16 -j RETURN
iptables -t nat -A REDSOCKS -d 198.18.0.0/15 -j RETURN
iptables -t nat -A REDSOCKS -d 198.51.100.0/24 -j RETURN
iptables -t nat -A REDSOCKS -d 203.0.113.0/24 -j RETURN
iptables -t nat -A REDSOCKS -d 224.0.0.0/4 -j RETURN
iptables -t nat -A REDSOCKS -d 233.252.0.0/24 -j RETURN
iptables -t nat -A REDSOCKS -d 240.0.0.0/4 -j RETURN
iptables -t nat -A REDSOCKS -d 255.255.255.255/32 -j RETURN
iptables -t nat -A REDSOCKS -p tcp -j REDIRECT --to-ports 12345
iptables -t nat -A OUTPUT -p tcp -j REDSOCKS
# iptables -t nat -N UDPSOCKS
# iptables -t nat -A UDPSOCKS -d 0.0.0.0/8 -j RETURN
# iptables -t nat -A UDPSOCKS -d 10.0.0.0/8 -j RETURN
# iptables -t nat -A UDPSOCKS -d 100.64.0.0/10 -j RETURN
# iptables -t nat -A UDPSOCKS -d 127.0.0.0/8 -j RETURN
# iptables -t nat -A UDPSOCKS -d 169.254.0.0/16 -j RETURN
# iptables -t nat -A UDPSOCKS -d 172.16.0.0/12 -j RETURN
# iptables -t nat -A UDPSOCKS -d 192.168.0.0/16 -j RETURN
# iptables -t nat -A UDPSOCKS -d 198.18.0.0/15 -j RETURN
# iptables -t nat -A UDPSOCKS -d 224.0.0.0/4 -j RETURN
# iptables -t nat -A UDPSOCKS -d 240.0.0.0/4 -j RETURN
# iptables -t nat -A UDPSOCKS -p udp -j REDIRECT --to-ports 12346
# iptables -t nat -A OUTPUT -p udp -j UDPSOCKS

View File

@ -1,22 +0,0 @@
base {
log_debug = off;
log_info = on;
log = "syslog:daemon";
daemon = off;
redirector = iptables;
}
redsocks {
local_ip = 0.0.0.0;
local_port = 12345;
ip = proxy;
port = 1080;
type = socks5;
}

31
android/entrypoint.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/bash
set -e
node /proxy_cache_thing/dist/index.js &
CACHE_PID=$!
/httptoolkit-server/bin/run start -c /certificates &
HTTPTOOLKIT_SERVER_PID=$!
bash /conf/docker-entrypoint.sh &
ANDROID_PID=$!
function check_dead() {
if ! ps -p $CACHE_PID > /dev/null; then
echo "[ERROR] The proxy cache died, exiting...";
exit 1;
fi
if ! ps -p $HTTPTOOLKIT_SERVER_PID > /dev/null; then
echo "[ERROR] The httptoolkit_server died, exiting...";
exit 1;
fi
if ! ps -p $ANDROID_PID > /dev/null; then
echo "[ERROR] The android emulator died, exiting...";
exit 1;
fi
}
# Exit on error
while true; do
check_dead;
sleep 1;
done

2665
android/proxy_cache_thing/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
{
"name": "proxy_thing",
"version": "1.0.0",
"description": "",
"license": "ISC",
"author": "",
"type": "commonjs",
"main": "./lib/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc",
"start": "tsc && node dist/index.js",
"lint": "tslint -c tslint.json src/**/*.ts",
"prepublish": "npm run build"
},
"dependencies": {
"express": "^4.21.2",
"mockttp": "^3.16.0",
"ts-node": "^10.9.2",
"tslint": "^5.20.1",
"ws": "^8.18.1"
},
"files": [
"./bin/*",
"./lib/*"
],
"typings": "./lib/index.d.ts",
"directories": {
"lib": "lib"
},
"devDependencies": {
"typescript": "^5.8.2"
},
"keywords": []
}

View File

@ -0,0 +1,188 @@
import { getLocal } from "mockttp";
import * as WebSock from "ws";
const mockServer = getLocal();
const wait_for_open = (socket: WebSock) => {
if (socket.readyState === socket.OPEN) return;
return new Promise((resolve, reject) => {
const maxNumberOfAttempts = 20;
const intervalTime = 100; //ms
let currentAttempt = 0;
const interval = setInterval(() => {
if (currentAttempt > maxNumberOfAttempts - 1) {
clearInterval(interval);
reject(new Error("Maximum number of attempts exceeded"));
} else if (socket.readyState === socket.OPEN) {
clearInterval(interval);
resolve(undefined);
} else if (socket.readyState == socket.CLOSED) {
console.log(socket.url);
reject(new Error("The server socket closed"));
}
currentAttempt++;
}, intervalTime);
});
};
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
function waitforhost(
url: string,
expected_status = 200,
interval = 1000,
attempts = 10
): Promise<void> {
let count = 1;
return new Promise(async (resolve, reject) => {
while (count < attempts) {
await sleep(interval);
try {
const response = await fetch(url);
if (response.status === expected_status) {
resolve();
break;
} else {
count++;
}
} catch {
count++;
console.log(`Still down, trying ${count} of ${attempts}`);
}
}
reject(new Error(`Server is down: ${count} attempts tried`));
});
}
(async () => {
const proxy_port = process.env.PROXY_PORT;
const server_port = process.env.SERVER_PORT;
const loopback_port = process.env.LOOPBACK_PORT; // internal only
const monitoring_api_port = process.env.MONITORING_API_PORT;
if (!proxy_port || !server_port || !monitoring_api_port || !loopback_port) {
throw Error("Configuration env variables not set");
}
// Expect 403 forbidden
await waitforhost("http://127.0.0.1:" + server_port, 403);
mockServer.start(+proxy_port);
let cached_resp: undefined | string = undefined;
const cors_headers = {
"access-control-allow-origin": "*",
"access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
"access-control-allow-headers": "Content-Type, Authorization",
"access-control-max-age": "86400",
"access-control-allow-credentials": "true",
Origin: "http://127.0.0.1:8080", // Trick the server into thinking that it is accessed through localhost
};
await mockServer.forOptions().thenReply(200, "", cors_headers);
await mockServer.forPost("/start").thenPassThrough({
beforeRequest: async (req) => {
if (cached_resp) {
return {
response: { body: cached_resp, headers: cors_headers },
};
}
// forward the request to the real server
return {
url: req.url,
headers: req.headers,
body: await req.body.getDecodedBuffer(),
};
},
beforeResponse: async (resp, _req) => {
// cache the response
cached_resp = (await resp.body.getText()) as string;
// set the cors headers, overwriting the prohibitive ones
return { headers: { ...resp.headers, ...cors_headers } };
},
});
await mockServer.forPost("/stop").thenReply(200);
// forward everything to the real server
await mockServer.forUnmatchedRequest().thenPassThrough({
beforeRequest: async (req) => {
return { url: req.url };
},
beforeResponse: async (resp, _req) => {
return { headers: { ...resp.headers, ...cors_headers } };
},
});
await mockServer
.forAnyWebSocket()
.thenForwardTo("ws://127.0.0.1:" + loopback_port);
let wss = new WebSock.Server({ port: +loopback_port });
// this is append only
let httptoolkit_server_messages: String[] = [];
let api_server = new WebSock.Server({ port: +monitoring_api_port });
api_server.on("connection", (ws) => {
let curr_idx_to_send = 0;
const interval = setInterval(() => {
while (httptoolkit_server_messages[curr_idx_to_send] != undefined) {
if (ws.readyState != ws.OPEN) {
clearInterval(interval);
ws.close();
break;
}
ws.send(httptoolkit_server_messages[curr_idx_to_send]);
curr_idx_to_send++;
}
}, 100);
});
wss.on("connection", (ws, req) => {
let server_session_url = "ws://127.0.0.1:" + server_port + req.url;
let httptoolkit_server_session: WebSock;
console.log("ws connection:", ws.protocol, typeof ws.protocol);
if (ws.protocol) {
httptoolkit_server_session = new WebSock(
server_session_url,
ws.protocol,
{ joinDuplicateHeaders: true, headers: req.headers }
);
} else {
httptoolkit_server_session = new WebSock(server_session_url, {
joinDuplicateHeaders: true,
headers: req.headers,
});
}
httptoolkit_server_session.onerror = (_) => {
ws.close();
httptoolkit_server_session.close();
return;
};
httptoolkit_server_session.onopen = () => {
console.log("ws connected to the server");
};
httptoolkit_server_session.onmessage = (msg) => {
httptoolkit_server_messages.push(msg.data.toString());
ws.send(msg.data);
};
// Listening for messages from the client
ws.on("message", async (message) => {
await wait_for_open(httptoolkit_server_session);
httptoolkit_server_session.send(message.toString());
});
// Handling client disconnection
ws.on("close", () => {
httptoolkit_server_session.close();
});
});
console.log("WS Proxy started");
console.log(mockServer.proxyEnv);
})();

View File

@ -0,0 +1,38 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"lib": [
"es2015"
],
"rootDir": "src",
"outDir": "dist",
"strict": true,
"alwaysStrict": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"forceConsistentCasingInFileNames": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"downlevelIteration": true,
"declaration": true,
"pretty": true
},
"include": [
"typings/**/*",
"src/**/*"
]
}

View File

@ -0,0 +1,3 @@
{
"extends": "tslint:latest"
}

9
certgen/Dockerfile Normal file
View File

@ -0,0 +1,9 @@
FROM node:22.14.0
RUN git clone https://github.com/httptoolkit/httptoolkit-server
WORKDIR /httptoolkit-server
RUN git checkout 5c60a70b08d30126639484314f5b5619a388b026 \
&& npm i && npm run build:src
CMD /httptoolkit-server/bin/run start -c /certificates

View File

@ -1,14 +1,13 @@
services: services:
proxy:
build: ./proxy/
container_name: proxy
networks:
- rent_gen_android
volumes:
- $PWD/certificates:/root/.mitmproxy
- $PWD/log:/log
android: android:
build: ./android/ build:
context: ./android/
args:
PROXY_PORT: "45459"
SERVER_PORT: "45456"
LOOPBACK_PORT: "10000"
MONITORING_API_PORT: "10001"
container_name: httptoolkit_server
container_name: android container_name: android
sysctls: sysctls:
- net.ipv6.conf.all.disable_ipv6=1 - net.ipv6.conf.all.disable_ipv6=1
@ -18,9 +17,29 @@ services:
- /dev/kvm - /dev/kvm
networks: networks:
- rent_gen_android - rent_gen_android
ports:
- 45456:45459 # This cannot change
- 45457:45459 # This cannot change
- 10001:10001 # api port
- 3000:3000 # android server port
volumes: volumes:
- $PWD/shared_buffer:/shared_buffer
- $PWD/android/conf:/conf - $PWD/android/conf:/conf
- $PWD/certificates:/certificates
- $PWD/android/code:/code - $PWD/android/code:/code
httptoolkit_ui:
build:
context: ./httptoolkit_ui/
args:
# The ip / hostname using which,
# the browser can reach this docker session
DOCKER_HOST: "127.0.0.1"
container_name: httptoolkit_ui
networks:
- rent_gen_android
ports:
- 9080:9080
http_server: http_server:
build: ./http_server/ build: ./http_server/
container_name: http_server container_name: http_server
@ -28,6 +47,7 @@ services:
- rent_gen_android - rent_gen_android
volumes: volumes:
- $PWD/http_server/code:/code - $PWD/http_server/code:/code
- $PWD/shared_buffer:/shared_buffer
- $PWD/log:/log - $PWD/log:/log
ports: ports:
- 8080:8080 - 8080:8080

View File

@ -3,6 +3,6 @@
npm i npm i
npm run build npm run build
node waitSocket.mjs node waitSocket.mjs
node index.mjs node --watch index.mjs
#tail -f /dev/null #tail -f /dev/null

View File

@ -1,17 +1,18 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head style="height: 100vh">
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<title>Rentgen android</title> <title>Rentgen android</title>
<script src="/htmx.js"></script>
<style> <style>
main { main {
display: flex; display: flex;
} }
.log-section { .log-section {
height: 600px; height: auto;
width: 480px; width: 400px;
overflow-y: auto; overflow: auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
margin-left: 20px; margin-left: 20px;
@ -45,26 +46,155 @@
font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console,
monospace; monospace;
} }
.tab {
border: 1px solid #ccc;
background-color: #f1f1f1;
}
/* Style the buttons that are used to open the tab content */
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
/* Change background color of buttons on hover */
.tab button:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
.tab button.active {
background-color: #ccc;
}
.tabcontent.active {
display: flex;
flex-grow: 1;
}
/* Style the tab content */
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
html,
body, main{
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
}
main {
display:flex;
flex-direction: row;
align-items: stretch;
}
#logs-tab {
overflow: auto;
text-wrap: wrap;
}
.screen-section {
display: flex;
flex-direction: column;
}
.screen-section #screen, .screen-section.screen_buttons {
flex-grow: 0;
}
.tab-section {
display: flex; flex-direction: column; flex-grow: 1;
}
<!-- TODO: A notification system -->
#resp {
display: none;
}
#upload_form {
display:flex;
flex-direction: column;
}
#upload_form button, #upload_form label {
border: 2px solid #ccc;
background-color: #f1f1f1;
cursor: pointer;
padding: 3px 10px;
transition: 0.3s;
}
#upload_form button:hover, #upload_form label:hover {
background-color: #ddd;
}
</style> </style>
</head> </head>
<body> <body>
<div id="resp"></div>
<main> <main>
<section class="screen-section"> <section class="screen-section" >
<img <img
id="screen" id="screen"
alt="android screen" alt="android screen"
src="" src=""
draggable="false" draggable="false"
class="screen" class="screen"
style="flex-grow: 0"
/> />
<div class="screen-buttons"> <div class="screen-buttons" style="flex-grow: 0">
<button class="screen-buttons-home">home</button> <button class="screen-buttons-home">home</button>
<button class="screen-buttons-back">back</button> <button class="screen-buttons-back">back</button>
</div> </div>
<form id="upload_form" hx-post="/upload_apk" enctype="multipart/form-data" hx-target="#resp">
<label id="upload_input" for="app">Select file
<input type="file" id="app" name="app" accept=".apk" required/>
</label>
<button type="submit">Install the app</button>
</form>
</section> </section>
<p id="clicks-log" class="log-section"></p>
<div class="tab-section" >
<div class="tab">
<button class="tablinks active" onclick="open_tab(event, 'httptoolkit-tab')">HttpToolkit UI</button>
<button class="tablinks" onclick="open_tab(event, 'logs-tab')">Logs</button>
</div>
<div class="tabcontent" id="logs-tab">
<p id="clicks-log" class="log-section" ></p>
<p id="traffic-log" class="log-section"></p> <p id="traffic-log" class="log-section"></p>
</div>
<div class="tabcontent active" id="httptoolkit-tab">
<iframe id="httptoolkit-frame" style="flex-grow: 1;" src="http://localhost:9080/" title="httptoolkit"></iframe>
</div>
</div>
</main> </main>
<script>
function open_tab(evt, tab_name) {
let i, tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
if (tabcontent[i].id != tab_name) {
tabcontent[i].classList.remove("active");
} else {
tabcontent[i].classList.add("active");
}
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].classList.remove("active")
}
// Show the current tab, and add an "active" class to the button that opened the tab
evt.currentTarget.classList.add("active");
}
</script>
<script> <script>
var screen = document.getElementById("screen"); var screen = document.getElementById("screen");
var clicksLog = document.getElementById("clicks-log"); var clicksLog = document.getElementById("clicks-log");

View File

@ -6,6 +6,8 @@ import {
waitFullBoot, waitFullBoot,
} from "./screenshot.mjs"; } from "./screenshot.mjs";
import fileUpload from 'express-fileupload';
const device_size_x = 320; const device_size_x = 320;
const device_size_y = 640; const device_size_y = 640;
@ -25,6 +27,10 @@ app.get("/trafficLog.js", function (req, res) {
res.sendFile("/code/dist/trafficLog.js"); res.sendFile("/code/dist/trafficLog.js");
}); });
app.get("/htmx.js", function (req, res) {
res.sendFile("/code/node_modules/htmx.org/dist/htmx.min.js");
});
app.get("/trafficLog", async function (req, res) { app.get("/trafficLog", async function (req, res) {
res.sendFile("/log/trafficLog"); res.sendFile("/log/trafficLog");
}); });
@ -54,6 +60,23 @@ app.post("/back", function (req, res) {
res.sendStatus(200); res.sendStatus(200);
}); });
// default options
app.use(fileUpload());
app.post('/upload_apk',function (req, res) {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
let file = req.files.app;
let uploadPath = '/shared_buffer/app.apk';
file.mv(uploadPath, function(err) {
if (err)
return res.status(500).send(err);
android_websocket.send(`install`);
res.send('File uploaded!');
});
})
app.post("/home", function (req, res) { app.post("/home", function (req, res) {
android_websocket.send(`home`); android_websocket.send(`home`);
res.sendStatus(200); res.sendStatus(200);

View File

@ -6,6 +6,8 @@
"": { "": {
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"express-fileupload": "^1.5.1",
"htmx.org": "^1.9.12",
"preact": "^10.18.1", "preact": "^10.18.1",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
@ -405,6 +407,17 @@
"npm": "1.2.8000 || >= 1.4.16" "npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -586,6 +599,18 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/express-fileupload": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.1.tgz",
"integrity": "sha512-LsYG1ALXEB7vlmjuSw8ABeOctMp8a31aUC5ZF55zuz7O2jLFnmJYrCv10py357ky48aEoBQ/9bVXgFynjvaPmA==",
"license": "MIT",
"dependencies": {
"busboy": "^1.6.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/finalhandler": { "node_modules/finalhandler": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
@ -671,6 +696,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/htmx.org": {
"version": "1.9.12",
"resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-1.9.12.tgz",
"integrity": "sha512-VZAohXyF7xPGS52IM8d1T1283y+X4D+Owf3qY1NZ9RuBypyu9l8cGsxUMAG5fEAb/DhT7rDoJ9Hpu5/HxFD3cw==",
"license": "0BSD"
},
"node_modules/http-errors": { "node_modules/http-errors": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -955,6 +986,14 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/toidentifier": { "node_modules/toidentifier": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",

View File

@ -4,6 +4,8 @@
}, },
"dependencies": { "dependencies": {
"express": "^4.18.2", "express": "^4.18.2",
"express-fileupload": "^1.5.1",
"htmx.org": "^1.9.12",
"preact": "^10.18.1", "preact": "^10.18.1",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },

View File

@ -9,8 +9,17 @@ let screenshotPromise = null;
async function screenshot() { async function screenshot() {
const time_start = Date.now(); const time_start = Date.now();
let retries = 0;
while (android_websocket.readyState != WebSocket.OPEN) { while (android_websocket.readyState != WebSocket.OPEN) {
await sleep(15); await sleep(15);
retries++;
if (retries > 50)
{
console.error("Screenshot ws timeout");
doneWrite = 0;
screenshotPromise = null;
return ;
}
} }
android_websocket.send("screenshot"); android_websocket.send("screenshot");
while (!doneWrite) { while (!doneWrite) {

View File

@ -1,18 +1,21 @@
import { h, render, Component } from "preact"; import { h, render, Component } from "preact";
const refreshRate = 1000;
class TrafficLog extends Component { class TrafficLog extends Component {
constructor() { constructor() {
super(); super();
this.state = { content: "" }; this.state = { content: [] };
} }
componentDidMount() { componentDidMount() {
this.intervalSetter = setInterval(async () => { // This should also be dynamic
var log = await (await fetch("trafficLog")).text(); this.connection = new WebSocket("ws://localhost:10001");
this.setState({ content: log }); this.connection.onmessage = (msg) => {
}, refreshRate); this.setState({ content: [...this.state.content, msg.data] });
};
this.connection.onclose = this.connection.onerror = () => {
var element = document.getElementById("httptoolkit-frame");
element.parentNode.removeChild(element);
}
} }
componentWillUnmount() { componentWillUnmount() {
@ -21,11 +24,10 @@ class TrafficLog extends Component {
render() { render() {
const contentWithLineBreaks = this.state.content const contentWithLineBreaks = this.state.content
.split("\n") .map((text) => {
.map((line, _) => {
return ( return (
<span> <span>
{line} {text.substring(0, 100)}
<br /> <br />
</span> </span>
); );

20
httptoolkit_ui/Dockerfile Normal file
View File

@ -0,0 +1,20 @@
FROM node:20.18.1
# If iproute2 is not installed,
# node can't figure out what address to bind 0.0.0.0 to
RUN apt-get update && apt-get install iproute2 python3 --yes \
&& git clone https://github.com/httptoolkit/httptoolkit-ui
WORKDIR httptoolkit-ui
RUN git checkout a0dbb8e1cd38b346fe411b03de0c5191ff06c669 \
&& npm i && npm run server:setup
ARG DOCKER_HOST=localhost
# This gets sent to the browser as a server URL,
# so it is important that it is set to the domain / ip of the server.
RUN sed -i "s/127.0.0.1/${DOCKER_HOST}/" src/model/proxy-store.ts \
&& npm run build:default # Can take a long time
CMD npm exec static-server ./dist -o

218
package-lock.json generated
View File

@ -12,6 +12,7 @@
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"license": "MIT",
"dependencies": { "dependencies": {
"@nodelib/fs.stat": "2.0.5", "@nodelib/fs.stat": "2.0.5",
"run-parallel": "^1.1.9" "run-parallel": "^1.1.9"
@ -24,6 +25,7 @@
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
} }
@ -32,6 +34,7 @@
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@nodelib/fs.scandir": "2.1.5", "@nodelib/fs.scandir": "2.1.5",
"fastq": "^1.6.0" "fastq": "^1.6.0"
@ -41,57 +44,68 @@
} }
}, },
"node_modules/@types/fs-extra": { "node_modules/@types/fs-extra": {
"version": "11.0.1", "version": "11.0.4",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
"integrity": "sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==", "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@types/jsonfile": "*", "@types/jsonfile": "*",
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/jsonfile": { "node_modules/@types/jsonfile": {
"version": "6.1.1", "version": "6.1.4",
"resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.4.tgz",
"integrity": "sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==", "integrity": "sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/minimist": { "node_modules/@types/minimist": {
"version": "1.2.2", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==" "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==",
"license": "MIT"
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "18.16.7", "version": "18.19.80",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.7.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz",
"integrity": "sha512-MFg7ua/bRtnA1hYE3pVyWxGd/r7aMqjNOdHvlSsXV3n8iaeGKkOaPzpJh6/ovf4bEXWcojkeMJpTsq3mzXW4IQ==" "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
}
}, },
"node_modules/@types/ps-tree": { "node_modules/@types/ps-tree": {
"version": "1.1.2", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/@types/ps-tree/-/ps-tree-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@types/ps-tree/-/ps-tree-1.1.6.tgz",
"integrity": "sha512-ZREFYlpUmPQJ0esjxoG1fMvB2HNaD3z+mjqdSosZvd3RalncI9NEur73P8ZJz4YQdL64CmV1w0RuqoRUlhQRBw==" "integrity": "sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==",
"license": "MIT"
}, },
"node_modules/@types/which": { "node_modules/@types/which": {
"version": "3.0.0", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/which/-/which-3.0.4.tgz",
"integrity": "sha512-ASCxdbsrwNfSMXALlC3Decif9rwDMu+80KGp5zI2RLRotfMsTv7fHL8W8VDp24wymzDyIFudhUeSCugrgRFfHQ==" "integrity": "sha512-liyfuo/106JdlgSchJzXEQCVArk0CvevqPote8F8HgWgJ3dRCcTHgJIsLDuee0kxk/mhbInzIZk3QWSZJ8R+2w==",
"license": "MIT"
}, },
"node_modules/braces": { "node_modules/braces": {
"version": "3.0.2", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"license": "MIT",
"dependencies": { "dependencies": {
"fill-range": "^7.0.1" "fill-range": "^7.1.1"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/chalk": { "node_modules/chalk": {
"version": "5.2.0", "version": "5.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
"integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
"license": "MIT",
"engines": { "engines": {
"node": "^12.17.0 || ^14.13 || >=16.0.0" "node": "^12.17.0 || ^14.13 || >=16.0.0"
}, },
@ -103,6 +117,7 @@
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 12" "node": ">= 12"
} }
@ -111,6 +126,7 @@
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
"license": "MIT",
"dependencies": { "dependencies": {
"path-type": "^4.0.0" "path-type": "^4.0.0"
}, },
@ -121,12 +137,14 @@
"node_modules/duplexer": { "node_modules/duplexer": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"license": "MIT"
}, },
"node_modules/event-stream": { "node_modules/event-stream": {
"version": "3.3.4", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
"integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==",
"license": "MIT",
"dependencies": { "dependencies": {
"duplexer": "~0.1.1", "duplexer": "~0.1.1",
"from": "~0", "from": "~0",
@ -138,24 +156,26 @@
} }
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
"version": "3.2.12", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
"integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
"license": "MIT",
"dependencies": { "dependencies": {
"@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3", "@nodelib/fs.walk": "^1.2.3",
"glob-parent": "^5.1.2", "glob-parent": "^5.1.2",
"merge2": "^1.3.0", "merge2": "^1.3.0",
"micromatch": "^4.0.4" "micromatch": "^4.0.8"
}, },
"engines": { "engines": {
"node": ">=8.6.0" "node": ">=8.6.0"
} }
}, },
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.15.0", "version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
"integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
"license": "ISC",
"dependencies": { "dependencies": {
"reusify": "^1.0.4" "reusify": "^1.0.4"
} }
@ -174,6 +194,7 @@
"url": "https://paypal.me/jimmywarting" "url": "https://paypal.me/jimmywarting"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"node-domexception": "^1.0.0", "node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3" "web-streams-polyfill": "^3.0.3"
@ -183,9 +204,10 @@
} }
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.0.1", "version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"license": "MIT",
"dependencies": { "dependencies": {
"to-regex-range": "^5.0.1" "to-regex-range": "^5.0.1"
}, },
@ -197,6 +219,7 @@
"version": "4.0.10", "version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"license": "MIT",
"dependencies": { "dependencies": {
"fetch-blob": "^3.1.2" "fetch-blob": "^3.1.2"
}, },
@ -207,12 +230,14 @@
"node_modules/from": { "node_modules/from": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
"integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==" "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==",
"license": "MIT"
}, },
"node_modules/fs-extra": { "node_modules/fs-extra": {
"version": "11.1.1", "version": "11.3.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
"integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
"license": "MIT",
"dependencies": { "dependencies": {
"graceful-fs": "^4.2.0", "graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1", "jsonfile": "^6.0.1",
@ -223,9 +248,10 @@
} }
}, },
"node_modules/fx": { "node_modules/fx": {
"version": "28.0.0", "version": "35.0.0",
"resolved": "https://registry.npmjs.org/fx/-/fx-28.0.0.tgz", "resolved": "https://registry.npmjs.org/fx/-/fx-35.0.0.tgz",
"integrity": "sha512-vKQDA9g868cZiW8ulgs2uN1yx1i7/nsS33jTMOxekk0Z03BJLffVcdW6AVD32fWb3E6RtmWWuBXBZOk8cLXFNQ==", "integrity": "sha512-O07q+Lknrom5RUX/u53tjo2KTTLUnL0K703JbqMYb19ORijfJNvijzFqqYXEjdk25T9R14S6t6wHD8fCWXCM0g==",
"license": "MIT",
"bin": { "bin": {
"fx": "index.js" "fx": "index.js"
} }
@ -234,6 +260,7 @@
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"license": "ISC",
"dependencies": { "dependencies": {
"is-glob": "^4.0.1" "is-glob": "^4.0.1"
}, },
@ -242,13 +269,14 @@
} }
}, },
"node_modules/globby": { "node_modules/globby": {
"version": "13.1.4", "version": "13.2.2",
"resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz",
"integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==",
"license": "MIT",
"dependencies": { "dependencies": {
"dir-glob": "^3.0.1", "dir-glob": "^3.0.1",
"fast-glob": "^3.2.11", "fast-glob": "^3.3.0",
"ignore": "^5.2.0", "ignore": "^5.2.4",
"merge2": "^1.4.1", "merge2": "^1.4.1",
"slash": "^4.0.0" "slash": "^4.0.0"
}, },
@ -262,12 +290,14 @@
"node_modules/graceful-fs": { "node_modules/graceful-fs": {
"version": "4.2.11", "version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
}, },
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.2.4", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 4" "node": ">= 4"
} }
@ -276,6 +306,7 @@
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -284,6 +315,7 @@
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"license": "MIT",
"dependencies": { "dependencies": {
"is-extglob": "^2.1.1" "is-extglob": "^2.1.1"
}, },
@ -295,6 +327,7 @@
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"license": "MIT",
"engines": { "engines": {
"node": ">=0.12.0" "node": ">=0.12.0"
} }
@ -302,12 +335,14 @@
"node_modules/isexe": { "node_modules/isexe": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
}, },
"node_modules/jsonfile": { "node_modules/jsonfile": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"universalify": "^2.0.0" "universalify": "^2.0.0"
}, },
@ -324,16 +359,18 @@
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/micromatch": { "node_modules/micromatch": {
"version": "4.0.5", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"license": "MIT",
"dependencies": { "dependencies": {
"braces": "^3.0.2", "braces": "^3.0.3",
"picomatch": "^2.3.1" "picomatch": "^2.3.1"
}, },
"engines": { "engines": {
@ -344,6 +381,7 @@
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
@ -362,6 +400,7 @@
"url": "https://paypal.me/jimmywarting" "url": "https://paypal.me/jimmywarting"
} }
], ],
"license": "MIT",
"engines": { "engines": {
"node": ">=10.5.0" "node": ">=10.5.0"
} }
@ -370,6 +409,7 @@
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz",
"integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==",
"license": "MIT",
"dependencies": { "dependencies": {
"data-uri-to-buffer": "^4.0.0", "data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4", "fetch-blob": "^3.1.4",
@ -387,6 +427,7 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
"license": "MIT",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@ -395,6 +436,10 @@
"version": "0.0.11", "version": "0.0.11",
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
"integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
"license": [
"MIT",
"Apache2"
],
"dependencies": { "dependencies": {
"through": "~2.3" "through": "~2.3"
} }
@ -403,6 +448,7 @@
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": { "engines": {
"node": ">=8.6" "node": ">=8.6"
}, },
@ -414,6 +460,7 @@
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz",
"integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==",
"license": "MIT",
"dependencies": { "dependencies": {
"event-stream": "=3.3.4" "event-stream": "=3.3.4"
}, },
@ -441,12 +488,14 @@
"type": "consulting", "type": "consulting",
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
] ],
"license": "MIT"
}, },
"node_modules/reusify": { "node_modules/reusify": {
"version": "1.0.4", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
"license": "MIT",
"engines": { "engines": {
"iojs": ">=1.0.0", "iojs": ">=1.0.0",
"node": ">=0.10.0" "node": ">=0.10.0"
@ -470,6 +519,7 @@
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
@ -478,6 +528,7 @@
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
"integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
"license": "MIT",
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@ -489,6 +540,7 @@
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
"integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==",
"license": "MIT",
"dependencies": { "dependencies": {
"through": "2" "through": "2"
}, },
@ -500,6 +552,7 @@
"version": "0.0.4", "version": "0.0.4",
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz",
"integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==",
"license": "MIT",
"dependencies": { "dependencies": {
"duplexer": "~0.1.1" "duplexer": "~0.1.1"
} }
@ -507,12 +560,14 @@
"node_modules/through": { "node_modules/through": {
"version": "2.3.8", "version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
"license": "MIT"
}, },
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"is-number": "^7.0.0" "is-number": "^7.0.0"
}, },
@ -520,18 +575,26 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"license": "MIT"
},
"node_modules/universalify": { "node_modules/universalify": {
"version": "2.0.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 10.0.0" "node": ">= 10.0.0"
} }
}, },
"node_modules/web-streams-polyfill": { "node_modules/web-streams-polyfill": {
"version": "3.2.1", "version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
} }
@ -540,6 +603,7 @@
"version": "0.0.2", "version": "0.0.2",
"resolved": "https://registry.npmjs.org/webpod/-/webpod-0.0.2.tgz", "resolved": "https://registry.npmjs.org/webpod/-/webpod-0.0.2.tgz",
"integrity": "sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg==", "integrity": "sha512-cSwwQIeg8v4i3p4ajHhwgR7N6VyxAf+KYSSsY6Pd3aETE+xEU4vbitz7qQkB0I321xnhDdgtxuiSfk5r/FVtjg==",
"license": "MIT",
"bin": { "bin": {
"webpod": "dist/index.js" "webpod": "dist/index.js"
} }
@ -548,6 +612,7 @@
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz",
"integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==",
"license": "ISC",
"dependencies": { "dependencies": {
"isexe": "^2.0.0" "isexe": "^2.0.0"
}, },
@ -559,17 +624,22 @@
} }
}, },
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.2.2", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": { "engines": {
"node": ">= 14" "node": ">= 14"
} }
}, },
"node_modules/zx": { "node_modules/zx": {
"version": "7.2.2", "version": "7.2.3",
"resolved": "https://registry.npmjs.org/zx/-/zx-7.2.2.tgz", "resolved": "https://registry.npmjs.org/zx/-/zx-7.2.3.tgz",
"integrity": "sha512-50Gjicd6ijTt7Zcz5fNX+rHrmE0uVqC+X6lYKhf2Cu8wIxDpNIzXwTmzchNdW+JY3LFsRcU43B1lHE4HBMmKgQ==", "integrity": "sha512-QODu38nLlYXg/B/Gw7ZKiZrvPkEsjPN3LQ5JFXM7h0JvwhEdPNNl+4Ao1y4+o3CLNiDUNcwzQYZ4/Ko7kKzCMA==",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"@types/fs-extra": "^11.0.1", "@types/fs-extra": "^11.0.1",
"@types/minimist": "^1.2.2", "@types/minimist": "^1.2.2",

View File

@ -1,8 +1,8 @@
hashed_name=`openssl x509 -inform PEM -subject_hash_old -in /ca-cert.cer | head -1` hashed_name=`openssl x509 -inform PEM -subject_hash_old -in /ca-cert.pem | head -1`
adb start-server adb start-server
emulator -avd virtual_dev -writable-system -no-window -no-audio & emulator -avd virtual_dev -writable-system -no-window -no-audio &
cp /ca-cert.cer /$hashed_name.0 cp /ca-cert.pem /$hashed_name.0
bash /preconf/install_cert.sh $hashed_name.0 bash /preconf/install_cert.sh $hashed_name.0
bash /preconf/install_culebra.sh bash /preconf/install_culebra.sh

View File

@ -1,3 +0,0 @@
FROM mitmproxy/mitmproxy:9.0.1
CMD mitmdump --mode socks5 > /log/trafficLog

View File

@ -6,12 +6,8 @@ async function sleep(time) {
async function checkCertExistance() { async function checkCertExistance() {
return await Promise.all([ return await Promise.all([
fs.access("./certificates/mitmproxy-ca-cert.cer", fs.constants.R_OK), fs.access("./certificates/ca.key"),
fs.access("./certificates/mitmproxy-ca-cert.p12", fs.constants.R_OK), fs.access("./certificates/ca.pem", fs.constants.R_OK),
fs.access("./certificates/mitmproxy-ca-cert.pem", fs.constants.R_OK),
fs.access("./certificates/mitmproxy-ca.p12"),
fs.access("./certificates/mitmproxy-ca.pem"),
fs.access("./certificates/mitmproxy-dhparam.pem", fs.constants.R_OK),
]); ]);
} }
@ -19,31 +15,35 @@ async function generateCert() {
//remove certs if they exist //remove certs if they exist
try { try {
await $`rm -rf certificates`; await $`rm -rf certificates`;
await $`mkdir certificates`;
} catch { } catch {
throw new Error( throw new Error(
"To remove certificates, and create new ones, this command must be run with sudo" "To remove certificates, and create new ones, this command must be run with sudo"
); );
} }
//iniciate docker which will create certs await $`docker build --tag certgen $PWD/certgen`
$`docker run --rm -v $PWD/certificates:/home/mitmproxy/.mitmproxy --name certGenerator mitmproxy/mitmproxy:9.0.1 mitmdump &`; // iniciate docker which will create certs
$`docker run --rm -v $PWD/certificates:/certificates --name certGenerator certgen &`;
//wait for certs to generate //wait for certs to generate
let generated = false; let generated = false;
while (!generated) { while (!generated) {
try { try {
await checkCertExistance(); await checkCertExistance();
await $`sleep 1`;
generated = true; generated = true;
} catch {} } catch {}
} }
//kill docker container //kill docker container
$`docker stop certGenerator`; await $`docker stop certGenerator`;
await $`docker rmi certgen`
} }
async function generatePreAndroid() { async function generatePreAndroid() {
await $`docker build -t pre_android pre_android`; await $`docker build -t pre_android pre_android`;
$`docker run --sysctl net.ipv6.conf.all.disable_ipv6=1 --rm -v $PWD/certificates/mitmproxy-ca-cert.cer:/ca-cert.cer -v $PWD/pre_android/preconf:/preconf --device=/dev/kvm --name pre_android_cont pre_android &`; $`docker run --sysctl net.ipv6.conf.all.disable_ipv6=1 --rm -v $PWD/certificates/ca.pem:/ca-cert.pem -v $PWD/pre_android/preconf:/preconf --device=/dev/kvm --name pre_android_cont pre_android &`;
console.log( console.log(
"Installing tls certificate and culebra into the android pre-image..." "Installing tls certificate and culebra into the android pre-image..."
@ -73,6 +73,7 @@ else if (process.argv[3] === "up") {
await checkCertExistance(); await checkCertExistance();
} catch { } catch {
await generateCert(); await generateCert();
await generatePreAndroid(); // if the certs are new, the android should be regenerated
} }
try { try {