Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F9583240
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
110 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/android/Dockerfile b/android/Dockerfile
index 2813e82..0521c96 100644
--- a/android/Dockerfile
+++ b/android/Dockerfile
@@ -1,32 +1,32 @@
FROM pre_android/ready
# Set up node
RUN npm install -g n && n install 22.14.0 && n use 22.14.0 && hash -r
RUN node --version
# Set up httptoolkit-server
RUN git clone https://github.com/httptoolkit/httptoolkit-server /httptoolkit-server
WORKDIR /httptoolkit-server
-RUN git checkout 5c60a70b08d30126639484314f5b5619a388b026 \
+RUN git checkout 490b1b6f5180ad634b60997778c5f96b2f62bf0b \
&& 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
diff --git a/android/code/index.mjs b/android/code/index.mjs
index 1c1fd34..b911125 100644
--- a/android/code/index.mjs
+++ b/android/code/index.mjs
@@ -1,164 +1,171 @@
import child_process from "child_process";
import fs from "fs";
import { Server } from "socket.io";
async function spawnPromise(program, args) {
return new Promise((resolve, _reject) => {
let output = "";
const process = child_process.spawn(program, args);
process.stdout.on("data", (data) => {
output += data;
});
process.stderr.on("data", (data) => {
output += data;
});
process.on("close", (code) => {
resolve({ output, code });
});
});
}
let io = new Server();
async function send_private_data() {
let adid = await spawnPromise("bash", ["/conf/get_adid.sh"])
adid = adid.output;
let gps_coords = await spawnPromise("bash", ["/conf/get_location.sh"])
gps_coords = gps_coords.output;
gps_coords = gps_coords.trim().split(',');
io.emit("private_info", {adid, latitude: gps_coords[0], longitude: gps_coords[1]})
}
function send_notification(socket, is_ok, context, message) {
socket.emit("notification", {
is_ok,
context,
message,
});
}
let screenshot_in_flight = false;
let gps_setting_in_progress = false;
//maybe check output of child processes and send errors in some way
io.on("connection", (socket) => {
socket.onAny((ev, ...args) => {
console.log("server got: ", ev, ...args);
});
socket.on("screenshot", async () => {
if (screenshot_in_flight)
return;
screenshot_in_flight = true;
let screen;
try {
screen = await fetch("http://localhost:9987/v2/uiDevice/screenshot");
} catch(err) {
console.error("Failed to get the screenshot from culebra, the emulator probably died", err);
screenshot_in_flight = false;
return;
}
let body = await screen.bytes();
socket.emit("screenshot_data", body);
screenshot_in_flight = false;
});
socket.on("private_info_req", async () => {
await send_private_data();
})
socket.on("reset_adid", async () => {
await spawnPromise("bash", ["/conf/reset_adid.sh"]);
await send_private_data();
})
socket.on("back", async () => {
if (gps_setting_in_progress) {
send_notification(socket, false, "Interactions not allowed when setting gps coordinates", "");
- send_notification(socket, false, "Back", "");
return ;
}
await spawnPromise("bash", ["/conf/back.sh"]);
});
+ socket.on("recent", async () => {
+ if (gps_setting_in_progress) {
+ send_notification(socket, false, "Interactions not allowed when setting gps coordinates", "");
+ return ;
+ }
+ await spawnPromise("bash", ["/conf/recent.sh"]);
+ });
+
socket.on("home", async () => {
if (gps_setting_in_progress) {
send_notification(socket, false, "Interactions not allowed when setting gps coordinates", "");
return ;
}
await spawnPromise("bash", ["/conf/home.sh"]);
});
socket.on("install", async () => {
const res = await spawnPromise("bash", ["/conf/install.sh"]);
send_notification(
socket,
res.code === 0,
"Installing the application",
res.output
);
});
// drag handles both drag and click
socket.on("motionevent", async (data) => {
if (gps_setting_in_progress) {
send_notification(socket, false, "Interactions not allowed when setting gps coordinates", "");
return ;
}
await spawnPromise("bash", [
"/conf/motionevent.sh",
data.motionType,
data.x + "",
data.y + ""
]);
});
// drag handles both drag and click
socket.on("drag", async (data) => {
if (gps_setting_in_progress) {
send_notification(socket, false, "Interactions not allowed when setting gps coordinates", "");
return ;
}
await spawnPromise("bash", [
"/conf/drag.sh",
data.startX + "",
data.startY + "",
data.endX + "",
data.endY + "",
data.dragTime + "",
]);
});
socket.on("key", async (data) => {
if (gps_setting_in_progress) {
send_notification(socket, false, "Interactions not allowed when setting gps coordinates", "");
return ;
}
await spawnPromise("bash", [
"/conf/press_key.sh",
data.key
]);
});
socket.on("setcoord", async (data) => {
if (gps_setting_in_progress) {
send_notification(socket, false, "Interactions not allowed when setting gps coordinates", "");
return ;
}
gps_setting_in_progress = true;
const res = await spawnPromise("bash", [
"/conf/set_geo_full.sh",
data.lon + "",
data.lat + "",
]);
send_notification(
socket,
res.code === 0,
"Setting the moch location",
res.output
);
gps_setting_in_progress = false;
await send_private_data();
});
});
io.listen(3000);
console.log("listening on port 3000");
diff --git a/android/conf/get_adid.sh b/android/conf/get_adid.sh
index 896eceb..d4b1307 100644
--- a/android/conf/get_adid.sh
+++ b/android/conf/get_adid.sh
@@ -1 +1 @@
-adb shell su root cat /data/data/com.google.android.gms/shared_prefs/adid_settings.xml | xmllint --xpath 'string(//map/string[@name="adid_key"])' -
+adb shell su root cat /data/data/com.google.android.gms/shared_prefs/adid_settings.xml | xmllint --xpath 'string(//map/string[@name="adid_key"])' - | tr -d $'\n'
diff --git a/android/conf/recent.sh b/android/conf/recent.sh
new file mode 100644
index 0000000..df3fb52
--- /dev/null
+++ b/android/conf/recent.sh
@@ -0,0 +1 @@
+/opt/android-sdk-linux/platform-tools/adb shell input keyevent 187
diff --git a/certgen/Dockerfile b/certgen/Dockerfile
index 4089f2e..971ffad 100644
--- a/certgen/Dockerfile
+++ b/certgen/Dockerfile
@@ -1,9 +1,9 @@
FROM node:22.14.0
RUN git clone https://github.com/httptoolkit/httptoolkit-server
WORKDIR /httptoolkit-server
-RUN git checkout 5c60a70b08d30126639484314f5b5619a388b026 \
+RUN git checkout 490b1b6f5180ad634b60997778c5f96b2f62bf0b \
&& npm i && npm run build:src
CMD /httptoolkit-server/bin/run start -c /certificates
diff --git a/http_server/code/docker-entrypoint.sh b/http_server/code/docker-entrypoint.sh
index 8c58d63..8933c6c 100644
--- a/http_server/code/docker-entrypoint.sh
+++ b/http_server/code/docker-entrypoint.sh
@@ -1,6 +1,6 @@
#!/bin/bash
npm i
npm run build
-node --watch index.mjs
-#tail -f /dev/null
+node index.mjs &
+tail -f /dev/null
diff --git a/http_server/code/index.html b/http_server/code/index.html
index a58cc3b..007a1d4 100644
--- a/http_server/code/index.html
+++ b/http_server/code/index.html
@@ -1,474 +1,136 @@
<!doctype html>
<html lang="en">
<head style="height: 100vh">
<meta charset="UTF-8" />
<title>Rentgen android</title>
<script src="/htmx.js"></script>
- <style>
- main {
- display: flex;
- }
-
- .log-section {
- height: auto;
- width: 400px;
- overflow: auto;
- display: flex;
- flex-direction: column;
- margin-left: 20px;
- }
-
- .screen {
- display: inline-block;
- cursor: pointer;
- }
-
- .screen-buttons {
- display: flex;
- justify-content: space-around;
- margin-top: 5px;
- gap: 10px;
- }
-
- .screen-buttons button {
- font-size: 1.1rem;
- padding: 10px 20px;
- width: 100%;
- cursor: pointer;
- background-color: transparent;
- }
-
- .screen-buttons button:hover {
- background-color: aqua;
- }
-
- #clicks-log {
- font-family:
- Menlo,
- Consolas,
- Monaco,
- Liberation Mono,
- Lucida Console,
- 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-direction: column;
- 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;
- }
- #screen {
- user-select: none;
- }
- .tab-section {
- display: flex;
- flex-direction: column;
- flex-grow: 1;
- }
- #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;
- }
- #notifications {
- width: 40%;
- margin-left: 60%;
- position: absolute;
- }
- #logs {
- display: flex;
- flex-direction: row;
- }
- </style>
+ <link rel="stylesheet" href="styles.css" />
+ <script src="/main.js" type="module"></script>
</head>
<body>
<div id="notifications"></div>
<div id="resp" style="display: none"></div>
<main>
<section class="screen-section">
<img
id="screen"
alt="android screen"
src=""
draggable="false"
class="screen"
style="flex-grow: 0"
tabindex="0"
/>
<div class="screen-buttons" style="flex-grow: 0">
+ <button class="screen-buttons-recent-apps">recent-apps</button>
<button class="screen-buttons-home">home</button>
<button class="screen-buttons-back">back</button>
</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
multiple
/>
</label>
<button type="submit">Install the app</button>
</form>
</section>
<div class="tab-section">
<div class="tab">
<button
class="tablinks active"
- onclick="open_tab(event, 'httptoolkit-tab')"
+ onclick="main.open_tab(event, 'httptoolkit-tab')"
>
HttpToolkit UI
</button>
- <button class="tablinks" onclick="open_tab(event, 'logs-tab')">
+ <button class="tablinks" onclick="main.open_tab(event, 'logs-tab')">
Logs
</button>
- <button class="tablinks" onclick="open_tab(event, 'controls-tab')">
+ <button
+ class="tablinks"
+ onclick="main.open_tab(event, 'controls-tab')"
+ >
Device Controls
</button>
</div>
<div class="tabcontent" id="logs-tab">
- <div id="logs">
- <p id="clicks-log" class="log-section"></p>
- <p id="traffic-log" class="log-section"></p>
- </div>
+ <div id="logs">
+ <p id="clicks-log" class="log-section"></p>
+ <div id="traffic-log" class="log-section">
+ <div>
+ <button onClick="main.download_har()">Download HAR</button>
+ <button onClick="main.inspect_har()">Inspect HAR</button>
+ <div>
+ <h2>stats:</h2>
+ <p id="traffic-log-req-res-pairs">
+ Request + responce pairs: 0
+ </p>
+ <p id="traffic-log-waiting">
+ Waiting for the responce: 0
+ </p>
+ </div>
+ <div id="traffic-log-lines">
+ </div>
+ </div>
+ </div>
+ </div>
</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 class="tabcontent" id="controls-tab">
- <form id="set_coords" onsubmit="coords_handler(event)">
+ <form id="set_coords" onsubmit="main.coords_handler(event)">
<label>
Latitude:
<input type="text" name="lat" />
</label>
<label>
Longitude:
<input type="text" name="lon" />
</label>
<button type="submit">Submit coords</button>
</form>
- <button id="reset_adid_btn" onclick="reset_adid_handler(event)">Reset ADID</button>
- <table>
- <thead></thead>
- <tbody>
- <tr>
- <td>ADID:</td>
- <td id="adid_priv_info_table">UNKNOWN</td>
- </tr>
- <tr>
- <td>Longitude:</td>
- <td id="lon_priv_info_table">UNKNOWN</td>
- </tr>
- <tr>
- <td>Latitude:</td>
- <td id="lat_priv_info_table">UNKNOWN</td>
- </tr>
- </tbody>
- </table>
+ <button id="reset_adid_btn" onclick="main.reset_adid_handler(event)">
+ Reset ADID
+ </button>
+ <table>
+ <thead></thead>
+ <tbody>
+ <tr>
+ <td>ADID:</td>
+ <td id="adid_priv_info_table">UNKNOWN</td>
+ </tr>
+ <tr>
+ <td>Longitude:</td>
+ <td id="lon_priv_info_table">UNKNOWN</td>
+ </tr>
+ <tr>
+ <td>Latitude:</td>
+ <td id="lat_priv_info_table">UNKNOWN</td>
+ </tr>
+ </tbody>
+ </table>
</div>
</div>
</main>
- <script src="/socket.io.js"></script>
- <script>
- var socket = io();
-
- function reset_adid_handler(e) {
- socket.emit("reset_adid");
- }
-
- function coords_handler(e) {
- e.preventDefault();
- const form_data = new FormData(e.target);
- console.log(form_data);
- socket.emit("setcoord", {
- lon: Number.parseFloat(form_data.get("lon")),
- lat: Number.parseFloat(form_data.get("lat")),
- });
- }
-
- 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");
- }
- var screen = document.getElementById("screen");
- var clicksLog = document.getElementById("clicks-log");
- const homeButton = document.querySelector(".screen-buttons-home");
- const backButton = document.querySelector(".screen-buttons-back");
-
- let lastTouch = new Date().getTime();
-
- const calculateElapsedTime = (last) => {
- const currentTouch = new Date().getTime();
- const elapsedTime = currentTouch - lastTouch;
- const elapsedSec = Math.round(elapsedTime / 1000);
- lastTouch = currentTouch;
- return elapsedSec;
- };
-
- const waitToLog = (clickInfoText) => {
- const clickInfo = document.createElement("span");
- const waitInfo = document.createElement("span");
- waitInfo.textContent = `await wait(${calculateElapsedTime(
- lastTouch
- )});`;
- clicksLog.appendChild(waitInfo);
- clickInfo.textContent = clickInfoText;
- clicksLog.appendChild(clickInfo);
- };
-
- const registerClick = ({ path, logText, body }) => {
- const clicksLog = document.getElementById("clicks-log");
- const span = document.createElement("span");
-
- waitToLog(logText);
- socket.emit(path, body ? body : {});
- };
-
- homeButton.addEventListener("click", () =>
- registerClick({ path: "home", logText: "await homeButton();" })
- );
-
- backButton.addEventListener("click", () =>
- registerClick({ path: "back", logText: "await backButton();" })
- );
-
- socket.on("screenshot_data", (data) => {
- try {
- const blob = new Blob([data]);
- screen.src = URL.createObjectURL(blob);
- } catch (error) {
- console.error("Error fetching image: ", error);
- }
- });
-
- socket.on("private_info", (data) => {
- console.log("private_info");
- adid_priv_info_table.textContent = data.adid;
- lat_priv_info_table.textContent = data.latitude;
- lon_priv_info_table.textContent = data.longitude;
- });
-
- socket.emit("private_info_req");
-
- socket.onAny((ev, ...args) => {
- console.log("ev: ", ev, args);
- });
-
- async function displayImage() {
- socket.emit("screenshot");
- }
-
- let isDragging = false;
- const screenSize = [320, 640];
-
- function calcMousePos(event) {
- let rect = screen.getBoundingClientRect();
- let x = ((event.clientX - rect.left) / rect.width) * screenSize[0];
- let y = ((event.clientY - rect.top) / rect.height) * screenSize[1];
- x = Math.min(Math.max(x, 0), screenSize[0]);
- y = Math.min(Math.max(y, 0), screenSize[1]);
- return { x, y };
- }
-
- screen.addEventListener(
- "mousemove",
- (event) => {
- if (!isDragging) return;
- let pos = calcMousePos(window.event);
-
- if (isDragging) {
- registerClick({
- path: "motionevent",
- logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
- body: {
- motionType: "MOVE",
- x: pos.x,
- y: pos.y,
- },
- });
- }
- },
- false
- );
-
- const handleDraggStart = (event) => {
- isDragging = true;
- let pos = calcMousePos(event);
- registerClick({
- path: "motionevent",
- logText: `await motionevent({motionType: "DOWN", x:${pos.x},y:${pos.y}}});`,
- body: {
- motionType: "DOWN",
- x: pos.x,
- y: pos.y,
- },
- });
- };
-
- screen.addEventListener("mousedown", handleDraggStart);
-
- document.addEventListener("mouseup", (e) => {
- if (!isDragging) return;
- isDragging = false;
- let pos = calcMousePos(e);
- registerClick({
- path: "motionevent",
- logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
- body: {
- motionType: "MOVE",
- x: pos.x,
- y: pos.y,
- },
- });
- registerClick({
- path: "motionevent",
- logText: `await motionevent({motionType: "UP", x:${pos.x},y:${pos.y}}});`,
- body: {
- motionType: "UP",
- x: pos.x,
- y: pos.y,
- },
- });
- });
-
- window.addEventListener("keydown", (event) => {
- let key = event.key;
- if (key === "Space") key = " ";
- else if (key !== "Enter" && key !== "Backspace" && key.length !== 1)
- return;
- console.log(event.key, key);
- if (document.getElementById("screen").matches(":hover")) {
- registerClick({
- path: "key",
- logText: `await key(${event.key});`,
- body: { key },
- });
- }
- });
-
- async function sleep(time) {
- return new Promise((resolve) => setTimeout(resolve, time));
- }
-
- async function screenshot_loop() {
- var before;
-
- while (true) {
- before = performance.now();
- await displayImage();
- while (performance.now() - before < ___screenshotDelayMs___)
- await sleep(50);
- }
- }
- screenshot_loop();
- </script>
- <script src="/trafficLog.js"></script>
- <script src="/notifications.js"></script>
</body>
</html>
diff --git a/http_server/code/index.mjs b/http_server/code/index.mjs
index 222f219..9b18a9b 100644
--- a/http_server/code/index.mjs
+++ b/http_server/code/index.mjs
@@ -1,110 +1,114 @@
import express from "express";
import { readFile } from "node:fs/promises";
import { execSync } from "node:child_process";
import { Server } from "socket.io";
import { io } from "socket.io-client";
-import { build_html } from "./har-analyzer/build_html.js"
+import { build_html } from "har-analyzer"
import fileUpload from "express-fileupload";
const app = express();
+import multer from "multer"
+
+const upload = multer();
async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
console.log("Waiting for full boot...");
// bidirectional forwarding
// Wait untill the connection
const back = io("ws://android:3000", {
reconnectionAttempts: 1000000,
reconnectionDelay: 100,
});
while (!back.connected) {
await sleep(100);
}
console.log("Boot detected! activating endpoints");
app.use(express.urlencoded({ extended: false }));
app.use(express.static("/code/dist"));
//GET
app.get("/favicon.ico", function (_req, res) {
res.sendFile("/code/favicon.ico");
});
app.get("/htmx.js", function (_req, res) {
res.sendFile("/code/node_modules/htmx.org/dist/htmx.min.js");
});
app.get("/socket.io.js", function (_req, res) {
res.sendFile("/code/node_modules/socket.io/client-dist/socket.io.js");
});
app.get("/", async function (req, res) {
let fileData = (await readFile("/code/index.html")).toString();
fileData = fileData.replace(
"___screenshotDelayMs___",
process.env.screenshotDelayMs
);
res.setHeader("Content-Type", "text/html");
res.setHeader("Content-Disposition", "inline");
res.send(fileData);
});
//POST
app.use(express.text({limit: "100mb"}));
-app.post("/inspect_har", function (req, res) {
- let body = JSON.parse(req.body);
- let har = JSON.stringify(body.har);
+app.post("/inspect_har", upload.none(), function (req, res) {
+ let body = req.body;
+ let har = body.har;
let private_data;
if (body.private_data)
- private_data = body.private_data;
+ private_data = JSON.parse(body.private_data);
res.setHeader("Content-Type", "text/html");
- res.send(build_html(har, private_data, "/code/har-analyzer/"));
+ console.log(private_data);
+ res.send(build_html(har, private_data));
});
app.use(fileUpload());
app.post("/upload_apk", async function (req, res) {
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send("No files were uploaded.");
}
execSync("rm -rf /shared_buffer/*");
if (Array.isArray(req.files.app)) {
for (const [idx, file] of req.files.app.entries()) {
let uploadPath = "/shared_buffer/app" + idx + ".apk";
await file.mv(uploadPath);
}
} else {
let uploadPath = "/shared_buffer/app" + 0 + ".apk";
await req.files.app.mv(uploadPath);
}
back.emit("install");
res.send("Files uploaded!");
});
let server = app.listen(8080, () => console.log("Listening in port 8080"));
const front = new Server(server);
// forwarding the messages
front.on("connection", (socket) => {
socket.onAny((event, ...args) => {
if (back.connected) {
back.emit(event, ...args);
} else {
console.log("Front tried to send: ", event, ...args);
}
});
});
back.onAny((event, ...args) => {
front.emit(event, ...args);
});
diff --git a/http_server/code/package-lock.json b/http_server/code/package-lock.json
index bd86331..11f9461 100644
--- a/http_server/code/package-lock.json
+++ b/http_server/code/package-lock.json
@@ -1,1448 +1,1622 @@
{
"name": "code",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"@types/har-format": "^1.2.16",
"express": "^4.18.2",
"express-fileupload": "^1.5.1",
+ "har-analyzer": "git+ssh://git@hub.sealcode.org/diffusion/171/har-parser.git#master",
"htmx.org": "^1.9.12",
+ "multer": "^2.0.2",
"preact": "^10.18.1",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"ws": "^8.18.0"
},
"devDependencies": {
"esbuild": "^0.19.5"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.5.tgz",
"integrity": "sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.5.tgz",
"integrity": "sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.5.tgz",
"integrity": "sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.5.tgz",
"integrity": "sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.5.tgz",
"integrity": "sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.5.tgz",
"integrity": "sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.5.tgz",
"integrity": "sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.5.tgz",
"integrity": "sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.5.tgz",
"integrity": "sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.5.tgz",
"integrity": "sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.5.tgz",
"integrity": "sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.5.tgz",
"integrity": "sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.5.tgz",
"integrity": "sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.5.tgz",
"integrity": "sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.5.tgz",
"integrity": "sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.5.tgz",
"integrity": "sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.5.tgz",
"integrity": "sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.5.tgz",
"integrity": "sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.5.tgz",
"integrity": "sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.5.tgz",
"integrity": "sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.5.tgz",
"integrity": "sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.5.tgz",
"integrity": "sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
+ "node_modules/@smithy/util-hex-encoding": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.0.0.tgz",
+ "integrity": "sha512-Yk5mLhHtfIgW2W2WQZWSg5kuMZCVbvhFmC7rV4IO2QqnZdbEFPmQnCcGMAX2z/8Qj3B9hYYNjZOhWym+RwhePw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.6.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
"license": "MIT"
},
"node_modules/@types/cors": {
"version": "2.8.18",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.18.tgz",
"integrity": "sha512-nX3d0sxJW41CqQvfOzVG1NCTXfFDrDWIghCZncpHeWlVFd81zxB/DLhg7avFg6eHLCRX7ckBmoIIcqa++upvJA==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/har-format": {
"version": "1.2.16",
"resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz",
"integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==",
"license": "MIT"
},
"node_modules/@types/node": {
"version": "22.15.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.21.tgz",
"integrity": "sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==",
"license": "MIT",
"dependencies": {
"undici-types": "~6.21.0"
}
},
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
+ "node_modules/append-field": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
+ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
+ "license": "MIT"
+ },
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
},
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
"license": "MIT",
"engines": {
"node": "^4.5.0 || >= 5.9"
}
},
"node_modules/body-parser": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.11.0",
"raw-body": "2.5.1",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "license": "MIT"
+ },
"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": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/call-bind": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
"dependencies": {
"function-bind": "^1.1.1",
"get-intrinsic": "^1.0.2"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "engines": [
+ "node >= 6.0"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
+ },
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dependencies": {
"safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/engine.io": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz",
"integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==",
"license": "MIT",
"dependencies": {
"@types/cors": "^2.8.12",
"@types/node": ">=10.0.0",
"accepts": "~1.3.4",
"base64id": "2.0.0",
"cookie": "~0.7.2",
"cors": "~2.8.5",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1"
},
"engines": {
"node": ">=10.2.0"
}
},
"node_modules/engine.io-client": {
"version": "6.6.3",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.3.tgz",
"integrity": "sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.17.1",
"xmlhttprequest-ssl": "~2.1.1"
}
},
"node_modules/engine.io-client/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/engine.io-client/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/engine.io-client/node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/engine.io/node_modules/cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/engine.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/engine.io/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/engine.io/node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/esbuild": {
"version": "0.19.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz",
"integrity": "sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.19.5",
"@esbuild/android-arm64": "0.19.5",
"@esbuild/android-x64": "0.19.5",
"@esbuild/darwin-arm64": "0.19.5",
"@esbuild/darwin-x64": "0.19.5",
"@esbuild/freebsd-arm64": "0.19.5",
"@esbuild/freebsd-x64": "0.19.5",
"@esbuild/linux-arm": "0.19.5",
"@esbuild/linux-arm64": "0.19.5",
"@esbuild/linux-ia32": "0.19.5",
"@esbuild/linux-loong64": "0.19.5",
"@esbuild/linux-mips64el": "0.19.5",
"@esbuild/linux-ppc64": "0.19.5",
"@esbuild/linux-riscv64": "0.19.5",
"@esbuild/linux-s390x": "0.19.5",
"@esbuild/linux-x64": "0.19.5",
"@esbuild/netbsd-x64": "0.19.5",
"@esbuild/openbsd-x64": "0.19.5",
"@esbuild/sunos-x64": "0.19.5",
"@esbuild/win32-arm64": "0.19.5",
"@esbuild/win32-ia32": "0.19.5",
"@esbuild/win32-x64": "0.19.5"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.1",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.5.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.2.0",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.1",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.7",
"qs": "6.11.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.18.0",
"serve-static": "1.15.0",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"engines": {
"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": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"node_modules/get-intrinsic": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
"integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
"dependencies": {
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/har-analyzer": {
+ "name": "module-starter",
+ "version": "0.0.1",
+ "resolved": "git+ssh://git@hub.sealcode.org/diffusion/171/har-parser.git#167d6bce983a30ac9699474c26ec6b0222a7309e",
+ "license": "ISC",
+ "dependencies": {
+ "@smithy/util-hex-encoding": "^4.0.0",
+ "base64-js": "^1.5.1",
+ "pako": "^2.1.0",
+ "tabulator-tables": "^6.3.1"
+ }
+ },
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/has-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
"integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
},
"node_modules/methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
"node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
+ "node_modules/multer": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz",
+ "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==",
+ "license": "MIT",
+ "dependencies": {
+ "append-field": "^1.0.0",
+ "busboy": "^1.6.0",
+ "concat-stream": "^2.0.0",
+ "mkdirp": "^0.5.6",
+ "object-assign": "^4.1.1",
+ "type-is": "^1.6.18",
+ "xtend": "^4.0.2"
+ },
+ "engines": {
+ "node": ">= 10.16.0"
+ }
+ },
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
+ "node_modules/pako": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
+ "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
+ "license": "(MIT AND Zlib)"
+ },
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/path-to-regexp": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"node_modules/preact": {
"version": "10.18.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.18.1.tgz",
"integrity": "sha512-mKUD7RRkQQM6s7Rkmi7IFkoEHjuFqRQUaXamO61E6Nn7vqF/bo7EZCmSyrUnp2UWHw0O7XjZ2eeXis+m7tf4lg==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
"dependencies": {
"forwarded": "0.2.0",
"ipaddr.js": "1.9.1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dependencies": {
"side-channel": "^1.0.4"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/raw-body": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/send": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
"dependencies": {
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/send/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/serve-static": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
"dependencies": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.18.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
"dependencies": {
"call-bind": "^1.0.0",
"get-intrinsic": "^1.0.2",
"object-inspect": "^1.9.0"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/socket.io": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"license": "MIT",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"cors": "~2.8.5",
"debug": "~4.3.2",
"engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.2.0"
}
},
"node_modules/socket.io-adapter": {
"version": "2.5.5",
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
"license": "MIT",
"dependencies": {
"debug": "~4.3.4",
"ws": "~8.17.1"
}
},
"node_modules/socket.io-adapter/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io-adapter/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/socket.io-adapter/node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/socket.io-client": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.6.1",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-client/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io-client/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io-parser/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/socket.io/node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/socket.io/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"engines": {
"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/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/tabulator-tables": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/tabulator-tables/-/tabulator-tables-6.3.1.tgz",
+ "integrity": "sha512-qFW7kfadtcaISQIibKAIy0f3eeIXUVi8242Vly1iJfMD79kfEGzfczNuPBN/80hDxHzQJXYbmJ8VipI40hQtfA==",
+ "license": "MIT"
+ },
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"engines": {
"node": ">=0.6"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
},
"engines": {
"node": ">= 0.6"
}
},
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "license": "MIT"
+ },
"node_modules/undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"license": "MIT"
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"engines": {
"node": ">= 0.8"
}
},
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/ws": {
"version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"engines": {
"node": ">=0.4.0"
}
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4"
+ }
}
}
}
diff --git a/http_server/code/package.json b/http_server/code/package.json
index 4ea4dce..6529d3f 100644
--- a/http_server/code/package.json
+++ b/http_server/code/package.json
@@ -1,18 +1,20 @@
{
"scripts": {
- "build": "esbuild --sourcemap --bundle src/trafficLog.tsx src/notifications.jsx --outdir=dist/ --jsx-factory=h --jsx-fragment=Fragment"
+ "build": "esbuild --format=esm --sourcemap --bundle src/main.ts --outdir=dist/ --jsx-factory=h --jsx-fragment=Fragment"
},
"dependencies": {
"@types/har-format": "^1.2.16",
"express": "^4.18.2",
"express-fileupload": "^1.5.1",
"htmx.org": "^1.9.12",
+ "multer": "^2.0.2",
"preact": "^10.18.1",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
- "ws": "^8.18.0"
+ "ws": "^8.18.0",
+ "har-analyzer": "git+ssh://git@hub.sealcode.org/diffusion/171/har-parser.git#master"
},
"devDependencies": {
"esbuild": "^0.19.5"
}
}
diff --git a/http_server/code/src/main.ts b/http_server/code/src/main.ts
new file mode 100644
index 0000000..0941c8d
--- /dev/null
+++ b/http_server/code/src/main.ts
@@ -0,0 +1,232 @@
+// make the export accessible from inline js
+import * as main from "./main";
+// for some reason doing the same with the window object doesn't work
+(globalThis as any).main = main;
+
+import {
+ backButton,
+ clicksLog,
+ homeButton,
+ socket,
+ screen,
+ adid_priv_info_table,
+ lat_priv_info_table,
+ lon_priv_info_table,
+ recentButton,
+} from "./shared";
+
+import { start_notifications } from "./notifications";
+import { start_traffic_log } from "./traffic_log";
+
+export { download_har, inspect_har } from "./traffic_log";
+
+export function reset_adid_handler(_: Event) {
+ socket.emit("reset_adid");
+}
+
+export function coords_handler(e: FormDataEvent) {
+ e.preventDefault();
+ const form_data = new FormData(e.target as HTMLFormElement);
+ socket.emit("setcoord", {
+ lon: Number.parseFloat(form_data.get("lon") as string),
+ lat: Number.parseFloat(form_data.get("lat") as string),
+ });
+}
+
+export function open_tab(evt: Event, tab_name: string) {
+ 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 as HTMLElement).classList.add("active");
+}
+
+let lastTouch = new Date().getTime();
+
+export const calculateElapsedTime = () => {
+ const currentTouch = new Date().getTime();
+ const elapsedTime = currentTouch - lastTouch;
+ const elapsedSec = Math.round(elapsedTime / 1000);
+ lastTouch = currentTouch;
+ return elapsedSec;
+};
+
+export const waitToLog = (clickInfoText: string) => {
+ const clickInfo = document.createElement("span");
+ const waitInfo = document.createElement("span");
+ waitInfo.textContent = `await wait(${calculateElapsedTime()});`;
+ clicksLog.appendChild(waitInfo);
+ clickInfo.textContent = clickInfoText;
+ clicksLog.appendChild(clickInfo);
+};
+
+export const registerClick = ({
+ path,
+ logText,
+ body,
+}: {
+ path: string;
+ logText: string;
+ body?: any;
+}) => {
+ waitToLog(logText);
+ socket.emit(path, body ? body : {});
+};
+
+homeButton.addEventListener("click", () =>
+ registerClick({ path: "home", logText: "await homeButton();" })
+);
+
+backButton.addEventListener("click", () =>
+ registerClick({ path: "back", logText: "await backButton();" })
+);
+
+recentButton.addEventListener("click", () =>
+ registerClick({ path: "recent", logText: "await recentButton();" })
+);
+
+socket.on("screenshot_data", (data) => {
+ try {
+ const blob = new Blob([data]);
+ screen.src = URL.createObjectURL(blob);
+ } catch (error) {
+ console.error("Error fetching image: ", error);
+ }
+});
+
+socket.on("private_info", (data) => {
+ console.log("private_info");
+ adid_priv_info_table.textContent = data.adid;
+ lat_priv_info_table.textContent = data.latitude;
+ lon_priv_info_table.textContent = data.longitude;
+});
+
+socket.emit("private_info_req");
+
+socket.onAny((ev, ...args) => {
+ console.log("ev: ", ev, args);
+});
+
+async function displayImage() {
+ socket.emit("screenshot");
+}
+
+let isDragging = false;
+const screenSize = [320, 640];
+
+export function calcMousePos(event: MouseEvent) {
+ let rect = screen.getBoundingClientRect();
+ let x = ((event.clientX - rect.left) / rect.width) * screenSize[0];
+ let y = ((event.clientY - rect.top) / rect.height) * screenSize[1];
+ x = Math.min(Math.max(x, 0), screenSize[0]);
+ y = Math.min(Math.max(y, 0), screenSize[1]);
+ return { x, y };
+}
+
+screen.addEventListener(
+ "mousemove",
+ (event) => {
+ if (!isDragging) return;
+ let pos = calcMousePos(event);
+
+ if (isDragging) {
+ registerClick({
+ path: "motionevent",
+ logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
+ body: {
+ motionType: "MOVE",
+ x: pos.x,
+ y: pos.y,
+ },
+ });
+ }
+ },
+ false
+);
+
+export const handleDraggStart = (event: MouseEvent) => {
+ isDragging = true;
+ let pos = calcMousePos(event);
+ registerClick({
+ path: "motionevent",
+ logText: `await motionevent({motionType: "DOWN", x:${pos.x},y:${pos.y}}});`,
+ body: {
+ motionType: "DOWN",
+ x: pos.x,
+ y: pos.y,
+ },
+ });
+};
+
+screen.addEventListener("mousedown", handleDraggStart);
+
+document.addEventListener("mouseup", (e) => {
+ if (!isDragging) return;
+ isDragging = false;
+ let pos = calcMousePos(e);
+ registerClick({
+ path: "motionevent",
+ logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
+ body: {
+ motionType: "MOVE",
+ x: pos.x,
+ y: pos.y,
+ },
+ });
+ registerClick({
+ path: "motionevent",
+ logText: `await motionevent({motionType: "UP", x:${pos.x},y:${pos.y}}});`,
+ body: {
+ motionType: "UP",
+ x: pos.x,
+ y: pos.y,
+ },
+ });
+});
+
+window.addEventListener("keydown", (event) => {
+ let key = event.key;
+ if (key === "Space") key = " ";
+ else if (key !== "Enter" && key !== "Backspace" && key.length !== 1) return;
+ console.log(event.key, key);
+ if (screen.matches(":hover")) {
+ registerClick({
+ path: "key",
+ logText: `await key(${event.key});`,
+ body: { key },
+ });
+ }
+});
+
+export async function sleep(time: number) {
+ return new Promise((resolve) => setTimeout(resolve, time));
+}
+
+async function screenshot_loop() {
+ var before;
+
+ while (true) {
+ before = performance.now();
+ await displayImage();
+ // TODO: Make this dynamic again
+ while (performance.now() - before < 100) await sleep(50);
+ }
+}
+screenshot_loop();
+start_notifications();
+start_traffic_log();
diff --git a/http_server/code/src/notifications.jsx b/http_server/code/src/notifications.jsx
deleted file mode 100644
index edfe1b8..0000000
--- a/http_server/code/src/notifications.jsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import { render, Component } from "preact";
-import { io } from "socket.io-client";
-
-function rand_num() {
- return Math.floor(Math.random() * Number.MAX_VALUE);
-}
-
-class Notifications extends Component {
- constructor() {
- super();
- this.state = { notifications: [] };
- }
-
- remove_notification(id) {
- const newNotifications = this.state.notifications.filter(
- (notification) => notification.id !== id
- );
- this.setState({ notifications: newNotifications });
- }
-
- componentDidMount() {
- // This should also be dynamic
-
- io().on("notification", (data) => {
- let new_id = rand_num();
- this.setState({
- notifications: [
- { id: new_id, notification: data },
- ...this.state.notifications,
- ],
- });
- // a 10 sec timeout
- setTimeout(() => {
- this.remove_notification(new_id);
- }, 10000);
- });
- }
-
- render() {
- return this.state.notifications.map(({ id, notification }) => (
- <div
- onClick={() => this.remove_notification(id)}
- style={`
- background-color: ${notification.is_ok ? "#66ff99" : "#ff5c33"};
- border-radius: 5px;
- border-width: 2px;
- border-style: solid;
- border-color: ${notification.is_ok ? "#369648" : "#a23915"};
- padding: 5px;
- margin-top: 2px;
- margin-bottom: 2px;
- `}
- >
- <div>
- <b>{notification.context}</b>
- </div>
- <div>
- {notification.message.split("\n").map((line) => (
- <p>{line}</p>
- ))}
- </div>
- </div>
- ));
- }
-}
-
-render(<Notifications />, document.getElementById("notifications"));
diff --git a/http_server/code/src/notifications.ts b/http_server/code/src/notifications.ts
new file mode 100644
index 0000000..c84e955
--- /dev/null
+++ b/http_server/code/src/notifications.ts
@@ -0,0 +1,41 @@
+import * as shared from "./shared";
+
+const notifications = document.getElementById("notifications")!;
+
+function create_notification(notification: {
+ is_ok: boolean;
+ message: string;
+ context: string;
+}): HTMLElement {
+ const el = document.createElement("div");
+
+ el.addEventListener("click", (_) => {
+ el.remove();
+ });
+
+ el.classList.add("notification");
+ if (notification.is_ok) el.classList.add("notification_ok");
+ else el.classList.add("notification_err");
+
+ // el.innerText = notification.message;
+ el.innerHTML = `
+ <div><b>${notification.context}</b></div>
+ <div>
+ ${notification.message
+ .split("\n")
+ .map((line) => `<p>${line}</p>`)
+ .join("")}
+ </div>`;
+ return el;
+}
+
+export function start_notifications() {
+ shared.socket.on("notification", (data) => {
+ let el = create_notification(data);
+ notifications.appendChild(el);
+ // a 10 sec timeout
+ setTimeout(() => {
+ el.remove();
+ }, 10000);
+ });
+}
diff --git a/http_server/code/src/shared.ts b/http_server/code/src/shared.ts
new file mode 100644
index 0000000..e9ee988
--- /dev/null
+++ b/http_server/code/src/shared.ts
@@ -0,0 +1,15 @@
+import { io } from "socket.io-client";
+
+export const screen = document.getElementById("screen")! as HTMLImageElement;
+
+export const clicksLog = document.getElementById("clicks-log")!;
+
+export const recentButton = document.querySelector(".screen-buttons-recent-apps")!;
+export const homeButton = document.querySelector(".screen-buttons-home")!;
+export const backButton = document.querySelector(".screen-buttons-back")!;
+
+export const adid_priv_info_table = document.getElementById("adid_priv_info_table")!;
+export const lat_priv_info_table = document.getElementById("lat_priv_info_table")!;
+export const lon_priv_info_table = document.getElementById("lon_priv_info_table")!;
+
+export const socket = io();
diff --git a/http_server/code/src/trafficLog.tsx b/http_server/code/src/trafficLog.tsx
deleted file mode 100644
index 461648e..0000000
--- a/http_server/code/src/trafficLog.tsx
+++ /dev/null
@@ -1,253 +0,0 @@
-import { Entry, Har, PostData, Request, Response } from "har-format";
-import { render, Component } from "preact";
-
-type MyState = {
- finished_entries: Entry[];
- unfinished_entries: Map<string, Entry>;
-};
-
-class TrafficLog extends Component {
- connection: WebSocket | undefined;
-
- state: MyState = { finished_entries: [], unfinished_entries: new Map() };
-
- constructor() {
- super();
- }
-
- componentDidMount() {
- // This should also be dynamic
- this.connection = new WebSocket("ws://localhost:10001");
- this.connection.onmessage = (msg) => {
- this.process_msg(msg.data);
- this.setState({
- finished_entries: this.state.finished_entries,
- unfinished_entries: this.state.unfinished_entries,
- });
- };
- this.connection.onclose = this.connection.onerror = () => {
- window.location.reload();
- };
- }
-
- render() {
- const download_har = () => {
- var tempLink = document.createElement("a");
- var taBlob = new Blob([JSON.stringify(this.export_har())], {
- type: "text/plain",
- });
-
- tempLink.setAttribute("href", URL.createObjectURL(taBlob));
- tempLink.setAttribute("download", `rentgendroid-capture.har`);
-
- tempLink.click();
-
- URL.revokeObjectURL(tempLink.href);
- };
-
- const inspect_har = async () => {
- const req_body = {
- har: this.export_har(),
- private_data: [
- [
- "adid",
- document.getElementById("adid_priv_info_table")!
- .textContent,
- ],
- [
- "latitude",
- document.getElementById("lat_priv_info_table")!
- .textContent,
- ],
- [
- "longitude",
- document.getElementById("lon_priv_info_table")!
- .textContent,
- ],
- ],
- };
-
- const resp = await fetch("/inspect_har", {
- method: "POST",
- body: JSON.stringify(req_body),
- });
- const resp_text = await resp.text();
- const newWindow = window.open();
- newWindow?.document.write(resp_text);
- newWindow?.document.close();
- };
-
- const contentWithLineBreaks = this.state.finished_entries.map((req) => {
- return (
- <span>
- {req.request.url}
- <br />
- </span>
- );
- });
-
- return (
- <div>
- <button onClick={download_har}>Download HAR</button>
- <button onClick={inspect_har}>Inspect HAR</button>
- <div>
- <h2>stats: </h2>
- <p>
- Request + responce pairs:{" "}
- {this.state.finished_entries.length}
- </p>
- <p>
- Waiting for the responce:{" "}
- {this.state.unfinished_entries.size}
- </p>
- </div>
- <div>{contentWithLineBreaks}</div>
- </div>
- );
- }
-
- process_msg(s: string) {
- let obj = JSON.parse(s);
- console.log(obj);
-
- if (obj.type !== "data") return;
- if (obj.payload && obj.payload.data && obj.payload.data.requestReceived)
- this.process_req(obj.payload.data.requestReceived);
- if (
- obj.payload &&
- obj.payload.data &&
- obj.payload.data.responseCompleted
- )
- this.process_res(obj.payload.data.responseCompleted);
- }
-
- process_res(res: any) {
- let entry = this.state.unfinished_entries.get(res.id)!;
-
- let content_type = "application/text";
- let headers = JSON.parse(res.rawHeaders).map(
- (header: [string, string]) => {
- if (header[0].toLowerCase() === "content-type")
- content_type = header[1];
- return { name: header[0], value: header[1], comment: "" };
- }
- );
-
- //'{"startTime":1751745139334,
- // "startTimestamp":347666.762487,
- // "bodyReceivedTimestamp":347667.529477,
- // "headersSentTimestamp":347906.038202,
- // "responseSentTimestamp":347906.616067}'
-
- let timing_events = JSON.parse(res.timingEvents);
-
- let start_ts = timing_events.startTimestamp;
- let got_headers_ts = timing_events.headersSentTimestamp;
- let end_ts = timing_events.responseSentTimestamp;
-
- let wait_time = got_headers_ts - start_ts;
- let recieve_time = end_ts - got_headers_ts;
-
- let response: Response = {
- status: res.statusCode,
- statusText: res.statusMessage,
- httpVersion: entry.request.httpVersion,
- cookies: [],
- headers,
- content: {
- size: 0,
- mimeType: content_type,
- text: res.body,
- encoding: "base64",
- },
- redirectURL: "",
- headersSize: -1,
- bodySize: -1,
- };
-
- entry.response = response;
- entry.timings.wait = wait_time;
- entry.timings.receive = recieve_time;
- this.state.unfinished_entries.delete(res.id);
- this.state.finished_entries.push(entry);
- }
-
- process_req(req: any) {
- let content_type = "application/text";
-
- let headers = JSON.parse(req.rawHeaders).map(
- (header: [string, string]) => {
- if (header[0].toLowerCase() === "Content-Type")
- content_type = header[1];
- return { name: header[0], value: header[1], comment: "" };
- }
- );
-
- let timing_events = JSON.parse(req.timingEvents);
-
- let start_time: number = timing_events.startTime!;
-
- let start_datetime = new Date(start_time).toISOString();
-
- let request: Request = {
- method: req.method,
- url: req.url,
- httpVersion: req.httpVersion,
- cookies: [],
- headers,
- queryString: [],
- postData: req.body
- ? ({ text: req.body, mimeType: content_type } as PostData)
- : undefined,
- headersSize: -1,
- bodySize: -1,
- comment: "",
- };
-
- //'{"startTime":1751745139334,"startTimestamp":347666.762487,"bodyReceivedTimestamp":347667.529477,"headersSentTimestamp":347906.038202,"responseSentTimestamp":347906.616067}'
- let entry: Entry = {
- startedDateTime: start_datetime,
- time: 0,
- request: request,
- response: {
- status: 0,
- statusText: "",
- httpVersion: "",
- cookies: [],
- headers: [],
- content: {
- size: 0,
- mimeType: "",
- },
- redirectURL: "",
- headersSize: 0,
- bodySize: 0,
- },
- cache: {},
- timings: {
- wait: 0,
- receive: 0,
- },
- };
- this.state.unfinished_entries.set(req.id, entry);
- }
-
- export_har(): Har {
- let ret: Har = {
- log: {
- version: "1.2",
- creator: {
- name: "Rentgendroid",
- version: "0.0.1",
- },
- entries: [
- ...this.state.finished_entries,
- ...this.state.unfinished_entries.values(),
- ],
- },
- };
- return ret;
- }
-}
-
-render(<TrafficLog />, document.getElementById("traffic-log")!);
diff --git a/http_server/code/src/traffic_log.ts b/http_server/code/src/traffic_log.ts
new file mode 100644
index 0000000..a770a3d
--- /dev/null
+++ b/http_server/code/src/traffic_log.ts
@@ -0,0 +1,224 @@
+import { Entry, Har, PostData, Request, Response } from "har-format";
+import {
+ adid_priv_info_table,
+ lat_priv_info_table,
+ lon_priv_info_table,
+} from "./shared";
+
+// Request + responce pairs: 0
+const req_res_pairs = document.getElementById("traffic-log-req-res-pairs")!;
+
+// Waiting for the responce: 0
+const waiting = document.getElementById("traffic-log-waiting")!;
+
+const traffic_log_lines = document.getElementById("traffic-log-lines")!;
+
+const inspect_har_form: HTMLFormElement = document.getElementById(
+ "inspect-har-form"
+)! as HTMLFormElement;
+
+const connection = new WebSocket("ws://localhost:10001");
+
+const unfinished_entries: Map<string, Entry> = new Map();
+const finished_entries: Entry[] = [];
+
+export function start_traffic_log() {
+ update_stats();
+ connection.onmessage = (msg) => {
+ process_msg(msg.data);
+ update_stats();
+ };
+ connection.onclose = connection.onerror = () => {
+ window.location.reload();
+ };
+}
+
+export function download_har() {
+ var tempLink = document.createElement("a");
+ var taBlob = new Blob([JSON.stringify(export_har())], {
+ type: "text/plain",
+ });
+
+ tempLink.setAttribute("href", URL.createObjectURL(taBlob));
+ tempLink.setAttribute("download", `rentgendroid-capture.har`);
+
+ tempLink.click();
+
+ URL.revokeObjectURL(tempLink.href);
+}
+
+function launch_window_with_post(url: string, data: any) {
+ let form = document.createElement("form");
+ form.target = "_blank";
+ form.method = "POST";
+ form.action = url;
+ form.enctype = "multipart/form-data"
+ form.style.display = "none";
+
+ for (var key in data) {
+ var input = document.createElement("input");
+ input.type = "hidden";
+ input.name = key;
+ input.value = data[key];
+ form.appendChild(input);
+ }
+ document.body.appendChild(form);
+ form.submit();
+ document.body.removeChild(form);
+}
+
+export async function inspect_har() {
+ let data = {
+ har: JSON.stringify(export_har()),
+
+ private_data: JSON.stringify([
+ {desc: "adid", data: adid_priv_info_table.textContent},
+ {desc: "latitude", data: lat_priv_info_table.textContent },
+ {desc: "longitude", data: lon_priv_info_table.textContent },
+ ]),
+ };
+ launch_window_with_post("/inspect_har", data);
+}
+
+function update_stats() {
+ req_res_pairs.innerText = `Request + responce pairs: ${finished_entries.length}`;
+ waiting.innerText = `Waiting for the responce: ${unfinished_entries.size}`;
+}
+
+function process_msg(s: string) {
+ let obj = JSON.parse(s);
+ console.log(obj);
+
+ if (obj.type !== "data") return;
+ if (obj.payload && obj.payload.data && obj.payload.data.requestReceived)
+ process_req(obj.payload.data.requestReceived);
+ if (obj.payload && obj.payload.data && obj.payload.data.responseCompleted)
+ process_res(obj.payload.data.responseCompleted);
+}
+
+function process_res(res: any) {
+ let entry = unfinished_entries.get(res.id)!;
+
+ let content_type = "application/text";
+ let headers = JSON.parse(res.rawHeaders).map((header: [string, string]) => {
+ if (header[0].toLowerCase() === "content-type")
+ content_type = header[1];
+ return { name: header[0], value: header[1], comment: "" };
+ });
+
+ //'{"startTime":1751745139334,
+ // "startTimestamp":347666.762487,
+ // "bodyReceivedTimestamp":347667.529477,
+ // "headersSentTimestamp":347906.038202,
+ // "responseSentTimestamp":347906.616067}'
+
+ let timing_events = JSON.parse(res.timingEvents);
+
+ let start_ts = timing_events.startTimestamp;
+ let got_headers_ts = timing_events.headersSentTimestamp;
+ let end_ts = timing_events.responseSentTimestamp;
+
+ let wait_time = got_headers_ts - start_ts;
+ let recieve_time = end_ts - got_headers_ts;
+
+ let response: Response = {
+ status: res.statusCode,
+ statusText: res.statusMessage,
+ httpVersion: entry.request.httpVersion,
+ cookies: [],
+ headers,
+ content: {
+ size: 0,
+ mimeType: content_type,
+ text: res.body,
+ encoding: "base64",
+ },
+ redirectURL: "",
+ headersSize: -1,
+ bodySize: -1,
+ };
+
+ entry.response = response;
+ entry.timings.wait = wait_time;
+ entry.timings.receive = recieve_time;
+ unfinished_entries.delete(res.id);
+ finished_entries.push(entry);
+
+ let el = document.createElement("span");
+ el.innerHTML = `
+ ${entry.request.url}
+ <br />`;
+ traffic_log_lines.appendChild(el);
+}
+
+function process_req(req: any) {
+ let content_type = "application/text";
+
+ let headers = JSON.parse(req.rawHeaders).map((header: [string, string]) => {
+ if (header[0].toLowerCase() === "Content-Type")
+ content_type = header[1];
+ return { name: header[0], value: header[1], comment: "" };
+ });
+
+ let timing_events = JSON.parse(req.timingEvents);
+
+ let start_time: number = timing_events.startTime!;
+
+ let start_datetime = new Date(start_time).toISOString();
+
+ let request: Request = {
+ method: req.method,
+ url: req.url,
+ httpVersion: req.httpVersion,
+ cookies: [],
+ headers,
+ queryString: [],
+ postData: req.body
+ ? ({ text: req.body, mimeType: content_type } as PostData)
+ : undefined,
+ headersSize: -1,
+ bodySize: -1,
+ comment: "",
+ };
+
+ //'{"startTime":1751745139334,"startTimestamp":347666.762487,"bodyReceivedTimestamp":347667.529477,"headersSentTimestamp":347906.038202,"responseSentTimestamp":347906.616067}'
+ let entry: Entry = {
+ startedDateTime: start_datetime,
+ time: 0,
+ request: request,
+ response: {
+ status: 0,
+ statusText: "",
+ httpVersion: "",
+ cookies: [],
+ headers: [],
+ content: {
+ size: 0,
+ mimeType: "",
+ },
+ redirectURL: "",
+ headersSize: 0,
+ bodySize: 0,
+ },
+ cache: {},
+ timings: {
+ wait: 0,
+ receive: 0,
+ },
+ };
+ unfinished_entries.set(req.id, entry);
+}
+
+function export_har(): Har {
+ let ret: Har = {
+ log: {
+ version: "1.2",
+ creator: {
+ name: "Rentgendroid",
+ version: "0.0.1",
+ },
+ entries: [...finished_entries, ...unfinished_entries.values()],
+ },
+ };
+ return ret;
+}
diff --git a/http_server/code/styles.css b/http_server/code/styles.css
new file mode 100644
index 0000000..39491a5
--- /dev/null
+++ b/http_server/code/styles.css
@@ -0,0 +1,167 @@
+main {
+ display: flex;
+}
+
+.log-section {
+ height: auto;
+ width: 400px;
+ overflow: auto;
+ display: flex;
+ flex-direction: column;
+ margin-left: 20px;
+}
+
+.screen {
+ display: inline-block;
+ cursor: pointer;
+}
+
+.screen-buttons {
+ display: flex;
+ justify-content: space-around;
+ margin-top: 5px;
+ gap: 10px;
+}
+
+.screen-buttons button {
+ font-size: 1.1rem;
+ padding: 10px 20px;
+ width: 100%;
+ cursor: pointer;
+ background-color: transparent;
+}
+
+.screen-buttons button:hover {
+ background-color: aqua;
+}
+
+#clicks-log {
+ font-family:
+ Menlo,
+ Consolas,
+ Monaco,
+ Liberation Mono,
+ Lucida Console,
+ 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-direction: column;
+ 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;
+}
+#screen {
+ user-select: none;
+}
+.tab-section {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+}
+#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;
+}
+#notifications {
+ width: 40%;
+ margin-left: 60%;
+ position: absolute;
+}
+
+.notification {
+ border-radius: 5px;
+ border-width: 2px;
+ border-style: solid;
+ padding: 5px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+}
+
+.notification_ok {
+ background-color: #66ff99;
+ border-color: #369648;
+}
+
+.notification_err {
+ background-color: #ff5c33;
+ border-color: #a23915;
+}
+
+#logs {
+ display: flex;
+ flex-direction: row;
+}
+
diff --git a/http_server/code/test.html b/http_server/code/test.html
new file mode 100644
index 0000000..499b4c0
--- /dev/null
+++ b/http_server/code/test.html
@@ -0,0 +1,15 @@
+ <script type="text/javascript">
+ function randomlinks(){
+ var myrandom=Math.round(Math.random()*3)
+ var links=new Array()
+ links[0]="https://www.DemiCardGame.com"
+ links[1]="https://www.games.xyphienllc.com"
+ links[2]="https://www.htcg.news"
+ links[3]="https://www.eTableCon.com"
+
+ window.open(links[myrandom], '_blank');
+ }
+ </script>
+ <form>
+ <input type="button" value="random link!" onClick="randomlinks()">
+ </form>
diff --git a/httptoolkit_ui/Dockerfile b/httptoolkit_ui/Dockerfile
index 5738a08..bf2f3eb 100644
--- a/httptoolkit_ui/Dockerfile
+++ b/httptoolkit_ui/Dockerfile
@@ -1,20 +1,23 @@
FROM node:20.18.1
+# Set up node
+RUN npm install -g n && n install 22.14.0 && n use 22.14.0 && hash -r
+
# 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 \
+RUN git checkout ac44f8e6e1f5f41be988a32eb89c98f57723d005 \
&& 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
diff --git a/pre_android/preconf/AdIdreader/.idea/misc.xml b/pre_android/preconf/AdIdreader/.idea/misc.xml
index 74dd639..b2c751a 100644
--- a/pre_android/preconf/AdIdreader/.idea/misc.xml
+++ b/pre_android/preconf/AdIdreader/.idea/misc.xml
@@ -1,10 +1,9 @@
-<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Oct 11, 09:15 (8 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
984085
Default Alt Text
(110 KB)
Attached To
Mode
R134 rentgen-android
Attached
Detach File
Event Timeline
Log In to Comment