Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F10361248
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/android/code/index.mjs b/android/code/index.mjs
index 11531b5..3fc1ba3 100644
--- a/android/code/index.mjs
+++ b/android/code/index.mjs
@@ -1,60 +1,64 @@
import { WebSocketServer } from "ws";
import child_process from "child_process";
import fs from "fs";
-import { send_notification } from "./notifications.mjs"
+import { send_notification } from "./notifications.mjs";
async function spawnPromise(program, args) {
return new Promise((resolve, reject) => {
let output = "";
const process = child_process.spawn(program, args);
- process.stdout.on('data', (data) => {
+ process.stdout.on("data", (data) => {
output += data;
});
- process.stderr.on('data', (data) => {
+ process.stderr.on("data", (data) => {
output += data;
});
process.on("close", (code) => {
- resolve({output, code});
+ resolve({ output, code });
});
});
}
const wss = new WebSocketServer({ port: 3000 });
//maybe check output of child processes and send errors in some way
wss.on("connection", (ws) => {
ws.on("message", async (dataBuf) => {
let data = dataBuf.toString();
if (data === "screenshot") {
await spawnPromise("bash", ["/conf/screenshot.sh"]);
ws.send(fs.readFileSync("/screenshot.png"));
} else if (data.includes("touch")) {
const dataSplit = data.split(" ");
await spawnPromise("bash", [
"/conf/touch.sh",
dataSplit[1],
dataSplit[2],
]);
} else if (data === "back") {
await spawnPromise("bash", ["/conf/back.sh"]);
} else if (data === "home") {
await spawnPromise("bash", ["/conf/home.sh"]);
} else if (data === "install") {
const res = await spawnPromise("bash", ["/conf/install.sh"]);
- send_notification(res.code === 0, "Installing the application", res.output);
+ send_notification(
+ res.code === 0,
+ "Installing the application",
+ res.output
+ );
} else if (data.includes("drag")) {
const dataSplit = data.split(" ");
await spawnPromise("bash", [
"/conf/drag.sh",
dataSplit[1],
dataSplit[2],
dataSplit[3],
dataSplit[4],
]);
}
});
ws.on("close", (_) => {
ws.close();
});
});
diff --git a/android/code/notifications.mjs b/android/code/notifications.mjs
index 200d5b2..01ce9a1 100644
--- a/android/code/notifications.mjs
+++ b/android/code/notifications.mjs
@@ -1,36 +1,41 @@
import { WebSocket } from "ws";
import { WebSocketServer } from "ws";
const notification_proxy = new WebSocketServer({ port: 3001 });
let notification_subs = [];
-notification_proxy.on('connection', (ws) => {
+notification_proxy.on("connection", (ws) => {
notification_subs.push(ws);
});
-export function send_notification(is_ok, context, message)
-{
+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");
+ 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
- }));
+ 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");
+ console.log(
+ "WARNING: Fail to send a notification, closing the connection"
+ );
}
}
}
}
diff --git a/http_server/code/index.mjs b/http_server/code/index.mjs
index 1e5dc42..26c6d4a 100644
--- a/http_server/code/index.mjs
+++ b/http_server/code/index.mjs
@@ -1,113 +1,112 @@
import express from "express";
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 fileUpload from 'express-fileupload';
+import fileUpload from "express-fileupload";
const device_size_x = 320;
const device_size_y = 640;
const app = express();
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
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("/trafficLog", async function (req, res) {
res.sendFile("/log/trafficLog");
});
app.get("/screen", async function (req, res) {
await guardedScreenshot();
res.sendFile("/code/screenshot.png");
});
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.post("/back", function (req, res) {
android_websocket.send(`back`);
res.sendStatus(200);
});
// default options
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) {
- return res.status(400).send('No files were uploaded.');
+ 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';
+ let uploadPath = "/shared_buffer/app" + idx + ".apk";
await file.mv(uploadPath);
}
} else {
- let uploadPath = '/shared_buffer/app' + 0 + '.apk';
+ let uploadPath = "/shared_buffer/app" + 0 + ".apk";
await req.files.app.mv(uploadPath);
}
android_websocket.send(`install`);
- res.send('Files uploaded!');
-})
+ res.send("Files uploaded!");
+});
app.post("/home", function (req, res) {
android_websocket.send(`home`);
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 {
android_websocket.send(`touch ${x} ${y}`);
res.sendStatus(200);
}
});
app.post("/drag", function (req, res) {
const body = req.body;
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.listen(8080, () => console.log("Listening in port 8080"));
-
diff --git a/http_server/code/screenshot.mjs b/http_server/code/screenshot.mjs
index 199d7ae..4caac92 100644
--- a/http_server/code/screenshot.mjs
+++ b/http_server/code/screenshot.mjs
@@ -1,69 +1,68 @@
import fs from "fs";
import { sleep } from "./utils.mjs";
import { WebSocket } from "ws";
export const android_websocket = new WebSocket("ws://android:3000");
let doneWrite = 0;
let screenshotPromise = null;
async function screenshot() {
const time_start = Date.now();
let retries = 0;
while (android_websocket.readyState != WebSocket.OPEN) {
await sleep(15);
retries++;
- if (retries > 50)
- {
+ if (retries > 50) {
console.error("Screenshot ws timeout");
doneWrite = 0;
screenshotPromise = null;
- return ;
+ return;
}
}
android_websocket.send("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() {
if (!screenshotPromise) {
screenshotPromise = screenshot();
} else {
console.log("ongoing screenshot promise not taking a new one");
}
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");
}
android_websocket.on("message", (dataBuf) => {
let fd;
fd = fs.openSync("/code/screenshot.png", "w");
fs.writeSync(fd, dataBuf);
fs.close(fd);
doneWrite = 1;
});
diff --git a/http_server/code/src/notifications.jsx b/http_server/code/src/notifications.jsx
index 9ba6110..741523f 100644
--- a/http_server/code/src/notifications.jsx
+++ b/http_server/code/src/notifications.jsx
@@ -1,69 +1,68 @@
import { render, Component } from "preact";
-import { useState } from "preact/hooks";
function rand_num() {
return Math.floor(Math.random() * Number.MAX_VALUE);
}
class Notifications extends Component {
constructor() {
super();
this.state = { notifications: [] };
}
- remove_notification (id) {
+ remove_notification(id) {
const newNotifications = this.state.notifications.filter(
(notification) => notification.id !== id
);
this.setState({ notifications: newNotifications });
- };
+ }
componentDidMount() {
// This should also be dynamic
this.connection = new WebSocket("ws://127.0.0.1:3001");
this.connection.onmessage = (msg) => {
let new_id = rand_num();
this.setState({
notifications: [
{ id: new_id, notification: JSON.parse(msg.data) },
...this.state.notifications,
],
});
// a 10 sec timeout
setTimeout(() => {
- this.remove_notification(new_id)
- }, 10000)
+ this.remove_notification(new_id);
+ }, 10000);
};
}
render() {
console.log("Render", this.state.notifications);
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"));
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 8, 12:14 (16 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1034567
Default Alt Text
(10 KB)
Attached To
Mode
R134 rentgen-android
Attached
Detach File
Event Timeline
Log In to Comment