fixed mutiple issues, specified socket protocol and cleaned code

Summary:
Issues fixed:

- ipv6 in pre_android container
- frontend was detecting drags when clicking out of screen
- frontend was registering clicks when clicking out of screen

Reviewers: #testers, kuba-orlik

Reviewed By: #testers, kuba-orlik

Maniphest Tasks: T2976

Differential Revision: https://hub.sealcode.org/D1568
This commit is contained in:
migueldar 2025-01-19 14:18:13 +01:00
parent 0a6e04c5ba
commit 40cb7397b0
6 changed files with 121 additions and 103 deletions

View File

@ -131,6 +131,8 @@
let startDraggingPosY = 0; let startDraggingPosY = 0;
let endDraggingPosY = 0; let endDraggingPosY = 0;
const screenSize = [320, 640]
const handleDraggStart = (e) => { const handleDraggStart = (e) => {
e.preventDefault(); e.preventDefault();
isDragging = true; isDragging = true;
@ -144,24 +146,25 @@
endDraggingPosX = e.offsetX; endDraggingPosX = e.offsetX;
endDraggingPosY = e.offsetY; endDraggingPosY = e.offsetY;
if ( if (
(isDragging && Math.abs(endDraggingPosY - startDraggingPosY) > 10) || isDragging && (Math.abs(endDraggingPosY - startDraggingPosY) > 10 ||
Math.abs(endDraggingPosX - startDraggingPosX) > 10 Math.abs(endDraggingPosX - startDraggingPosX) > 10)
) { ) {
registerClick({ registerClick({
path: "drag", path: "drag",
logText: `await drag({x:${startDraggingPosX},y:${startDraggingPosY}},{x:${e.offsetX},y:${e.offsetY}});`, logText: `await drag({x:${startDraggingPosX},y:${startDraggingPosY}},{x:${e.offsetX},y:${e.offsetY}});`,
body: `startX=${startDraggingPosX}&startY=${startDraggingPosY}&endX=${e.offsetX}&endY=${e.offsetY}`, body: `startX=${startDraggingPosX}&startY=${startDraggingPosY}&endX=${e.offsetX}&endY=${e.offsetY}`,
}); });
isDragging = false;
} else { } else {
const phoneX = event.offsetX; const phoneX = event.offsetX;
const phoneY = event.offsetY; const phoneY = event.offsetY;
if (phoneX <= screenSize[0] && phoneY <= screenSize[1])
registerClick({ registerClick({
path: "touch", path: "touch",
logText: `await click(${phoneX}, ${phoneY});`, logText: `await click(${phoneX}, ${phoneY});`,
body: `x=${phoneX}&y=${phoneY}`, body: `x=${phoneX}&y=${phoneY}`,
}); });
} }
isDragging = false;
}); });
async function sleep(time) { async function sleep(time) {

View File

@ -1,85 +1,18 @@
import express from "express"; import express from "express";
import net from "net";
import fs from "fs";
import { readFile } from "node:fs/promises"; import { readFile } from "node:fs/promises";
import { guardedScreenshot, socket_client, waitFullBoot } from "./screenshot.mjs";
const device_size_x = 320; const device_size_x = 320;
const device_size_y = 640; const device_size_y = 640;
const app = express(); const app = express();
app.use(express.urlencoded({ extended: false })); app.use(express.urlencoded({ extended: false }));
const socket_client = net.createConnection({ port: 3000, host: "android" });
async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
let doneWrite = 0;
let screenshotPromise = null;
async function screenshot() {
const time_start = Date.now();
socket_client.write("screenshot");
while (!doneWrite) {
await sleep(15);
if (Date.now() - time_start > 2000) {
console.error("Screenshot timed out after 2s");
break; // timeout
}
}
doneWrite = 0;
screenshotPromise = null;
}
async function guardedScreenshot() {
console.log("Requesting a screenshot");
if (!screenshotPromise) {
console.log("no ongoing promise, starting a new one");
screenshotPromise = screenshot();
}
return screenshotPromise;
}
async function waitFullBoot() {
var start = performance.now();
var counter = 0;
//will timeout after 10 min
while (performance.now() - start < 600 * 1000) {
var before = performance.now();
await screenshot();
var after = performance.now();
if (after - before < process.env.screenshotDelayMs) counter++;
else counter = 0;
if (counter === 10) return;
}
throw new Error("wait for screenshot time to be less than 0.5s timed out");
}
let fd;
socket_client.on("data", (dataBuf) => {
if (dataBuf.toString() === "start")
fd = fs.openSync("/code/screenshot.png", "w");
else {
if (dataBuf.toString().includes("ENDOFMSG")) {
fs.writeSync(fd, dataBuf);
fs.close(fd);
doneWrite = 1;
} else fs.writeSync(fd, dataBuf);
}
});
console.log("Waiting for full boot..."); console.log("Waiting for full boot...");
await waitFullBoot(); await waitFullBoot();
console.log("Boot detected! activating endpoints"); console.log("Boot detected! activating endpoints");
app.get("/screen", async function (req, res) { //GET
await guardedScreenshot();
res.sendFile("/code/screenshot.png");
});
app.get("/favicon.ico", function (req, res) { app.get("/favicon.ico", function (req, res) {
res.sendFile("/code/favicon.ico"); res.sendFile("/code/favicon.ico");
}); });
@ -92,18 +25,9 @@ app.get("/trafficLog", async function (req, res) {
res.sendFile("/log/trafficLog"); res.sendFile("/log/trafficLog");
}); });
app.post("/touch", function (req, res) { app.get("/screen", async function (req, res) {
const x = parseInt(req.body.x); await guardedScreenshot();
const y = parseInt(req.body.y); res.sendFile("/code/screenshot.png");
if (isNaN(x) || isNaN(y) || x > device_size_x || y > device_size_y) {
res.send(
`the query params must be x <= ${device_size_x}, y <= ${device_size_y}\n`
);
} else {
socket_client.write(`touch ${x} ${y}`);
res.sendStatus(200);
}
}); });
app.get("/", async function (req, res) { app.get("/", async function (req, res) {
@ -120,6 +44,7 @@ app.get("/", async function (req, res) {
res.send(fileData); res.send(fileData);
}); });
//POST
app.post("/back", function (req, res) { app.post("/back", function (req, res) {
socket_client.write(`back`); socket_client.write(`back`);
res.sendStatus(200); res.sendStatus(200);
@ -130,6 +55,20 @@ app.post("/home", function (req, res) {
res.sendStatus(200); res.sendStatus(200);
}); });
app.post("/touch", function (req, res) {
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) {
res.send(
`the query params must be x <= ${device_size_x}, y <= ${device_size_y}\n`
);
} else {
socket_client.write(`touch ${x} ${y}`);
res.sendStatus(200);
}
});
app.post("/drag", function (req, res) { app.post("/drag", function (req, res) {
const body = req.body; const body = req.body;
const startX = Number(body.startX); const startX = Number(body.startX);

View File

@ -0,0 +1,62 @@
import net from "net";
import fs from "fs";
import { sleep } from "./utils.mjs";
export const socket_client = net.createConnection({ port: 3000, host: "android" });
let doneWrite = 0;
let screenshotPromise = null;
async function screenshot() {
const time_start = Date.now();
socket_client.write("screenshot");
while (!doneWrite) {
await sleep(15);
if (Date.now() - time_start > 2000) {
console.error("Screenshot timed out after 2s");
break; // timeout
}
}
doneWrite = 0;
screenshotPromise = null;
}
export async function guardedScreenshot() {
console.log("Requesting a screenshot");
if (!screenshotPromise) {
console.log("no ongoing promise, starting a new one");
screenshotPromise = screenshot();
}
return screenshotPromise;
}
export async function waitFullBoot() {
var start = performance.now();
var counter = 0;
//will timeout after 10 min
while (performance.now() - start < 600 * 1000) {
var before = performance.now();
await screenshot();
var after = performance.now();
if (after - before < process.env.screenshotDelayMs) counter++;
else counter = 0;
if (counter === 10) return;
}
throw new Error("wait for screenshot time to be less than 0.5s timed out");
}
let fd;
socket_client.on("data", (dataBuf) => {
if (dataBuf.toString() === "start")
fd = fs.openSync("/code/screenshot.png", "w");
else {
if (dataBuf.toString().includes("ENDOFMSG")) {
fs.writeSync(fd, dataBuf);
fs.close(fd);
doneWrite = 1;
} else fs.writeSync(fd, dataBuf);
}
});

View File

@ -0,0 +1,3 @@
export async function sleep(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}

11
intraContainerCom.txt Normal file
View File

@ -0,0 +1,11 @@
INTRA CONTAINER COMMUNICATION
FROM HTTPSERVER TO ANDROID
- screenshot
- home
- back
- touch $x $y
- drag $startx $starty $endx $endy
FROM ANDROID TO HTTPSERVER
- start $screenshotdata ENDOFMSG (to send screenshot data)

View File

@ -43,7 +43,7 @@ async function generateCert() {
async function generatePreAndroid() { async function generatePreAndroid() {
await $`docker build -t pre_android pre_android`; await $`docker build -t pre_android pre_android`;
$`docker run --rm -v $PWD/certificates/mitmproxy-ca-cert.cer:/ca-cert.cer -v $PWD/pre_android/preconf:/preconf --device=/dev/kvm --name pre_android_cont pre_android &`; $`docker run --sysctl net.ipv6.conf.all.disable_ipv6=1 --rm -v $PWD/certificates/mitmproxy-ca-cert.cer:/ca-cert.cer -v $PWD/pre_android/preconf:/preconf --device=/dev/kvm --name pre_android_cont pre_android &`;
console.log( console.log(
"Installing tls certificate and culebra into the android pre-image..." "Installing tls certificate and culebra into the android pre-image..."
@ -90,5 +90,5 @@ else if (process.argv[3] === "generateCert") {
generatePreAndroid(); generatePreAndroid();
} else } else
throw new Error( throw new Error(
"expected [up | down | generateCert | generatePreAndroid ] as argument" "expected [ up | down | generateCert | generatePreAndroid ] as argument"
); );