ksjsb/core/h5_vendor_encode.mjs
2026-07-30 20:25:56 +08:00

244 lines
6.6 KiB
JavaScript

import { readFileSync } from "node:fs";
import { pathToFileURL } from "node:url";
export function installBrowserStubs(cookie = "") {
const g = globalThis;
g.window = g;
g.self = g;
g.top = g;
g.__assetsPath = "./";
Object.defineProperty(g, "navigator", {
value: {
userAgent:
"Mozilla/5.0 (Linux; Android 16; PJZ110 Build/BP2A.250605.015; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/149.0.7827.164 Mobile Safari/537.36 ksNebula/14.5.50.11631",
appVersion: "Android 16",
language: "zh-CN",
},
configurable: true,
});
g.screen = { width: 1080, height: 2376, availWidth: 1080, availHeight: 2376 };
g.devicePixelRatio = 3;
Object.defineProperty(g, "location", {
value: {
href: "https://nebula.kuaishou.com/nebula/task/earning?&layoutType=4&source=bottom_guide_first",
search: "?layoutType=4&source=bottom_guide_first",
origin: "https://nebula.kuaishou.com",
pathname: "/nebula/task/earning",
hash: "",
hostname: "nebula.kuaishou.com",
assign(v) {
this.href = v;
},
replace(v) {
this.href = v;
},
},
configurable: true,
});
g.history = { state: null, length: 1, pushState() {}, replaceState() {}, back() {}, go() {} };
g.Event = class {
constructor(type, opts = {}) {
this.type = type;
this.cancelable = !!opts.cancelable;
this.defaultPrevented = false;
}
};
g.CustomEvent = g.Event;
g.HTMLElement = class {};
g.Element = class {};
g.Node = class {};
const elem = (tag = "div") => {
const e = {
tagName: String(tag).toUpperCase(),
nodeType: 1,
style: {},
children: [],
childNodes: [],
parentNode: { removeChild() {} },
setAttribute() {},
getAttribute() {
return null;
},
appendChild(c) {
this.children.push(c);
this.childNodes.push(c);
return c;
},
insertBefore(c) {
this.children.push(c);
this.childNodes.push(c);
return c;
},
removeChild() {},
addEventListener() {},
removeEventListener() {},
dispatchEvent() {
return true;
},
href: "",
rel: "",
as: "",
crossOrigin: "",
cloneNode() {
return elem(tag);
},
getBoundingClientRect() {
return { top: 0, left: 0, width: 1, height: 1, right: 1, bottom: 1 };
},
clientWidth: 1080,
clientHeight: 2376,
};
Object.setPrototypeOf(e, Element.prototype);
return e;
};
Object.defineProperty(g, "document", {
value: {
cookie,
hidden: false,
visibilityState: "visible",
nodeType: 9,
createElement: elem,
createTextNode(text) {
return { nodeType: 3, textContent: text, nodeValue: text, childNodes: [], children: [] };
},
createEvent(type) {
return {
type,
initEvent(name, bubbles, cancelable) {
this.type = name;
this.bubbles = bubbles;
this.cancelable = cancelable;
},
preventDefault() {
this.defaultPrevented = true;
},
};
},
getElementsByTagName() {
return [];
},
querySelector() {
return null;
},
querySelectorAll() {
return [];
},
addEventListener() {},
removeEventListener() {},
dispatchEvent() {
return true;
},
},
configurable: true,
});
document.documentElement = elem("html");
document.head = elem("head");
document.body = elem("body");
g.getComputedStyle = () => ({
display: "block",
visibility: "visible",
opacity: "1",
width: "1px",
height: "1px",
getPropertyValue() {
return "";
},
});
g.localStorage = { getItem() { return null; }, setItem() {}, removeItem() {}, clear() {} };
g.sessionStorage = g.localStorage;
g.performance = { now: () => Date.now(), mark() {}, measure() {} };
g.requestAnimationFrame = (fn) => setTimeout(fn, 0);
g.cancelAnimationFrame = (id) => clearTimeout(id);
g.addEventListener = () => {};
g.removeEventListener = () => {};
g.dispatchEvent = () => true;
g.MutationObserver = class {
constructor() {}
observe() {}
disconnect() {}
takeRecords() {
return [];
}
};
g.XMLHttpRequest = class {
open() {}
setRequestHeader() {}
send() {
this.readyState = 4;
this.status = 0;
this.onreadystatechange && this.onreadystatechange();
}
addEventListener() {}
};
g.fetch = async () => ({ ok: false, status: 0, json: async () => ({}), text: async () => "" });
g.atob = (s) => Buffer.from(s, "base64").toString("binary");
g.btoa = (s) => Buffer.from(s, "binary").toString("base64");
Object.defineProperty(g, "crypto", {
value: {
getRandomValues(arr) {
for (let i = 0; i < arr.length; i++) arr[i] = Math.floor(Math.random() * 256);
return arr;
},
},
configurable: true,
});
}
export async function loadVendor() {
let src = readFileSync(new URL("./main-vendor-ox-x1_g5.mjs", import.meta.url), "utf8");
src = src.replace(
'import{_ as __vitePreload}from"./main-CZ3ZSK5w.js";',
"const __vitePreload=(base,deps,importerUrl)=>base();",
);
return import("data:text/javascript;base64," + Buffer.from(src).toString("base64"));
}
export function encodeWith(instance, signInput) {
return new Promise((resolve, reject) => {
instance.call("$encode", [
signInput,
{
suc(result, cInfo) {
resolve({ result, cInfo });
},
err(error) {
reject(error);
},
},
]);
});
}
async function main() {
const signInput = process.argv[2] === "-" ? readFileSync(0, "utf8") : process.argv[2] || "sigCatVer=1";
const cookie = process.env.KS_COOKIE || "";
const exportName = process.env.KS_VENDOR_EXPORT || "f";
installBrowserStubs(cookie);
const realConsole = { log: console.log, warn: console.warn, error: console.error };
if (!process.env.KS_VENDOR_DEBUG) {
console.log = () => {};
console.warn = () => {};
console.error = () => {};
}
const vendor = await loadVendor();
console.log = realConsole.log;
console.warn = realConsole.warn;
console.error = realConsole.error;
const instance = vendor[exportName];
if (!instance || typeof instance.call !== "function") {
throw new Error(`vendor export ${exportName} has no call()`);
}
const encoded = await encodeWith(instance, signInput);
console.log(JSON.stringify({ exportName, signInput, ...encoded }, null, 2));
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
await main();
}