* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix * fix: track native source modules with root-anchored runtime ignores
61 lines
2.7 KiB
JavaScript
61 lines
2.7 KiB
JavaScript
const ext = globalThis.browser || globalThis.chrome;
|
|
const csrfCache = new Map();
|
|
|
|
function arrayBufferToBase64(buffer) {
|
|
const bytes = new Uint8Array(buffer);
|
|
const chunkSize = 0x8000;
|
|
let binary = '';
|
|
for (let offset = 0; offset < bytes.length; offset += chunkSize) binary += String.fromCharCode(...bytes.subarray(offset, offset + chunkSize));
|
|
return btoa(binary);
|
|
}
|
|
|
|
async function getCsrf(serverUrl) {
|
|
if (csrfCache.has(serverUrl)) return csrfCache.get(serverUrl);
|
|
const response = await fetch(`${serverUrl}/api/me`, { credentials: 'include', cache: 'no-store' });
|
|
if (!response.ok) return '';
|
|
const data = await response.json();
|
|
const token = data.csrf || '';
|
|
csrfCache.set(serverUrl, token);
|
|
return token;
|
|
}
|
|
|
|
ext.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
|
|
if (msg.type === 'api') {
|
|
(async () => {
|
|
try {
|
|
const { serverUrl, path, method = 'GET', body } = msg;
|
|
const opts = { method, headers: {}, credentials: 'include', cache: 'no-store' };
|
|
if (body !== undefined) { opts.headers['Content-Type'] = 'application/json'; opts.body = JSON.stringify(body); }
|
|
if (!['GET', 'HEAD', 'OPTIONS'].includes(method)) {
|
|
const csrf = await getCsrf(serverUrl);
|
|
if (csrf) opts.headers['X-CSRF-Token'] = csrf;
|
|
}
|
|
let response = await fetch(`${serverUrl}${path}`, opts);
|
|
if (response.status === 403 && !['GET', 'HEAD', 'OPTIONS'].includes(method)) {
|
|
csrfCache.delete(serverUrl);
|
|
const csrf = await getCsrf(serverUrl);
|
|
if (csrf) opts.headers['X-CSRF-Token'] = csrf;
|
|
response = await fetch(`${serverUrl}${path}`, opts);
|
|
}
|
|
const contentType = response.headers.get('content-type') || '';
|
|
const data = contentType.includes('application/json') ? await response.json() : { error: await response.text() };
|
|
sendResponse({ ok: response.ok, status: response.status, data });
|
|
} catch (error) { sendResponse({ ok: false, status: 0, error: error.message }); }
|
|
})();
|
|
return true;
|
|
}
|
|
if (msg.type === 'fetch-image') {
|
|
(async () => {
|
|
try {
|
|
const response = await fetch(msg.url, { cache: 'no-store', credentials: 'include' });
|
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
const blob = await response.blob();
|
|
if (!blob.type.startsWith('image/')) throw new Error('Antwort ist kein Bild');
|
|
const buffer = await blob.arrayBuffer();
|
|
sendResponse({ ok: true, dataUrl: `data:${blob.type};base64,${arrayBufferToBase64(buffer)}`, mime: blob.type, size: blob.size });
|
|
} catch (error) { sendResponse({ ok: false, error: error.message }); }
|
|
})();
|
|
return true;
|
|
}
|
|
});
|