267 lines
9.6 KiB
JavaScript
267 lines
9.6 KiB
JavaScript
// !!!!! Do not use in release mode. Just a native inject fake wrapper for test spider. !!!!!
|
|
// !!!!! Do not use in release mode. Just a native inject fake wrapper for test spider. !!!!!
|
|
// !!!!! Do not use in release mode. Just a native inject fake wrapper for test spider. !!!!!
|
|
import axios from 'axios';
|
|
import crypto from 'crypto';
|
|
import https from 'https';
|
|
import fs from 'node:fs';
|
|
import qs from 'qs';
|
|
import { Uri, _ } from '../lib/cat.js';
|
|
|
|
const confs = {};
|
|
|
|
function initLocalStorage(storage) {
|
|
if (!_.has(confs, storage)) {
|
|
if (!fs.existsSync('local')) {
|
|
fs.mkdirSync('local');
|
|
}
|
|
|
|
const storagePath = 'local/js_' + storage;
|
|
|
|
if (!fs.existsSync(storagePath)) {
|
|
fs.writeFileSync(storagePath, '{}');
|
|
confs[storage] = {};
|
|
} else {
|
|
confs[storage] = JSON.parse(fs.readFileSync(storagePath).toString());
|
|
}
|
|
}
|
|
}
|
|
|
|
function localGet(storage, key) {
|
|
initLocalStorage(storage);
|
|
return _.get(confs[storage], key, '');
|
|
}
|
|
|
|
function localSet(storage, key, value) {
|
|
initLocalStorage(storage);
|
|
confs[storage][key] = value;
|
|
fs.writeFileSync('local/js_' + storage, JSON.stringify(confs[storage]));
|
|
}
|
|
|
|
async function request(url, opt) {
|
|
try {
|
|
var data = opt ? opt.data || null : null;
|
|
var postType = opt ? opt.postType || null : null;
|
|
var returnBuffer = opt ? opt.buffer || 0 : 0;
|
|
var timeout = opt ? opt.timeout || 5000 : 5000;
|
|
|
|
var headers = opt ? opt.headers || {} : {};
|
|
if (postType == 'form') {
|
|
headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
|
|
if (data != null) {
|
|
data = qs.stringify(data, { encode: false });
|
|
}
|
|
}
|
|
let respType = returnBuffer == 1 || returnBuffer == 2 ? 'arraybuffer' : undefined;
|
|
var resp = await axios(url, {
|
|
responseType: respType,
|
|
method: opt ? opt.method || 'get' : 'get',
|
|
headers: headers,
|
|
data: data,
|
|
timeout: timeout,
|
|
httpsAgent: https.Agent({
|
|
rejectUnauthorized: false,
|
|
}),
|
|
});
|
|
var data = resp.data;
|
|
|
|
var resHeader = {};
|
|
for (const hks of resp.headers) {
|
|
var v = hks[1];
|
|
resHeader[hks[0]] = Array.isArray(v) ? (v.length == 1 ? v[0] : v) : v;
|
|
}
|
|
|
|
if (!returnBuffer) {
|
|
if (typeof data === 'object') {
|
|
data = JSON.stringify(data);
|
|
}
|
|
} else if (returnBuffer == 1) {
|
|
return { code: resp.status, headers: resHeader, content: data };
|
|
} else if (returnBuffer == 2) {
|
|
return { code: resp.status, headers: resHeader, content: data.toString('base64') };
|
|
}
|
|
return { code: resp.status, headers: resHeader, content: data };
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
return { headers: {}, content: '' };
|
|
}
|
|
|
|
function base64EncodeBuf(buff, urlsafe = false) {
|
|
return buff.toString(urlsafe ? 'base64url' : 'base64');
|
|
}
|
|
|
|
function base64Encode(text, urlsafe = false) {
|
|
return base64EncodeBuf(Buffer.from(text, 'utf8'), urlsafe);
|
|
}
|
|
|
|
function base64DecodeBuf(text) {
|
|
return Buffer.from(text, 'base64');
|
|
}
|
|
|
|
function base64Decode(text) {
|
|
return base64DecodeBuf(text).toString('utf8');
|
|
}
|
|
|
|
function md5(text) {
|
|
return crypto.createHash('md5').update(Buffer.from(text, 'utf8')).digest('hex');
|
|
}
|
|
|
|
function aes(mode, encrypt, input, inBase64, key, iv, outBase64) {
|
|
if (iv.length == 0) iv = null;
|
|
try {
|
|
if (mode.startsWith('AES/CBC')) {
|
|
switch (key.length) {
|
|
case 16:
|
|
mode = 'aes-128-cbc';
|
|
break;
|
|
case 32:
|
|
mode = 'aes-256-cbc';
|
|
break;
|
|
}
|
|
} else if (mode.startsWith('AES/ECB')) {
|
|
switch (key.length) {
|
|
case 16:
|
|
mode = 'aes-128-ecb';
|
|
break;
|
|
case 32:
|
|
mode = 'aes-256-ecb';
|
|
break;
|
|
}
|
|
}
|
|
const inBuf = inBase64 ? base64DecodeBuf(input) : Buffer.from(input, 'utf8');
|
|
let keyBuf = Buffer.from(key);
|
|
if (keyBuf.length < 16) keyBuf = Buffer.concat([keyBuf], 16);
|
|
let ivBuf = iv == null ? Buffer.alloc(0) : Buffer.from(iv);
|
|
if (iv != null && ivBuf.length < 16) ivBuf = Buffer.concat([ivBuf], 16);
|
|
const cipher = encrypt ? crypto.createCipheriv(mode, keyBuf, ivBuf) : crypto.createDecipheriv(mode, keyBuf, ivBuf);
|
|
const outBuf = Buffer.concat([cipher.update(inBuf), cipher.final()]);
|
|
return outBase64 ? base64EncodeBuf(outBuf) : outBuf.toString('utf8');
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
function des(mode, encrypt, input, inBase64, key, iv, outBase64) {
|
|
try {
|
|
if (mode.startsWith('DESede/CBC')) {
|
|
// https://stackoverflow.com/questions/29831300/convert-desede-ecb-nopadding-algorithm-written-in-java-into-nodejs-using-crypto
|
|
switch (key.length) {
|
|
case 16:
|
|
mode = 'des-ede-cbc';
|
|
break;
|
|
case 24:
|
|
mode = 'des-ede3-cbc';
|
|
break;
|
|
}
|
|
}
|
|
const inBuf = inBase64 ? base64DecodeBuf(input) : Buffer.from(input, 'utf8');
|
|
let keyBuf = Buffer.from(key);
|
|
if (keyBuf.length < 16) keyBuf = Buffer.concat([keyBuf], 16);
|
|
let ivBuf = iv == null ? Buffer.alloc(0) : Buffer.from(iv);
|
|
if (iv != null && ivBuf.length < 8) ivBuf = Buffer.concat([ivBuf], 8);
|
|
const cipher = encrypt ? crypto.createCipheriv(mode, keyBuf, ivBuf) : crypto.createDecipheriv(mode, keyBuf, ivBuf);
|
|
const outBuf = Buffer.concat([cipher.update(inBuf), cipher.final()]);
|
|
return outBase64 ? base64EncodeBuf(outBuf) : outBuf.toString('utf8');
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
// pkcs8 only
|
|
function rsa(mode, pub, encrypt, input, inBase64, key, outBase64) {
|
|
try {
|
|
let pd = undefined;
|
|
const keyObj = pub ? crypto.createPublicKey(key) : crypto.createPrivateKey(key);
|
|
if (!keyObj.asymmetricKeyDetails || !keyObj.asymmetricKeyDetails.modulusLength) return '';
|
|
const moduleLen = keyObj.asymmetricKeyDetails.modulusLength;
|
|
let blockLen = moduleLen / 8;
|
|
switch (mode) {
|
|
case 'RSA/PKCS1':
|
|
pd = crypto.constants.RSA_PKCS1_PADDING;
|
|
blockLen = encrypt ? blockLen - 11 : blockLen;
|
|
break;
|
|
case 'RSA/None/NoPadding':
|
|
pd = crypto.constants.RSA_NO_PADDING;
|
|
break;
|
|
case 'RSA/None/OAEPPadding':
|
|
pd = crypto.constants.RSA_PKCS1_OAEP_PADDING;
|
|
blockLen = encrypt ? blockLen - 41 : blockLen;
|
|
break;
|
|
default:
|
|
throw Error('not support ' + mode);
|
|
}
|
|
let inBuf = inBase64 ? base64DecodeBuf(input) : Buffer.from(input, 'utf8');
|
|
let bufIdx = 0;
|
|
let outBuf = Buffer.alloc(0);
|
|
while (bufIdx < inBuf.length) {
|
|
const bufEndIdx = Math.min(bufIdx + blockLen, inBuf.length);
|
|
let tmpInBuf = inBuf.subarray(bufIdx, bufEndIdx);
|
|
if (pd == crypto.constants.RSA_NO_PADDING) {
|
|
if (tmpInBuf.length < blockLen) {
|
|
tmpInBuf = Buffer.concat([Buffer.alloc(128 - tmpInBuf.length), tmpInBuf]);
|
|
}
|
|
}
|
|
let tmpBuf;
|
|
if (pub) {
|
|
tmpBuf = encrypt ? crypto.publicEncrypt({ key: keyObj, padding: pd }, tmpInBuf) : crypto.publicDecrypt({ key: keyObj, padding: pd }, tmpInBuf);
|
|
} else {
|
|
tmpBuf = encrypt ? crypto.privateEncrypt({ key: keyObj, padding: pd }, tmpInBuf) : crypto.privateDecrypt({ key: keyObj, padding: pd }, tmpInBuf);
|
|
}
|
|
bufIdx = bufEndIdx;
|
|
outBuf = Buffer.concat([outBuf, tmpBuf]);
|
|
}
|
|
return outBase64 ? base64EncodeBuf(outBuf) : outBuf.toString('utf8');
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
var charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
|
|
|
|
function randStr(len, withNum) {
|
|
var _str = '';
|
|
let containsNum = withNum === undefined ? true : withNum;
|
|
for (var i = 0; i < len; i++) {
|
|
let idx = _.random(0, containsNum ? charStr.length - 1 : charStr.length - 11);
|
|
_str += charStr[idx];
|
|
}
|
|
return _str;
|
|
}
|
|
|
|
globalThis.local = {
|
|
get: async function (storage, key) {
|
|
return localGet(storage, key);
|
|
},
|
|
set: async function (storage, key, val) {
|
|
localSet(storage, key, val);
|
|
},
|
|
};
|
|
|
|
globalThis.md5X = md5;
|
|
globalThis.rsaX = rsa;
|
|
globalThis.aesX = aes;
|
|
globalThis.desX = des;
|
|
|
|
globalThis.req = request;
|
|
|
|
globalThis.url2Proxy = async function (type, url, headers) {
|
|
let hd = Object.keys(headers).length == 0 ? '_' : encodeURIComponent(JSON.stringify(headers));
|
|
let uri = new Uri(url);
|
|
let path = uri.path();
|
|
path = path.substring(path.lastIndexOf('/'));
|
|
let ext = path.indexOf('.') >= 0 ? path.substring(path.indexOf('.')) : '.bin';
|
|
return 'http://127.0.0.1:13333/up/' + randStr(6) + '/' + type + '/' + hd + '/' + encodeURIComponent(url) + '/' + ext;
|
|
};
|
|
|
|
globalThis.js2Proxy = async function (dynamic, siteType, site, url, headers) {
|
|
let hd = Object.keys(headers).length == 0 ? '_' : encodeURIComponent(JSON.stringify(headers));
|
|
return (dynamic ? 'js2p://_WEB_/' : 'http://127.0.0.1:13333/jp/') + randStr(6) + '/' + siteType + '/' + site + '/' + hd + '/' + encodeURIComponent(url);
|
|
};
|
|
|
|
export default {};
|