Summary: switch to httptoolkit Reviewers: kuba-orlik Reviewed By: kuba-orlik Differential Revision: https://hub.sealcode.org/D1578
321 lines
8.5 KiB
HTML
321 lines
8.5 KiB
HTML
<!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-grow: 1;
|
|
}
|
|
|
|
/* Style the tab content */
|
|
.tabcontent {
|
|
display: none;
|
|
padding: 6px 12px;
|
|
border: 1px solid #ccc;
|
|
border-top: none;
|
|
}
|
|
html,
|
|
body, main{
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
margin: 0;
|
|
}
|
|
main {
|
|
display:flex;
|
|
flex-direction: row;
|
|
align-items: stretch;
|
|
}
|
|
#logs-tab {
|
|
overflow: auto;
|
|
text-wrap: wrap;
|
|
}
|
|
.screen-section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.screen-section #screen, .screen-section.screen_buttons {
|
|
flex-grow: 0;
|
|
}
|
|
.tab-section {
|
|
display: flex; flex-direction: column; flex-grow: 1;
|
|
}
|
|
<!-- TODO: A notification system -->
|
|
#resp {
|
|
display: none;
|
|
}
|
|
#upload_form {
|
|
display:flex;
|
|
flex-direction: column;
|
|
}
|
|
#upload_form button, #upload_form label {
|
|
border: 2px solid #ccc;
|
|
background-color: #f1f1f1;
|
|
cursor: pointer;
|
|
padding: 3px 10px;
|
|
transition: 0.3s;
|
|
}
|
|
#upload_form button:hover, #upload_form label:hover {
|
|
background-color: #ddd;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="resp"></div>
|
|
<main>
|
|
<section class="screen-section" >
|
|
<img
|
|
id="screen"
|
|
alt="android screen"
|
|
src=""
|
|
draggable="false"
|
|
class="screen"
|
|
style="flex-grow: 0"
|
|
/>
|
|
<div class="screen-buttons" style="flex-grow: 0">
|
|
<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/>
|
|
</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')">HttpToolkit UI</button>
|
|
<button class="tablinks" onclick="open_tab(event, 'logs-tab')">Logs</button>
|
|
</div>
|
|
|
|
<div class="tabcontent" id="logs-tab">
|
|
<p id="clicks-log" class="log-section" ></p>
|
|
<p id="traffic-log" class="log-section"></p>
|
|
</div>
|
|
|
|
<div class="tabcontent active" id="httptoolkit-tab">
|
|
<iframe id="httptoolkit-frame" style="flex-grow: 1;" src="http://localhost:9080/" title="httptoolkit"></iframe>
|
|
</div>
|
|
</div>
|
|
|
|
</main>
|
|
<script>
|
|
function open_tab(evt, tab_name) {
|
|
let i, tabcontent, tablinks;
|
|
|
|
// Get all elements with class="tabcontent" and hide them
|
|
tabcontent = document.getElementsByClassName("tabcontent");
|
|
for (i = 0; i < tabcontent.length; i++) {
|
|
if (tabcontent[i].id != tab_name) {
|
|
tabcontent[i].classList.remove("active");
|
|
} else {
|
|
tabcontent[i].classList.add("active");
|
|
}
|
|
}
|
|
|
|
// Get all elements with class="tablinks" and remove the class "active"
|
|
tablinks = document.getElementsByClassName("tablinks");
|
|
for (i = 0; i < tablinks.length; i++) {
|
|
tablinks[i].classList.remove("active")
|
|
}
|
|
|
|
// Show the current tab, and add an "active" class to the button that opened the tab
|
|
evt.currentTarget.classList.add("active");
|
|
}
|
|
</script>
|
|
<script>
|
|
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);
|
|
|
|
fetch(path, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
...(body ? { body } : {}),
|
|
});
|
|
};
|
|
|
|
homeButton.addEventListener("click", () =>
|
|
registerClick({ path: "home", logText: "await homeButton();" })
|
|
);
|
|
|
|
backButton.addEventListener("click", () =>
|
|
registerClick({ path: "back", logText: "await backButton();" })
|
|
);
|
|
|
|
async function displayImage() {
|
|
try {
|
|
const response = await fetch("screen");
|
|
const blob = await response.blob();
|
|
screen.src = URL.createObjectURL(blob);
|
|
} catch (error) {
|
|
console.error("Error fetching image: ", error);
|
|
}
|
|
}
|
|
|
|
let isDragging = false;
|
|
let startDraggingPosX = 0;
|
|
let endDraggingPosX = 0;
|
|
let startDraggingPosY = 0;
|
|
let endDraggingPosY = 0;
|
|
|
|
const screenSize = [320, 640];
|
|
|
|
const handleDraggStart = (e) => {
|
|
e.preventDefault();
|
|
isDragging = true;
|
|
startDraggingPosX = e.offsetX;
|
|
startDraggingPosY = e.offsetY;
|
|
};
|
|
|
|
screen.addEventListener("mousedown", handleDraggStart);
|
|
|
|
document.addEventListener("mouseup", (e) => {
|
|
endDraggingPosX = e.offsetX;
|
|
endDraggingPosY = e.offsetY;
|
|
if (
|
|
isDragging &&
|
|
(Math.abs(endDraggingPosY - startDraggingPosY) > 10 ||
|
|
Math.abs(endDraggingPosX - startDraggingPosX) > 10)
|
|
) {
|
|
registerClick({
|
|
path: "drag",
|
|
logText: `await drag({x:${startDraggingPosX},y:${startDraggingPosY}},{x:${e.offsetX},y:${e.offsetY}});`,
|
|
body: `startX=${startDraggingPosX}&startY=${startDraggingPosY}&endX=${e.offsetX}&endY=${e.offsetY}`,
|
|
});
|
|
} else if (e.target === screen) {
|
|
const phoneX = event.offsetX;
|
|
const phoneY = event.offsetY;
|
|
if (phoneX <= screenSize[0] && phoneY <= screenSize[1])
|
|
registerClick({
|
|
path: "touch",
|
|
logText: `await click(${phoneX}, ${phoneY});`,
|
|
body: `x=${phoneX}&y=${phoneY}`,
|
|
});
|
|
}
|
|
isDragging = false;
|
|
});
|
|
|
|
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>
|
|
</body>
|
|
</html>
|