This commit is contained in:
Andrii Dokhniak 2025-06-09 16:16:14 +02:00
parent c64c17d86e
commit 8d528f294a
23 changed files with 1439 additions and 376 deletions

View File

@ -1,10 +1,9 @@
import { WebSocketServer } from "ws";
import child_process from "child_process"; import child_process from "child_process";
import fs from "fs"; import fs from "fs";
import { send_notification } from "./notifications.mjs"; import { Server } from "socket.io";
async function spawnPromise(program, args) { async function spawnPromise(program, args) {
return new Promise((resolve, reject) => { return new Promise((resolve, _reject) => {
let output = ""; let output = "";
const process = child_process.spawn(program, args); const process = child_process.spawn(program, args);
process.stdout.on("data", (data) => { process.stdout.on("data", (data) => {
@ -19,58 +18,111 @@ async function spawnPromise(program, args) {
}); });
} }
const wss = new WebSocketServer({ port: 3000 }); let io = new Server();
async function send_private_data() {
let adid = fs.readFileSync("/adid").toString();
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;
//maybe check output of child processes and send errors in some way //maybe check output of child processes and send errors in some way
wss.on("connection", (ws) => { io.on("connection", (socket) => {
ws.on("message", async (dataBuf) => { socket.onAny((ev, ...args) => {
let data = dataBuf.toString(); console.log("server got: ", ev, ...args);
if (data === "screenshot") { });
await spawnPromise("bash", ["/conf/screenshot.sh"]); socket.on("screenshot", async () => {
ws.send(fs.readFileSync("/screenshot.png")); if (screenshot_in_flight)
} else if (data.includes("touch")) { return;
const dataSplit = data.split(" "); screenshot_in_flight = true;
await spawnPromise("bash", [ let screen = await fetch("http://localhost:9987/v2/uiDevice/screenshot");
"/conf/touch.sh", let body = await screen.bytes();
dataSplit[1], socket.emit("screenshot_data", body);
dataSplit[2], screenshot_in_flight = false;
]); });
} else if (data === "back") {
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 () => {
await spawnPromise("bash", ["/conf/back.sh"]); await spawnPromise("bash", ["/conf/back.sh"]);
} else if (data === "home") { });
socket.on("home", async () => {
await spawnPromise("bash", ["/conf/home.sh"]); await spawnPromise("bash", ["/conf/home.sh"]);
} else if (data === "install") { });
socket.on("install", async () => {
const res = await spawnPromise("bash", ["/conf/install.sh"]); const res = await spawnPromise("bash", ["/conf/install.sh"]);
send_notification( send_notification(
socket,
res.code === 0, res.code === 0,
"Installing the application", "Installing the application",
res.output res.output
); );
} else if (data.includes("drag")) { });
const dataSplit = data.split(" ");
// drag handles both drag and click
socket.on("motionevent", async (data) => {
await spawnPromise("bash", [
"/conf/motionevent.sh",
data.motionType,
data.x + "",
data.y + ""
]);
});
// drag handles both drag and click
socket.on("drag", async (data) => {
await spawnPromise("bash", [ await spawnPromise("bash", [
"/conf/drag.sh", "/conf/drag.sh",
dataSplit[1], data.startX + "",
dataSplit[2], data.startY + "",
dataSplit[3], data.endX + "",
dataSplit[4], data.endY + "",
data.dragTime + "",
]); ]);
} else if (data.startsWith("setcoord")) { });
const dataSplit = data.split(" ");
socket.on("key", async (data) => {
await spawnPromise("bash", [
"/conf/press_key.sh",
data.key
]);
});
socket.on("setcoord", async (data) => {
const res = await spawnPromise("bash", [ const res = await spawnPromise("bash", [
"/conf/set_geo.sh", "/conf/set_geo.sh",
dataSplit[1], data.lon + "",
dataSplit[2], data.lat + "",
]); ]);
send_notification( send_notification(
socket,
res.code === 0, res.code === 0,
"Setting the moch location", "Setting the moch location",
res.output res.output
); );
} await send_private_data();
});
ws.on("close", (_) => {
ws.close();
}); });
}); });
io.listen(3000);
console.log("listening on port 3000");

View File

@ -1,42 +0,0 @@
import { WebSocket } from "ws";
import { WebSocketServer } from "ws";
const notification_proxy = new WebSocketServer({ port: 3001 });
let notification_subs = [];
notification_proxy.on("connection", (ws) => {
notification_subs.push(ws);
});
export function send_notification(is_ok, context, message) {
let updated_subs = [];
if (notification_subs.length === 0) {
console.log("WARNING: Got a notification, but nobody is subscribed");
}
for (const sub of notification_subs) {
if (sub.readyState == WebSocket.CONNECTING) {
console.log(
"WARNING: Unable to forward a notification to client that is still connecting"
);
updated_subs.push(sub);
} else {
try {
sub.send(
JSON.stringify({
is_ok,
context,
message,
})
);
updated_subs.push(sub);
} catch {
sub.close();
console.log(
"WARNING: Fail to send a notification, closing the connection"
);
}
}
}
notification_subs = updated_subs;
}

View File

@ -5,9 +5,267 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"socket.io": "^4.8.1",
"ws": "^8.18.0" "ws": "^8.18.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/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==",
"license": "MIT",
"dependencies": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"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/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/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": "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": {
"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-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/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/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"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==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"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/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT",
"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/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/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-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/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/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/ws": { "node_modules/ws": {
"version": "8.18.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
@ -30,6 +288,170 @@
} }
}, },
"dependencies": { "dependencies": {
"@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=="
},
"@types/cors": {
"version": "2.8.18",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.18.tgz",
"integrity": "sha512-nX3d0sxJW41CqQvfOzVG1NCTXfFDrDWIghCZncpHeWlVFd81zxB/DLhg7avFg6eHLCRX7ckBmoIIcqa++upvJA==",
"requires": {
"@types/node": "*"
}
},
"@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==",
"requires": {
"undici-types": "~6.21.0"
}
},
"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==",
"requires": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
}
},
"base64id": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
},
"cookie": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="
},
"cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"requires": {
"object-assign": "^4",
"vary": "^1"
}
},
"debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"requires": {
"ms": "^2.1.3"
}
},
"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==",
"requires": {
"@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"
},
"dependencies": {
"ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"requires": {}
}
}
},
"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=="
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"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==",
"requires": {
"mime-db": "1.52.0"
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
},
"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=="
},
"socket.io": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
"requires": {
"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"
}
},
"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==",
"requires": {
"debug": "~4.3.4",
"ws": "~8.17.1"
},
"dependencies": {
"ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"requires": {}
}
}
},
"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==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
}
},
"undici-types": {
"version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
},
"ws": { "ws": {
"version": "8.18.0", "version": "8.18.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",

View File

@ -1,5 +1,6 @@
{ {
"dependencies": { "dependencies": {
"socket.io": "^4.8.1",
"ws": "^8.18.0" "ws": "^8.18.0"
} }
} }

View File

@ -1 +1 @@
/opt/android-sdk-linux/platform-tools/adb shell input swipe $1 $2 $3 $4 1000 /opt/android-sdk-linux/platform-tools/adb shell input swipe $1 $2 $3 $4 $5

View File

@ -0,0 +1,2 @@
#!/bin/bash
adb shell dumpsys location | grep 'last location=' | head -n 1 | awk -F' ' '{ print $3 }'

View File

@ -0,0 +1 @@
/opt/android-sdk-linux/platform-tools/adb shell input motionevent $1 $2 $3

View File

@ -0,0 +1,9 @@
#!/bin/bash
# https://stackoverflow.com/questions/7789826/adb-shell-input-events
if [ "$1" = "Enter" ]; then
/opt/android-sdk-linux/platform-tools/adb shell input keyevent 66
elif [ "$1" = "Backspace" ]; then
/opt/android-sdk-linux/platform-tools/adb shell input keyevent 67
else
/opt/android-sdk-linux/platform-tools/adb shell input text "'$1'"
fi

View File

@ -0,0 +1,13 @@
#!/bin/bash
set -xe
# Change the file slightly
echo | adb shell su root "tee /data/data/com.google.android.gms/shared_prefs/adid_settings.xml"
# Ask android for the ADID. Android detects the changed file (somewhere), and regenerates it
adb shell su root am start -W -n com.example.adidreader/com.example.adidreader.MainActivity
sleep 0.1
# Get the new ADID
adb shell su root cat /data/data/com.google.android.gms/shared_prefs/adid_settings.xml | xmllint --xpath 'string(//map/string[@name="adid_key"])' - > /adid

View File

@ -1 +0,0 @@
curl http://localhost:9987/v2/uiDevice/screenshot -o /screenshot.png

View File

@ -3,9 +3,17 @@ ko=$((
echo "auth $(cat ~/.emulator_console_auth_token)" echo "auth $(cat ~/.emulator_console_auth_token)"
echo "geo fix $1 $2 0.0" echo "geo fix $1 $2 0.0"
sleep 0.2 sleep 0.2
) | telnet localhost 5554 | grep KO: ); ) | telnet localhost 5554 2> /dev/null | grep KO: );
if [ -z "${ko}" ]; then if [ -z "${ko}" ]; then
# Check if the location was actually set, for some reason the location moching doesn't work,
# unless google maps is launched first, and is given access to the phone location
adb shell dumpsys location | grep 'last location=Location\[gps' > /dev/null
if [ $? -ne 0 ]; then
echo Failed to actually set the location, probably need to launch google maps first
exit 1
fi
echo Succesfully set the coordinates to: $(. /conf/get_location.sh)
exit 0 exit 0
else else
echo "$ko" echo "$ko"

View File

@ -1,3 +1,4 @@
set -xe
rm -f /opt/android-sdk-linux/.android/avd/virtual_dev.avd/*.lock rm -f /opt/android-sdk-linux/.android/avd/virtual_dev.avd/*.lock
adb start-server adb start-server
cat > /simple.gpx << EOF cat > /simple.gpx << EOF
@ -9,8 +10,11 @@ cat > /simple.gpx << EOF
</gpx> </gpx>
EOF EOF
emulator -grpc 5556 -avd virtual_dev -snapshot configured -no-window -no-audio -debug all,-adb,-gles1emu,-gles,-mtport,-metrics,-memory,-car,-tvremote & emulator -avd virtual_dev -writable-system -no-window -no-audio &
adb wait-for-device adb wait-for-device
adb emu avd snapshot load configured
# emulator -grpc 5556 -avd virtual_dev -snapshot configured -no-window -no-audio -no-metrics -debug-no > /dev/null &
# adb wait-for-device
export PATH=$PATH:/root/culebraDependencies export PATH=$PATH:/root/culebraDependencies
cd /root/culebra cd /root/culebra

View File

@ -6,6 +6,6 @@ WORKDIR /code
RUN mkdir /images RUN mkdir /images
ENV screenshotDelayMs 500 ENV screenshotDelayMs 100
CMD sh /code/docker-entrypoint.sh CMD sh /code/docker-entrypoint.sh

View File

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

View File

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head style="height: 100vh"> <head style="height: 100vh">
<meta charset="UTF-8" /> <meta charset="UTF-8" />
@ -43,7 +43,12 @@
} }
#clicks-log { #clicks-log {
font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, font-family:
Menlo,
Consolas,
Monaco,
Liberation Mono,
Lucida Console,
monospace; monospace;
} }
@ -74,6 +79,7 @@
} }
.tabcontent.active { .tabcontent.active {
display: flex; display: flex;
flex-direction: column;
flex-grow: 1; flex-grow: 1;
} }
@ -85,14 +91,15 @@
border-top: none; border-top: none;
} }
html, html,
body, main{ body,
main {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
margin: 0; margin: 0;
} }
main { main {
display:flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: stretch; align-items: stretch;
} }
@ -104,28 +111,35 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.screen-section #screen, .screen-section.screen_buttons { .screen-section #screen,
.screen-section.screen_buttons {
flex-grow: 0; flex-grow: 0;
} }
.tab-section { #screen {
display: flex; flex-direction: column; flex-grow: 1; user-select: none;
}
.tab-section {
display: flex;
flex-direction: column;
flex-grow: 1;
} }
<!-- TODO: A notification system -->
#resp { #resp {
display: none; display: none;
} }
#upload_form { #upload_form {
display:flex; display: flex;
flex-direction: column; flex-direction: column;
} }
#upload_form button, #upload_form label { #upload_form button,
#upload_form label {
border: 2px solid #ccc; border: 2px solid #ccc;
background-color: #f1f1f1; background-color: #f1f1f1;
cursor: pointer; cursor: pointer;
padding: 3px 10px; padding: 3px 10px;
transition: 0.3s; transition: 0.3s;
} }
#upload_form button:hover, #upload_form label:hover { #upload_form button:hover,
#upload_form label:hover {
background-color: #ddd; background-color: #ddd;
} }
#notifications { #notifications {
@ -137,9 +151,9 @@
</head> </head>
<body> <body>
<div id="notifications"></div> <div id="notifications"></div>
<div id="resp" style="display: none;"></div> <div id="resp" style="display: none"></div>
<main> <main>
<section class="screen-section" > <section class="screen-section">
<img <img
id="screen" id="screen"
alt="android screen" alt="android screen"
@ -147,42 +161,113 @@
draggable="false" draggable="false"
class="screen" class="screen"
style="flex-grow: 0" style="flex-grow: 0"
tabindex="0"
/> />
<div class="screen-buttons" style="flex-grow: 0"> <div class="screen-buttons" style="flex-grow: 0">
<button class="screen-buttons-home">home</button> <button class="screen-buttons-home">home</button>
<button class="screen-buttons-back">back</button> <button class="screen-buttons-back">back</button>
</div> </div>
<form id="upload_form" hx-post="/upload_apk" enctype="multipart/form-data" hx-target="#resp"> <form
<label id="upload_input" for="app">Select file id="upload_form"
<input type="file" id="app" name="app" accept=".apk" required multiple/> 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> </label>
<button type="submit">Install the app</button> <button type="submit">Install the app</button>
</form> </form>
</section> </section>
<div class="tab-section" > <div class="tab-section">
<form id="set_coords" hx-post="/setcoord" hx-target="#resp">
<input type="text" name="lon"/>
<input type="text" name="lat"/>
<button type="submit">Submit coords</button>
</form>
<div class="tab"> <div class="tab">
<button class="tablinks active" onclick="open_tab(event, 'httptoolkit-tab')">HttpToolkit UI</button> <button
<button class="tablinks" onclick="open_tab(event, 'logs-tab')">Logs</button> class="tablinks active"
onclick="open_tab(event, 'httptoolkit-tab')"
>
HttpToolkit UI
</button>
<button class="tablinks" onclick="open_tab(event, 'logs-tab')">
Logs
</button>
<button class="tablinks" onclick="open_tab(event, 'controls-tab')">
Device Controls
</button>
</div> </div>
<div class="tabcontent" id="logs-tab"> <div class="tabcontent" id="logs-tab">
<p id="clicks-log" class="log-section" ></p> <p id="clicks-log" class="log-section"></p>
<p id="traffic-log" class="log-section"></p> <p id="traffic-log" class="log-section"></p>
</div> </div>
<div class="tabcontent active" id="httptoolkit-tab"> <div class="tabcontent active" id="httptoolkit-tab">
<iframe id="httptoolkit-frame" style="flex-grow: 1;" src="http://localhost:9080/" title="httptoolkit"></iframe> <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)">
<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>
</div> </div>
</div> </div>
</main> </main>
<script src="/socket.io.js"></script>
<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) { function open_tab(evt, tab_name) {
let i, tabcontent, tablinks; let i, tabcontent, tablinks;
@ -199,14 +284,12 @@
// Get all elements with class="tablinks" and remove the class "active" // Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks"); tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) { for (i = 0; i < tablinks.length; i++) {
tablinks[i].classList.remove("active") tablinks[i].classList.remove("active");
} }
// Show the current tab, and add an "active" class to the button that opened the tab // Show the current tab, and add an "active" class to the button that opened the tab
evt.currentTarget.classList.add("active"); evt.currentTarget.classList.add("active");
} }
</script>
<script>
var screen = document.getElementById("screen"); var screen = document.getElementById("screen");
var clicksLog = document.getElementById("clicks-log"); var clicksLog = document.getElementById("clicks-log");
const homeButton = document.querySelector(".screen-buttons-home"); const homeButton = document.querySelector(".screen-buttons-home");
@ -238,14 +321,7 @@
const span = document.createElement("span"); const span = document.createElement("span");
waitToLog(logText); waitToLog(logText);
socket.emit(path, body ? body : {});
fetch(path, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
...(body ? { body } : {}),
});
}; };
homeButton.addEventListener("click", () => homeButton.addEventListener("click", () =>
@ -256,57 +332,118 @@
registerClick({ path: "back", logText: "await backButton();" }) registerClick({ path: "back", logText: "await backButton();" })
); );
async function displayImage() { socket.on("screenshot_data", (data) => {
try { try {
const response = await fetch("screen"); const blob = new Blob([data]);
const blob = await response.blob();
screen.src = URL.createObjectURL(blob); screen.src = URL.createObjectURL(blob);
} catch (error) { } catch (error) {
console.error("Error fetching image: ", 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; let isDragging = false;
let startDraggingPosX = 0;
let endDraggingPosX = 0;
let startDraggingPosY = 0;
let endDraggingPosY = 0;
const screenSize = [320, 640]; const screenSize = [320, 640];
const handleDraggStart = (e) => { function calcMousePos(event) {
e.preventDefault(); 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; isDragging = true;
startDraggingPosX = e.offsetX; let pos = calcMousePos(event);
startDraggingPosY = e.offsetY; 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); screen.addEventListener("mousedown", handleDraggStart);
document.addEventListener("mouseup", (e) => { document.addEventListener("mouseup", (e) => {
endDraggingPosX = e.offsetX; if (!isDragging) return;
endDraggingPosY = e.offsetY; isDragging = false;
if ( let pos = calcMousePos(e);
isDragging &&
(Math.abs(endDraggingPosY - startDraggingPosY) > 10 ||
Math.abs(endDraggingPosX - startDraggingPosX) > 10)
) {
registerClick({ registerClick({
path: "drag", path: "motionevent",
logText: `await drag({x:${startDraggingPosX},y:${startDraggingPosY}},{x:${e.offsetX},y:${e.offsetY}});`, logText: `await motionevent({motionType: "MOVE", x:${pos.x},y:${pos.y}}});`,
body: `startX=${startDraggingPosX}&startY=${startDraggingPosY}&endX=${e.offsetX}&endY=${e.offsetY}`, body: {
motionType: "MOVE",
x: pos.x,
y: pos.y,
},
}); });
} else if (e.target === screen) {
const phoneX = event.offsetX;
const phoneY = event.offsetY;
if (phoneX <= screenSize[0] && phoneY <= screenSize[1])
registerClick({ registerClick({
path: "touch", path: "motionevent",
logText: `await click(${phoneX}, ${phoneY});`, logText: `await motionevent({motionType: "UP", x:${pos.x},y:${pos.y}}});`,
body: `x=${phoneX}&y=${phoneY}`, 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 },
}); });
} }
isDragging = false;
}); });
async function sleep(time) { async function sleep(time) {
@ -323,7 +460,6 @@
await sleep(50); await sleep(50);
} }
} }
screenshot_loop(); screenshot_loop();
</script> </script>
<script src="/trafficLog.js"></script> <script src="/trafficLog.js"></script>

View File

@ -1,27 +1,34 @@
import express from "express"; import express from "express";
import { readFile } from "node:fs/promises"; import { readFile } from "node:fs/promises";
import {
guardedScreenshot,
android_websocket,
waitFullBoot,
} from "./screenshot.mjs";
import { execSync } from "node:child_process"; import { execSync } from "node:child_process";
import { Server } from "socket.io";
import { io } from "socket.io-client";
import fileUpload from "express-fileupload"; import fileUpload from "express-fileupload";
const device_size_x = 320;
const device_size_y = 640;
const app = express(); const app = express();
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.urlencoded({ extended: false }));
app.use(express.static("/code/dist")); app.use(express.static("/code/dist"));
console.log("Waiting for full boot...");
await waitFullBoot();
console.log("Boot detected! activating endpoints");
//GET //GET
app.get("/favicon.ico", function (req, res) { app.get("/favicon.ico", function (req, res) {
res.sendFile("/code/favicon.ico"); res.sendFile("/code/favicon.ico");
@ -31,13 +38,8 @@ app.get("/htmx.js", function (req, res) {
res.sendFile("/code/node_modules/htmx.org/dist/htmx.min.js"); res.sendFile("/code/node_modules/htmx.org/dist/htmx.min.js");
}); });
app.get("/trafficLog", async function (req, res) { app.get("/socket.io.js", function (_req, res) {
res.sendFile("/log/trafficLog"); res.sendFile("/code/node_modules/socket.io/client-dist/socket.io.js");
});
app.get("/screen", async function (req, res) {
await guardedScreenshot();
res.sendFile("/code/screenshot.png");
}); });
app.get("/", async function (req, res) { app.get("/", async function (req, res) {
@ -55,12 +57,6 @@ app.get("/", async function (req, res) {
}); });
//POST //POST
app.post("/back", function (req, res) {
android_websocket.send(`back`);
res.sendStatus(200);
});
// default options
app.use(fileUpload()); app.use(fileUpload());
app.post("/upload_apk", async function (req, res) { app.post("/upload_apk", async function (req, res) {
if (!req.files || Object.keys(req.files).length === 0) { if (!req.files || Object.keys(req.files).length === 0) {
@ -76,48 +72,25 @@ app.post("/upload_apk", async function (req, res) {
let uploadPath = "/shared_buffer/app" + 0 + ".apk"; let uploadPath = "/shared_buffer/app" + 0 + ".apk";
await req.files.app.mv(uploadPath); await req.files.app.mv(uploadPath);
} }
android_websocket.send(`install`); back.emit("install");
res.send("Files uploaded!"); res.send("Files uploaded!");
}); });
app.post("/home", function (req, res) { let server = app.listen(8080, () => console.log("Listening in port 8080"));
android_websocket.send(`home`);
res.sendStatus(200);
});
app.post("/touch", function (req, res) { const front = new Server(server);
const x = parseInt(req.body.x);
const y = parseInt(req.body.y);
if (isNaN(x) || isNaN(y) || x > device_size_x || y > device_size_y) { // forwarding the messages
res.send( front.on("connection", (socket) => {
`the query params must be x <= ${device_size_x}, y <= ${device_size_y}\n` socket.onAny((event, ...args) => {
); if (back.connected) {
back.emit(event, ...args);
} else { } else {
android_websocket.send(`touch ${x} ${y}`); console.log("Front tried to send: ", event, ...args);
res.sendStatus(200);
} }
});
}); });
app.post("/drag", function (req, res) { back.onAny((event, ...args) => {
const body = req.body; front.emit(event, ...args);
const startX = Number(body.startX);
const startY = Number(body.startY);
const endX = Number(body.endX);
const endY = Number(body.endY);
android_websocket.send(`drag ${startX} ${startY} ${endX} ${endY}`);
res.sendStatus(200);
}); });
app.post("/setcoord", function (req, res) {
console.log(req.body);
console.log(req.body.lat);
console.log(req.body.lon);
const lat = Number(req.body.lat);
const lon = Number(req.body.lon);
console.log(lat, lon);
android_websocket.send(`setcoord ${lat} ${lon}`);
res.sendStatus(200);
});
app.listen(8080, () => console.log("Listening in port 8080"));

View File

@ -9,6 +9,8 @@
"express-fileupload": "^1.5.1", "express-fileupload": "^1.5.1",
"htmx.org": "^1.9.12", "htmx.org": "^1.9.12",
"preact": "^10.18.1", "preact": "^10.18.1",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
"devDependencies": { "devDependencies": {
@ -367,6 +369,30 @@
"node": ">=12" "node": ">=12"
} }
}, },
"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/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": { "node_modules/accepts": {
"version": "1.3.8", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@ -384,6 +410,15 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
}, },
"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": { "node_modules/body-parser": {
"version": "1.20.1", "version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
@ -470,6 +505,19 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" "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": { "node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -508,6 +556,145 @@
"node": ">= 0.8" "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": { "node_modules/esbuild": {
"version": "0.19.5", "version": "0.19.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.5.tgz",
@ -805,6 +992,15 @@
"node": ">= 0.6" "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": { "node_modules/object-inspect": {
"version": "1.12.3", "version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
@ -978,6 +1174,175 @@
"url": "https://github.com/sponsors/ljharb" "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": { "node_modules/statuses": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
@ -1014,6 +1379,12 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"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": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -1057,6 +1428,14 @@
"optional": true "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"
}
} }
} }
} }

View File

@ -7,6 +7,8 @@
"express-fileupload": "^1.5.1", "express-fileupload": "^1.5.1",
"htmx.org": "^1.9.12", "htmx.org": "^1.9.12",
"preact": "^10.18.1", "preact": "^10.18.1",
"socket.io": "^4.8.1",
"socket.io-client": "^4.8.1",
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,4 +1,5 @@
import { render, Component } from "preact"; import { render, Component } from "preact";
import { io } from "socket.io-client";
function rand_num() { function rand_num() {
return Math.floor(Math.random() * Number.MAX_VALUE); return Math.floor(Math.random() * Number.MAX_VALUE);
@ -19,13 +20,12 @@ class Notifications extends Component {
componentDidMount() { componentDidMount() {
// This should also be dynamic // This should also be dynamic
this.connection = new WebSocket("ws://127.0.0.1:3001");
this.connection.onmessage = (msg) => { io().on("notification", (data) => {
let new_id = rand_num(); let new_id = rand_num();
this.setState({ this.setState({
notifications: [ notifications: [
{ id: new_id, notification: JSON.parse(msg.data) }, { id: new_id, notification: data },
...this.state.notifications, ...this.state.notifications,
], ],
}); });
@ -33,7 +33,7 @@ class Notifications extends Component {
setTimeout(() => { setTimeout(() => {
this.remove_notification(new_id); this.remove_notification(new_id);
}, 10000); }, 10000);
}; });
} }
render() { render() {

View File

@ -1,16 +0,0 @@
import { exit } from "process";
import { WebSocket } from "ws";
async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
while (true) {
let socket = new WebSocket("ws://android:3000");
socket.on("open", () => {
exit(0);
});
socket.on("error", () => {});
await sleep(200);
}

120
package-lock.json generated
View File

@ -6,6 +6,9 @@
"": { "": {
"dependencies": { "dependencies": {
"zx": "^7.2.2" "zx": "^7.2.2"
},
"devDependencies": {
"socket.io-client": "^4.8.1"
} }
}, },
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
@ -43,6 +46,13 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"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==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/fs-extra": { "node_modules/@types/fs-extra": {
"version": "11.0.4", "version": "11.0.4",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz",
@ -122,6 +132,24 @@
"node": ">= 12" "node": ">= 12"
} }
}, },
"node_modules/debug": {
"version": "4.3.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/dir-glob": { "node_modules/dir-glob": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -140,6 +168,30 @@
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"license": "MIT" "license": "MIT"
}, },
"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==",
"dev": true,
"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-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/event-stream": { "node_modules/event-stream": {
"version": "3.3.4", "version": "3.3.4",
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz",
@ -386,6 +438,13 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"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==",
"dev": true,
"license": "MIT"
},
"node_modules/node-domexception": { "node_modules/node-domexception": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@ -536,6 +595,36 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"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==",
"dev": true,
"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-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==",
"dev": true,
"license": "MIT",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/split": { "node_modules/split": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
@ -623,6 +712,37 @@
"node": "^14.17.0 || ^16.13.0 || >=18.0.0" "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
} }
}, },
"node_modules/ws": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
"dev": true,
"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/xmlhttprequest-ssl": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/yaml": { "node_modules/yaml": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz",

View File

@ -3,8 +3,10 @@
"start": "zx start.mjs up", "start": "zx start.mjs up",
"stop": "zx start.mjs down" "stop": "zx start.mjs down"
}, },
"dependencies": { "dependencies": {
"zx": "^7.2.2" "zx": "^7.2.2"
},
"devDependencies": {
"socket.io-client": "^4.8.1"
} }
} }

View File

@ -2,8 +2,8 @@ FROM runmymind/docker-android-sdk:ubuntu-standalone-20230511
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/android-sdk-linux/cmdline-tools/latest/bin:/opt/android-sdk-linux/cmdline-tools/tools/bin:/opt/android-sdk-linux/tools/bin:/opt/android-sdk-linux/build-tools/32.0.0:/opt/android-sdk-linux/platform-tools:/opt/android-sdk-linux/emulator:/opt/android-sdk-linux/bin ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/android-sdk-linux/cmdline-tools/latest/bin:/opt/android-sdk-linux/cmdline-tools/tools/bin:/opt/android-sdk-linux/tools/bin:/opt/android-sdk-linux/build-tools/32.0.0:/opt/android-sdk-linux/platform-tools:/opt/android-sdk-linux/emulator:/opt/android-sdk-linux/bin
RUN sdkmanager --channel=2 "system-images;android-30;google_apis;x86_64" \ RUN sdkmanager --channel=2 "system-images;android-35;google_apis;x86_64" \
&& echo no | avdmanager create avd -n virtual_dev -b google_apis/x86_64 -k "system-images;android-30;google_apis;x86_64" \ && echo no | avdmanager create avd -n virtual_dev -b google_apis/x86_64 -k "system-images;android-35;google_apis;x86_64" \
&& apt-get update && apt-get install -y iproute2 iputils-ping npm git libxml2-utils telnet && apt-get update && apt-get install -y iproute2 iputils-ping npm git libxml2-utils telnet
CMD bash /preconf/docker-entrypoint.sh CMD bash /preconf/docker-entrypoint.sh