This commit is contained in:
Carlos Polop 2025-05-03 02:30:38 +02:00
parent 0d10610d75
commit f1493f847b

View File

@ -1,96 +1,92 @@
/* ht_searcher.js ───────────────────────────────────────────────── */ /* ht_searcher.js ─────────────────────────────────────────────── */
/* Everything UI + worker lives in this one file. */
(() => { (() => {
/* /* ───────────── 0. Inline Web-Worker code ────────────────────── */
0. Build an inline Web Worker
*/
const workerCode = ` const workerCode = `
/* inside the worker thread ################################## */ /* Make scripts written for browsers happy inside the worker */
self.window = self; /* let searchindex.js use window */ self.window = self;
self.search = self.search || {}; /* ensure object */
/* 1. elasticlunr.min.js (CDN → local) */
const abs = p => location.origin + p; /* helper */
/* 1 ─ elasticlunr.min.js (CDN → local) */
try { try {
importScripts('https://cdn.jsdelivr.net/npm/elasticlunr@0.9.5/elasticlunr.min.js'); importScripts('https://cdn.jsdelivr.net/npm/elasticlunr@0.9.5/elasticlunr.min.js');
} catch (_) { } catch (e) {
importScripts('/elasticlunr.min.js'); console.error('elasticlunr CDN failed →', e);
importScripts(abs('/elasticlunr.min.js'));
} }
/* 2. searchindex.js (GitHub Raw → local) */ /* 2 searchindex.js (GitHub Raw → local) */
(async () => { (async () => {
try { try {
const r = await fetch( const r = await fetch(
'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js', 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js',
{ mode: 'cors' } { mode:'cors' }
); );
if (!r.ok) throw new Error(r.status); if (!r.ok) throw new Error('HTTP ' + r.status);
const blobURL = URL.createObjectURL( const blobURL = URL.createObjectURL(
new Blob([await r.text()], { type: 'application/javascript' }) new Blob([await r.text()], { type:'application/javascript' })
); /* force correct MIME */ );
importScripts(blobURL); importScripts(blobURL); /* MIME coercion */
} catch (_) { } catch (e) {
importScripts('/searchindex.js'); console.error('GitHub index fetch failed →', e);
try {
importScripts(abs('/searchindex.js'));
} catch (e2) {
console.error('Local index load failed →', e2);
throw e2; /* abort loudly */
}
} }
/* 3. Build index & reply to queries */ /* 3 ─ build index & answer queries */
const idx = elasticlunr.Index.load(self.search.index); const idx = elasticlunr.Index.load(self.search.index);
self.onmessage = ({ data: q }) => { self.onmessage = ({ data:q }) => {
const hits = idx.search(q, { bool: 'AND', expand: true }); if (!q) { postMessage([]); return; } /* empty search */
postMessage(hits); const raw = idx.search(q, { bool:'AND', expand:true });
const docs = raw.map(r => idx.documentStore.getDoc(r.ref));
postMessage(docs); /* only docs cross thread */
}; };
})(); })();
`; `;
/* Turn the string into a real worker file */
const workerURL = URL.createObjectURL( const workerURL = URL.createObjectURL(
new Blob([workerCode], { type: 'application/javascript' }) new Blob([workerCode], { type:'application/javascript' })
); );
const worker = new Worker(workerURL); /* classic worker, supports importScripts */ const worker = new Worker(workerURL);
URL.revokeObjectURL(workerURL); /* clean up */ URL.revokeObjectURL(workerURL); /* tidy blob */
/* /* ───────────── 1. Tiny UI glue ─────────────────────────────── */
1. Minimal search-UI glue const WRAP = document.getElementById('search-wrapper');
*/ const TOG = document.getElementById('search-toggle');
const WRAP = document.getElementById('search-wrapper'); const INP = document.getElementById('searchbar');
const TOG = document.getElementById('search-toggle'); const LIST = document.getElementById('searchresults');
const INP = document.getElementById('searchbar');
const LIST = document.getElementById('searchresults');
const HOTKEY = 83; /* “s” */ const HOTKEY = 83; /* “s” */
let debounce; let debounce;
/* Paint results that come back from the worker */ /* paint results */
const paint = hits => { worker.onmessage = ({ data:docs }) => {
LIST.innerHTML = hits.slice(0, 30).map(h => LIST.innerHTML = docs.slice(0,30).map(d =>
'<li><a href="' + h.doc.url + '">' + h.doc.title + '</a></li>' '<li><a href="' + d.url + '">' + d.title + '</a></li>'
).join(''); ).join('');
}; };
worker.onmessage = ({ data }) => paint(data); /* open UI */
const open = () => { WRAP.classList.remove('hidden'); INP.focus(); };
/* Open the search UI */
const open = () => {
WRAP.classList.remove('hidden');
INP.focus();
};
/* Toggle button */
TOG.addEventListener('click', open); TOG.addEventListener('click', open);
/* Keyboard shortcut: “s” (no modifiers) */
document.addEventListener('keydown', e => { document.addEventListener('keydown', e => {
if (!e.metaKey && !e.ctrlKey && !e.altKey && e.keyCode === HOTKEY) { if (!e.metaKey && !e.ctrlKey && !e.altKey && e.keyCode === HOTKEY) {
e.preventDefault(); e.preventDefault(); open();
open();
} }
}); });
/* Debounced input → worker */ /* debounced keystrokes → worker */
INP.addEventListener('input', e => { INP.addEventListener('input', e => {
clearTimeout(debounce); clearTimeout(debounce);
debounce = setTimeout(() => { debounce = setTimeout(() => {
worker.postMessage(e.target.value.trim()); worker.postMessage(e.target.value.trim());
}, 120); }, 120);
}); });
})(); })();