244 lines
6.6 KiB
JavaScript
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();
|
|
}
|