78 lines
3.0 KiB
JavaScript
78 lines
3.0 KiB
JavaScript
// Synthetic bundle for raycast_api.discovery tests.
|
|
//
|
|
// Structurally mirrors Raycast's bundle: a rot13+rot5 function, an async
|
|
// 4-param HMAC signer that .map()s through the rot fn, and a couple of decoys
|
|
// the extractor must reject. Identifier names are intentionally NOT the
|
|
// minified ones from real Raycast (Sur, Nkt) — we use longer names to prove
|
|
// the extractor matches structurally, not by name.
|
|
|
|
// --- decoy 1: 1-param but missing the rot triplets ----------------------
|
|
function decoyOneParam(t) {
|
|
return t.toUpperCase();
|
|
}
|
|
|
|
// --- decoy 2: 4-param HMAC-ish but with no .map(rot) call --------------
|
|
async function decoyHmac(a, b, c, d) {
|
|
// Mentions HMAC + SHA-256 + importKey but never calls .map(rotFn).
|
|
let key = await crypto.subtle.importKey("raw", a, {
|
|
name: "HMAC",
|
|
hash: "SHA-256"
|
|
}, false, ["sign"]);
|
|
return crypto.subtle.sign("HMAC", key, b);
|
|
}
|
|
|
|
// --- the real rot fn ----------------------------------------------------
|
|
function RotXform(s) {
|
|
let out = "";
|
|
for (let ch of s) {
|
|
let r = ch.charCodeAt(0);
|
|
if (r >= 65 && r <= 90) {
|
|
out += String.fromCharCode((r - 65 + 13) % 26 + 65);
|
|
} else if (r >= 97 && r <= 122) {
|
|
out += String.fromCharCode((r - 97 + 13) % 26 + 97);
|
|
} else if (r >= 48 && r <= 57) {
|
|
out += String.fromCharCode((r - 48 + 5) % 10 + 48);
|
|
} else {
|
|
out += ch;
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
// --- duplicate rot (real bundle has two byte-identical copies) ---------
|
|
function RotXform2(s) {
|
|
let out = "";
|
|
for (let ch of s) {
|
|
let r = ch.charCodeAt(0);
|
|
if (r >= 65 && r <= 90) { out += String.fromCharCode((r - 65 + 13) % 26 + 65); }
|
|
else if (r >= 97 && r <= 122) { out += String.fromCharCode((r - 97 + 13) % 26 + 97); }
|
|
else if (r >= 48 && r <= 57) { out += String.fromCharCode((r - 48 + 5) % 10 + 48); }
|
|
else { out += ch; }
|
|
}
|
|
return out;
|
|
}
|
|
|
|
// --- the real signing fn -----------------------------------------------
|
|
async function SignReq(secret, timestamp, deviceId, body) {
|
|
let enc = new TextEncoder().encode(body);
|
|
let h = await crypto.subtle.digest("SHA-256", enc);
|
|
let bodyHash = Array.from(new Uint8Array(h)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
let canonical = [timestamp, deviceId, bodyHash].map(RotXform).join(".");
|
|
let keyBytes = new TextEncoder().encode(secret);
|
|
let canonBytes = new TextEncoder().encode(canonical);
|
|
let key = await crypto.subtle.importKey("raw", keyBytes, {
|
|
name: "HMAC",
|
|
hash: "SHA-256"
|
|
}, false, ["sign"]);
|
|
let sig = await crypto.subtle.sign("HMAC", key, canonBytes);
|
|
return Array.from(new Uint8Array(sig)).map(b => b.toString(16).padStart(2, "0")).join("");
|
|
}
|
|
|
|
// Decoy: looks like a string-handling function but with a `/` inside a
|
|
// regex literal — exercises the regex-aware brace matcher.
|
|
function noiseFn(input) {
|
|
return input.replace(/\}/g, "_");
|
|
}
|
|
|
|
export { SignReq, RotXform };
|