225 lines
5.6 KiB
TypeScript
225 lines
5.6 KiB
TypeScript
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;
|
|
}
|