mirror of
https://github.com/MathMan05/Fermi.git
synced 2026-08-06 23:29:44 +00:00
traces
This commit is contained in:
@@ -644,6 +644,11 @@ class Localuser {
|
||||
this.rights.update(rights);
|
||||
this.perminfo.user.rights = rights;
|
||||
}
|
||||
traceSub() {
|
||||
SW.captureEvent("trace", (e) => {
|
||||
this.handleTrace(e.trace);
|
||||
});
|
||||
}
|
||||
async handleEvent(temp: wsjson) {
|
||||
if (temp.d._trace) this.handleTrace(temp.d._trace);
|
||||
if (localStorage.getItem("logGateway")) console.debug(temp);
|
||||
@@ -3247,9 +3252,23 @@ class Localuser {
|
||||
SW.postMessage({code: "isDev", dev: e});
|
||||
};
|
||||
devSettings.addText(I18n.devSettings.cacheDesc());
|
||||
|
||||
const box5 = devSettings.addCheckboxInput(I18n.devSettings.captureTrace(), () => {}, {
|
||||
initState: !!localStorage.getItem("capTrace"),
|
||||
});
|
||||
box5.onchange = (e) => {
|
||||
if (e) {
|
||||
localStorage.setItem("capTrace", "true");
|
||||
} else {
|
||||
localStorage.removeItem("capTrace");
|
||||
}
|
||||
SW.traceInit();
|
||||
};
|
||||
}
|
||||
if (this.trace.length && localStorage.getItem("traces")) {
|
||||
const traces = settings.addButton(I18n.localuser.trace());
|
||||
const traces = settings.addButton(I18n.localuser.trace(), {
|
||||
noSubmit: true,
|
||||
});
|
||||
const traceArr = this.trace;
|
||||
|
||||
const sel = traces.addSelect(
|
||||
|
||||
+31
-1
@@ -171,8 +171,30 @@ async function getfile(event: FetchEvent): Promise<Response> {
|
||||
}
|
||||
}
|
||||
|
||||
self.addEventListener("fetch", (e) => {
|
||||
self.addEventListener("fetch", async (e) => {
|
||||
const event = e as FetchEvent;
|
||||
|
||||
if (URL.canParse(event.request.url) && apiHosts?.has(new URL(event.request.url).host)) {
|
||||
try {
|
||||
const responce = await fetch(event.request.clone());
|
||||
try {
|
||||
event.respondWith(responce.clone());
|
||||
} catch {}
|
||||
|
||||
const json = await responce.json();
|
||||
if (json._trace) {
|
||||
sendAll({
|
||||
code: "trace",
|
||||
trace: json._trace,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
//Wasn't meant to be ig lol
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.request.method === "POST") {
|
||||
return;
|
||||
}
|
||||
@@ -187,6 +209,7 @@ self.addEventListener("fetch", (e) => {
|
||||
});
|
||||
const ports = new Set<MessagePort>();
|
||||
let dev = false;
|
||||
let apiHosts: Set<string> | void;
|
||||
function listenToPort(port: MessagePort) {
|
||||
function sendMessage(message: messageFrom) {
|
||||
port.postMessage(message);
|
||||
@@ -233,6 +256,13 @@ function listenToPort(port: MessagePort) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "apiUrls": {
|
||||
if (data.hosts) {
|
||||
apiHosts = new Set(data.hosts);
|
||||
} else {
|
||||
apiHosts = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
port.addEventListener("close", () => {
|
||||
|
||||
+37
-31
@@ -1112,7 +1112,7 @@ class Options implements OptionsElement<void> {
|
||||
headers = {},
|
||||
method = "POST",
|
||||
traditionalSubmit = false,
|
||||
tfaCheck=true
|
||||
tfaCheck = true,
|
||||
} = {},
|
||||
) {
|
||||
const options = new Form(name, this, onSubmit, {
|
||||
@@ -1122,7 +1122,7 @@ class Options implements OptionsElement<void> {
|
||||
headers,
|
||||
method,
|
||||
traditionalSubmit,
|
||||
tfaCheck
|
||||
tfaCheck,
|
||||
});
|
||||
this.subOptions = options;
|
||||
this.genTop();
|
||||
@@ -1304,10 +1304,10 @@ class Options implements OptionsElement<void> {
|
||||
container.append(div);
|
||||
}
|
||||
}
|
||||
deleteElm(opt:OptionsElement<any>){
|
||||
deleteElm(opt: OptionsElement<any>) {
|
||||
const html = this.html.get(opt)?.deref();
|
||||
this.options=this.options.filter(_=>_!==opt);
|
||||
if(!html) return;
|
||||
this.options = this.options.filter((_) => _ !== opt);
|
||||
if (!html) return;
|
||||
html.remove();
|
||||
this.html.delete(opt);
|
||||
}
|
||||
@@ -1559,42 +1559,48 @@ class FormError extends Error {
|
||||
}
|
||||
async function handle2fa(json: any, api: string): Promise<false | any> {
|
||||
if (json.ticket) {
|
||||
if(json.webauthn){
|
||||
const challenge = JSON.parse(json.webauthn).publicKey as PublicKeyCredentialRequestOptionsJSON;
|
||||
challenge.challenge=challenge.challenge.split("=")[0].replaceAll("+","-").replaceAll("/","_");
|
||||
challenge.allowCredentials?.forEach(_=>_.id=_.id.split("=")[0].replaceAll("+","-").replaceAll("/","_"))
|
||||
if (json.webauthn) {
|
||||
const challenge = JSON.parse(json.webauthn)
|
||||
.publicKey as PublicKeyCredentialRequestOptionsJSON;
|
||||
challenge.challenge = challenge.challenge
|
||||
.split("=")[0]
|
||||
.replaceAll("+", "-")
|
||||
.replaceAll("/", "_");
|
||||
challenge.allowCredentials?.forEach(
|
||||
(_) => (_.id = _.id.split("=")[0].replaceAll("+", "-").replaceAll("/", "_")),
|
||||
);
|
||||
console.log(challenge);
|
||||
const options = PublicKeyCredential.parseRequestOptionsFromJSON(challenge);
|
||||
const credential = await navigator.credentials.get({publicKey: options}) as unknown as {
|
||||
rawId:ArrayBuffer,
|
||||
response:{
|
||||
[key:string]:ArrayBuffer,
|
||||
}
|
||||
const credential = (await navigator.credentials.get({publicKey: options})) as unknown as {
|
||||
rawId: ArrayBuffer;
|
||||
response: {
|
||||
[key: string]: ArrayBuffer;
|
||||
};
|
||||
};
|
||||
if(!credential) return false;
|
||||
function toBase64(buf:ArrayBuffer){
|
||||
return btoa(String.fromCharCode(...new Uint8Array(buf)))
|
||||
if (!credential) return false;
|
||||
function toBase64(buf: ArrayBuffer) {
|
||||
return btoa(String.fromCharCode(...new Uint8Array(buf)));
|
||||
}
|
||||
const keys = ["authenticatorData","clientDataJSON","signature"];
|
||||
const keys = ["authenticatorData", "clientDataJSON", "signature"];
|
||||
const response = {} as any;
|
||||
for(const key of keys){
|
||||
response[key]=toBase64(credential.response[key] as ArrayBuffer);
|
||||
for (const key of keys) {
|
||||
response[key] = toBase64(credential.response[key] as ArrayBuffer);
|
||||
}
|
||||
const res = {
|
||||
rawId:toBase64(credential.rawId),
|
||||
response
|
||||
rawId: toBase64(credential.rawId),
|
||||
response,
|
||||
};
|
||||
const resObj = await fetch(api + "/auth/mfa/webauthn",{
|
||||
const resObj = await fetch(api + "/auth/mfa/webauthn", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body:JSON.stringify({code:JSON.stringify(res),ticket:json.ticket})
|
||||
body: JSON.stringify({code: JSON.stringify(res), ticket: json.ticket}),
|
||||
});
|
||||
if(!resObj.ok) return false;
|
||||
if (!resObj.ok) return false;
|
||||
const jsonRes = await resObj.json();
|
||||
return jsonRes;
|
||||
}else{
|
||||
} else {
|
||||
return new Promise<boolean>((resolution) => {
|
||||
const better = new Dialog("");
|
||||
const form = better.options.addForm(
|
||||
@@ -1656,7 +1662,7 @@ class Form implements OptionsElement<object> {
|
||||
value!: object;
|
||||
traditionalSubmit: boolean;
|
||||
values: {[key: string]: any} = {};
|
||||
tfaCheck:boolean;
|
||||
tfaCheck: boolean;
|
||||
constructor(
|
||||
name: string,
|
||||
owner: Options,
|
||||
@@ -1669,12 +1675,12 @@ class Form implements OptionsElement<object> {
|
||||
method = "POST",
|
||||
traditionalSubmit = false,
|
||||
vsmaller = false,
|
||||
tfaCheck=true
|
||||
tfaCheck = true,
|
||||
} = {},
|
||||
) {
|
||||
this.traditionalSubmit = traditionalSubmit;
|
||||
this.name = name;
|
||||
this.tfaCheck=tfaCheck;
|
||||
this.tfaCheck = tfaCheck;
|
||||
this.method = method;
|
||||
this.submitText = submitText;
|
||||
this.options = new Options(name, this, {ltr, vsmaller});
|
||||
@@ -2153,8 +2159,8 @@ class Settings extends Buttons {
|
||||
constructor(name: string) {
|
||||
super(name);
|
||||
}
|
||||
addButton(name: string, {ltr = false, optName = name} = {}): Options {
|
||||
const options = new Options(optName, this, {ltr});
|
||||
addButton(name: string, {ltr = false, optName = name, noSubmit = false} = {}): Options {
|
||||
const options = new Options(optName, this, {ltr, noSubmit});
|
||||
this.add(name, options);
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ export type messageTo =
|
||||
| {
|
||||
code: "isDev";
|
||||
dev: boolean;
|
||||
}
|
||||
| {
|
||||
code: "apiUrls";
|
||||
hosts?: string[];
|
||||
};
|
||||
export type messageFrom =
|
||||
| {
|
||||
@@ -38,4 +42,8 @@ export type messageFrom =
|
||||
code: "isValid";
|
||||
url: string;
|
||||
valid: boolean;
|
||||
}
|
||||
| {
|
||||
code: "trace";
|
||||
trace: string[];
|
||||
};
|
||||
|
||||
@@ -35,10 +35,22 @@ export function setTheme() {
|
||||
}
|
||||
export function getBulkUsers() {
|
||||
const json = getBulkInfo();
|
||||
apiDoms.clear();
|
||||
for (const thing in json.users) {
|
||||
const user = (json.users[thing] = new Specialuser(json.users[thing]));
|
||||
apiDoms.add(new URL(user.serverurls.api).host);
|
||||
}
|
||||
if (localStorage.getItem("capTrace")) {
|
||||
SW.postMessage({
|
||||
code: "apiUrls",
|
||||
hosts: [...apiDoms],
|
||||
});
|
||||
} else {
|
||||
SW.postMessage({
|
||||
code: "apiUrls",
|
||||
hosts: undefined,
|
||||
});
|
||||
}
|
||||
return json;
|
||||
}
|
||||
export function getBulkInfo() {
|
||||
@@ -883,9 +895,16 @@ export class SW {
|
||||
}
|
||||
});
|
||||
}
|
||||
static traceInit() {
|
||||
getBulkUsers();
|
||||
}
|
||||
static needsUpdate = false;
|
||||
static postMessage(message: messageTo) {
|
||||
this.port?.postMessage(message);
|
||||
static async postMessage(message: messageTo) {
|
||||
if (!("serviceWorker" in navigator)) return;
|
||||
while (!this.port) {
|
||||
await new Promise((res) => setTimeout(res, 100));
|
||||
}
|
||||
this.port.postMessage(message);
|
||||
}
|
||||
static eventListeners = new Map<
|
||||
messageFrom["code"],
|
||||
|
||||
@@ -297,7 +297,8 @@
|
||||
"logGateway":"Log received gateway events (log level info):",
|
||||
"traces":"Expose traces:",
|
||||
"cache":"Enable Service Worker Caching map files:",
|
||||
"cacheDesc":"map files will still load either way, this'll just make sure they're in cache when a new update rolls out."
|
||||
"cacheDesc":"map files will still load either way, this'll just make sure they're in cache when a new update rolls out.",
|
||||
"captureTrace":"This setting tells Fermi to capture _trace properties from the server, enabling this may cause progressive JSON decoding to not work (might require a reload)"
|
||||
},
|
||||
"htmlPages": {
|
||||
"idpermissions": "This will allow the bot to:",
|
||||
|
||||
Reference in New Issue
Block a user