From b3c2d4c3075cabdd39059cba7126d339321da533 Mon Sep 17 00:00:00 2001 From: Virgil Clyne Date: Mon, 26 Feb 2024 11:30:45 +0800 Subject: [PATCH] build(WeChat): rollup.js --- .gitignore | 144 +++ .gitmodules | 6 + js/WeChat.request.beta.js | 905 ++++++++++++++++++ js/WeChat.response.beta.js | 900 +++++++++++++++++ js/WeChat.response.js | 1 + js/{ => archive}/Fries.WeChat.request.beta.js | 0 .../Fries.WeChat.response.beta.js | 0 js/{ => archive}/Fries.WeChat.response.js | 0 modules/Fries.WeChat.beta.sgmodule | 2 +- modules/Fries.WeChat.sgmodule | 2 +- package-lock.json | 620 ++++++++++++ package.json | 29 + rollup.config.js | 9 + rollup.debug.config.js | 24 + rollup.default.config.js | 15 + src/ENV | 1 + src/URI | 1 + src/WeChat.request.beta.js | 193 ++++ src/WeChat.response.beta.js | 185 ++++ src/WeChat.response.js | 165 ++++ src/database/Default.json | 5 + src/database/WeChat.json | 5 + src/database/index.mjs | 7 + src/function/setENV.mjs | 19 + 24 files changed, 3236 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 js/WeChat.request.beta.js create mode 100644 js/WeChat.response.beta.js create mode 100644 js/WeChat.response.js rename js/{ => archive}/Fries.WeChat.request.beta.js (100%) rename js/{ => archive}/Fries.WeChat.response.beta.js (100%) rename js/{ => archive}/Fries.WeChat.response.js (100%) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 rollup.config.js create mode 100644 rollup.debug.config.js create mode 100644 rollup.default.config.js create mode 160000 src/ENV create mode 160000 src/URI create mode 100644 src/WeChat.request.beta.js create mode 100644 src/WeChat.response.beta.js create mode 100644 src/WeChat.response.js create mode 100644 src/database/Default.json create mode 100644 src/database/WeChat.json create mode 100644 src/database/index.mjs create mode 100644 src/function/setENV.mjs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3502ef7f --- /dev/null +++ b/.gitignore @@ -0,0 +1,144 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node +# Edit at https://www.toptal.com/developers/gitignore?templates=node + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +# End of https://www.toptal.com/developers/gitignore/api/node diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e736d3b3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "src/ENV"] + path = src/ENV + url = https://github.com/NanoCat-Me/ENV.git +[submodule "src/URI"] + path = src/URI + url = https://github.com/NanoCat-Me/URI.git diff --git a/js/WeChat.request.beta.js b/js/WeChat.request.beta.js new file mode 100644 index 00000000..45ecf47b --- /dev/null +++ b/js/WeChat.request.beta.js @@ -0,0 +1,905 @@ +/* README: https://github.com/VirgilClyne/GetSomeFries */ +class Lodash { + constructor() { + this.name = "Lodash"; + this.version = '1.0.0'; + console.log(`\n${this.name} v${this.version}\n`); + } + + get(object = {}, path = "", defaultValue = undefined) { + // translate array case to dot case, then split with . + // a[0].b -> a.0.b -> ['a', '0', 'b'] + if (!Array.isArray(path)) path = this.toPath(path); + + const result = path.reduce((previousValue, currentValue) => { + return Object(previousValue)[currentValue]; // null undefined get attribute will throwError, Object() can return a object + }, object); + return (result === undefined) ? defaultValue : result; + } + + set(object = {}, path = "", value) { + if (!Array.isArray(path)) path = this.toPath(path); + path + .slice(0, -1) + .reduce( + (previousValue, currentValue, currentIndex) => + (Object(previousValue[currentValue]) === previousValue[currentValue]) + ? previousValue[currentValue] + : previousValue[currentValue] = (/^\d+$/.test(path[currentIndex + 1]) ? [] : {}), + object + )[path[path.length - 1]] = value; + return object + } + + toPath(value) { + return value.replace(/\[(\d+)\]/g, '.$1').split('.').filter(Boolean); + } + +} + +class ENV { + constructor(name, opts) { + this.name = name; + this.version = '1.4.1'; + this.data = null; + this.dataFile = 'box.dat'; + this.logs = []; + this.isMute = false; + this.logSeparator = '\n'; + this.encoding = 'utf-8'; + this.startTime = new Date().getTime(); + Object.assign(this, opts); + this.log('', '🚩 开始!', `ENV v${this.version}`, ''); + this.lodash = new Lodash(this.name); + this.log('', this.name, ''); + } + + platform() { + if ('undefined' !== typeof $environment && $environment['surge-version']) + return 'Surge' + if ('undefined' !== typeof $environment && $environment['stash-version']) + return 'Stash' + if ('undefined' !== typeof module && !!module.exports) return 'Node.js' + if ('undefined' !== typeof $task) return 'Quantumult X' + if ('undefined' !== typeof $loon) return 'Loon' + if ('undefined' !== typeof $rocket) return 'Shadowrocket' + if ('undefined' !== typeof Egern) return 'Egern' + } + + isNode() { + return 'Node.js' === this.platform() + } + + isQuanX() { + return 'Quantumult X' === this.platform() + } + + isSurge() { + return 'Surge' === this.platform() + } + + isLoon() { + return 'Loon' === this.platform() + } + + isShadowrocket() { + return 'Shadowrocket' === this.platform() + } + + isStash() { + return 'Stash' === this.platform() + } + + isEgern() { + return 'Egern' === this.platform() + } + + toObj(str, defaultValue = null) { + try { + return JSON.parse(str) + } catch { + return defaultValue + } + } + + toStr(obj, defaultValue = null) { + try { + return JSON.stringify(obj) + } catch { + return defaultValue + } + } + + getjson(key, defaultValue) { + let json = defaultValue; + const val = this.getdata(key); + if (val) { + try { + json = JSON.parse(this.getdata(key)); + } catch { } + } + return json + } + + setjson(val, key) { + try { + return this.setdata(JSON.stringify(val), key) + } catch { + return false + } + } + + getScript(url) { + return new Promise((resolve) => { + this.get({ url }, (error, response, body) => resolve(body)); + }) + } + + runScript(script, runOpts) { + return new Promise((resolve) => { + let httpapi = this.getdata('@chavy_boxjs_userCfgs.httpapi'); + httpapi = httpapi ? httpapi.replace(/\n/g, '').trim() : httpapi; + let httpapi_timeout = this.getdata( + '@chavy_boxjs_userCfgs.httpapi_timeout' + ); + httpapi_timeout = httpapi_timeout ? httpapi_timeout * 1 : 20; + httpapi_timeout = + runOpts && runOpts.timeout ? runOpts.timeout : httpapi_timeout; + const [key, addr] = httpapi.split('@'); + const opts = { + url: `http://${addr}/v1/scripting/evaluate`, + body: { + script_text: script, + mock_type: 'cron', + timeout: httpapi_timeout + }, + headers: { 'X-Key': key, 'Accept': '*/*' }, + timeout: httpapi_timeout + }; + this.post(opts, (error, response, body) => resolve(body)); + }).catch((e) => this.logErr(e)) + } + + loaddata() { + if (this.isNode()) { + this.fs = this.fs ? this.fs : require('fs'); + this.path = this.path ? this.path : require('path'); + const curDirDataFilePath = this.path.resolve(this.dataFile); + const rootDirDataFilePath = this.path.resolve( + process.cwd(), + this.dataFile + ); + const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath); + const isRootDirDataFile = + !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath); + if (isCurDirDataFile || isRootDirDataFile) { + const datPath = isCurDirDataFile + ? curDirDataFilePath + : rootDirDataFilePath; + try { + return JSON.parse(this.fs.readFileSync(datPath)) + } catch (e) { + return {} + } + } else return {} + } else return {} + } + + writedata() { + if (this.isNode()) { + this.fs = this.fs ? this.fs : require('fs'); + this.path = this.path ? this.path : require('path'); + const curDirDataFilePath = this.path.resolve(this.dataFile); + const rootDirDataFilePath = this.path.resolve( + process.cwd(), + this.dataFile + ); + const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath); + const isRootDirDataFile = + !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath); + const jsondata = JSON.stringify(this.data); + if (isCurDirDataFile) { + this.fs.writeFileSync(curDirDataFilePath, jsondata); + } else if (isRootDirDataFile) { + this.fs.writeFileSync(rootDirDataFilePath, jsondata); + } else { + this.fs.writeFileSync(curDirDataFilePath, jsondata); + } + } + } + getdata(key) { + let val = this.getval(key); + // 如果以 @ + if (/^@/.test(key)) { + const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key); + const objval = objkey ? this.getval(objkey) : ''; + if (objval) { + try { + const objedval = JSON.parse(objval); + val = objedval ? this.lodash.get(objedval, paths, '') : val; + } catch (e) { + val = ''; + } + } + } + return val + } + + setdata(val, key) { + let issuc = false; + if (/^@/.test(key)) { + const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key); + const objdat = this.getval(objkey); + const objval = objkey + ? objdat === 'null' + ? null + : objdat || '{}' + : '{}'; + try { + const objedval = JSON.parse(objval); + this.lodash.set(objedval, paths, val); + issuc = this.setval(JSON.stringify(objedval), objkey); + } catch (e) { + const objedval = {}; + this.lodash.set(objedval, paths, val); + issuc = this.setval(JSON.stringify(objedval), objkey); + } + } else { + issuc = this.setval(val, key); + } + return issuc + } + + getval(key) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + return $persistentStore.read(key) + case 'Quantumult X': + return $prefs.valueForKey(key) + case 'Node.js': + this.data = this.loaddata(); + return this.data[key] + default: + return (this.data && this.data[key]) || null + } + } + + setval(val, key) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + return $persistentStore.write(val, key) + case 'Quantumult X': + return $prefs.setValueForKey(val, key) + case 'Node.js': + this.data = this.loaddata(); + this.data[key] = val; + this.writedata(); + return true + default: + return (this.data && this.data[key]) || null + } + } + + initGotEnv(opts) { + this.got = this.got ? this.got : require('got'); + this.cktough = this.cktough ? this.cktough : require('tough-cookie'); + this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar(); + if (opts) { + opts.headers = opts.headers ? opts.headers : {}; + if (undefined === opts.headers.Cookie && undefined === opts.cookieJar) { + opts.cookieJar = this.ckjar; + } + } + } + + async fetch(request = {} || "", option = {}) { + switch (request.constructor) { + case Object: + request = { ...request, ...option }; + break; + case String: + request = { "url": request, ...option }; + break; + } if (!request.method) { + request.method = "GET"; + if (request.body ?? request.bodyBytes) request.method = "POST"; + } delete request.headers?.['Content-Length']; + delete request.headers?.['content-length']; + const method = request.method.toLocaleLowerCase(); + switch (this.platform()) { + case 'Loon': + case 'Surge': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + default: + // 移除不可写字段 + delete request.id; + // 添加策略组 + if (request.policy) { + if (this.isLoon()) request.node = request.policy; + if (this.isStash()) this.lodash.set(request, "headers.X-Stash-Selected-Proxy", encodeURI(request.policy)); + } // 判断请求数据类型 + if (ArrayBuffer.isView(request.body)) request["binary-mode"] = true; + // 发送请求 + return await new Promise((resolve, reject) => { + $httpClient[method](request, (error, response, body) => { + if (error) reject(error); + else { + response.ok = /^2\d\d$/.test(response.status); + response.statusCode = response.status; + if (body) { + response.body = body; + if (request["binary-mode"] == true) response.bodyBytes = body; + } resolve(response); + } + }); + }); + case 'Quantumult X': + // 移除不可写字段 + delete request.scheme; + delete request.sessionIndex; + delete request.charset; + // 添加策略组 + if (request.policy) this.lodash.set(request, "opts.policy", request.policy); + // 判断请求数据类型 + switch ((request?.headers?.["Content-Type"] ?? request?.headers?.["content-type"])?.split(";")?.[0]) { + default: + // 返回普通数据 + delete request.bodyBytes; + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + // 返回二进制数据 + delete request.body; + if (ArrayBuffer.isView(request.bodyBytes)) request.bodyBytes = request.bodyBytes.buffer.slice(request.bodyBytes.byteOffset, request.bodyBytes.byteLength + request.bodyBytes.byteOffset); + break; + case undefined: // 视为构造请求或无body + // 返回普通数据 + break; + } // 发送请求 + return await $task.fetch(request).then( + response => { + response.ok = /^2\d\d$/.test(response.statusCode); + response.status = response.statusCode; + return response; + }, + reason => Promise.reject(reason.error)); + case 'Node.js': + let iconv = require('iconv-lite'); + this.initGotEnv(request); + const { url, ...option } = request; + return await this.got[method](url, option) + .on('redirect', (response, nextOpts) => { + try { + if (response.headers['set-cookie']) { + const ck = response.headers['set-cookie'] + .map(this.cktough.Cookie.parse) + .toString(); + if (ck) { + this.ckjar.setCookieSync(ck, null); + } + nextOpts.cookieJar = this.ckjar; + } + } catch (e) { + this.logErr(e); + } + // this.ckjar.setCookieSync(response.headers['set-cookie'].map(Cookie.parse).toString()) + }) + .then( + response => { + response.statusCode = response.status; + response.body = iconv.decode(response.rawBody, this.encoding); + response.bodyBytes = response.rawBody; + return response; + }, + error => Promise.reject(error.message)); + } }; + + /** + * + * 示例:$.time('yyyy-MM-dd qq HH:mm:ss.S') + * :$.time('yyyyMMddHHmmssS') + * y:年 M:月 d:日 q:季 H:时 m:分 s:秒 S:毫秒 + * 其中y可选0-4位占位符、S可选0-1位占位符,其余可选0-2位占位符 + * @param {string} format 格式化参数 + * @param {number} ts 可选: 根据指定时间戳返回格式化日期 + * + */ + time(format, ts = null) { + const date = ts ? new Date(ts) : new Date(); + let o = { + 'M+': date.getMonth() + 1, + 'd+': date.getDate(), + 'H+': date.getHours(), + 'm+': date.getMinutes(), + 's+': date.getSeconds(), + 'q+': Math.floor((date.getMonth() + 3) / 3), + 'S': date.getMilliseconds() + }; + if (/(y+)/.test(format)) + format = format.replace( + RegExp.$1, + (date.getFullYear() + '').substr(4 - RegExp.$1.length) + ); + for (let k in o) + if (new RegExp('(' + k + ')').test(format)) + format = format.replace( + RegExp.$1, + RegExp.$1.length == 1 + ? o[k] + : ('00' + o[k]).substr(('' + o[k]).length) + ); + return format + } + + /** + * 系统通知 + * + * > 通知参数: 同时支持 QuanX 和 Loon 两种格式, EnvJs根据运行环境自动转换, Surge 环境不支持多媒体通知 + * + * 示例: + * $.msg(title, subt, desc, 'twitter://') + * $.msg(title, subt, desc, { 'open-url': 'twitter://', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' }) + * $.msg(title, subt, desc, { 'open-url': 'https://bing.com', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' }) + * + * @param {*} title 标题 + * @param {*} subt 副标题 + * @param {*} desc 通知详情 + * @param {*} opts 通知参数 + * + */ + msg(title = name, subt = '', desc = '', opts) { + const toEnvOpts = (rawopts) => { + switch (typeof rawopts) { + case undefined: + return rawopts + case 'string': + switch (this.platform()) { + case 'Surge': + case 'Stash': + case 'Egern': + default: + return { url: rawopts } + case 'Loon': + case 'Shadowrocket': + return rawopts + case 'Quantumult X': + return { 'open-url': rawopts } + case 'Node.js': + return undefined + } + case 'object': + switch (this.platform()) { + case 'Surge': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + default: { + let openUrl = + rawopts.url || rawopts.openUrl || rawopts['open-url']; + return { url: openUrl } + } + case 'Loon': { + let openUrl = + rawopts.openUrl || rawopts.url || rawopts['open-url']; + let mediaUrl = rawopts.mediaUrl || rawopts['media-url']; + return { openUrl, mediaUrl } + } + case 'Quantumult X': { + let openUrl = + rawopts['open-url'] || rawopts.url || rawopts.openUrl; + let mediaUrl = rawopts['media-url'] || rawopts.mediaUrl; + let updatePasteboard = + rawopts['update-pasteboard'] || rawopts.updatePasteboard; + return { + 'open-url': openUrl, + 'media-url': mediaUrl, + 'update-pasteboard': updatePasteboard + } + } + case 'Node.js': + return undefined + } + default: + return undefined + } + }; + if (!this.isMute) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + default: + $notification.post(title, subt, desc, toEnvOpts(opts)); + break + case 'Quantumult X': + $notify(title, subt, desc, toEnvOpts(opts)); + break + case 'Node.js': + break + } + } + if (!this.isMuteLog) { + let logs = ['', '==============📣系统通知📣==============']; + logs.push(title); + subt ? logs.push(subt) : ''; + desc ? logs.push(desc) : ''; + console.log(logs.join('\n')); + this.logs = this.logs.concat(logs); + } + } + + log(...logs) { + if (logs.length > 0) { + this.logs = [...this.logs, ...logs]; + } + console.log(logs.join(this.logSeparator)); + } + + logErr(error) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + case 'Quantumult X': + default: + this.log('', `❗️ ${this.name}, 错误!`, error); + break + case 'Node.js': + this.log('', `❗️${this.name}, 错误!`, error.stack); + break + } + } + + wait(time) { + return new Promise((resolve) => setTimeout(resolve, time)) + } + + done(val = {}) { + const endTime = new Date().getTime(); + const costTime = (endTime - this.startTime) / 1000; + this.log('', `🚩 ${this.name}, 结束! 🕛 ${costTime} 秒`); + this.log(); + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + case 'Quantumult X': + default: + $done(val); + break + case 'Node.js': + process.exit(1); + break + } + } + + /** + * Get Environment Variables + * @link https://github.com/VirgilClyne/GetSomeFries/blob/main/function/getENV/getENV.js + * @author VirgilClyne + * @param {String} key - Persistent Store Key + * @param {Array} names - Platform Names + * @param {Object} database - Default Database + * @return {Object} { Settings, Caches, Configs } + */ + getENV(key, names, database) { + //this.log(`☑️ ${this.name}, Get Environment Variables`, ""); + /***************** BoxJs *****************/ + // 包装为局部变量,用完释放内存 + // BoxJs的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。 + let BoxJs = this.getjson(key, database); + //this.log(`🚧 ${this.name}, Get Environment Variables`, `BoxJs类型: ${typeof BoxJs}`, `BoxJs内容: ${JSON.stringify(BoxJs)}`, ""); + /***************** Argument *****************/ + let Argument = {}; + if (typeof $argument !== "undefined") { + if (Boolean($argument)) { + //this.log(`🎉 ${this.name}, $Argument`); + let arg = Object.fromEntries($argument.split("&").map((item) => item.split("=").map(i => i.replace(/\"/g, '')))); + //this.log(JSON.stringify(arg)); + for (let item in arg) this.lodash.set(Argument, item, arg[item]); + //this.log(JSON.stringify(Argument)); + } //this.log(`✅ ${this.name}, Get Environment Variables`, `Argument类型: ${typeof Argument}`, `Argument内容: ${JSON.stringify(Argument)}`, ""); + } /***************** Store *****************/ + const Store = { Settings: database?.Default?.Settings || {}, Configs: database?.Default?.Configs || {}, Caches: {} }; + if (!Array.isArray(names)) names = [names]; + //this.log(`🚧 ${this.name}, Get Environment Variables`, `names类型: ${typeof names}`, `names内容: ${JSON.stringify(names)}`, ""); + for (let name of names) { + Store.Settings = { ...Store.Settings, ...database?.[name]?.Settings, ...Argument, ...BoxJs?.[name]?.Settings }; + Store.Configs = { ...Store.Configs, ...database?.[name]?.Configs }; + if (BoxJs?.[name]?.Caches && typeof BoxJs?.[name]?.Caches === "string") BoxJs[name].Caches = JSON.parse(BoxJs?.[name]?.Caches); + Store.Caches = { ...Store.Caches, ...BoxJs?.[name]?.Caches }; + } //this.log(`🚧 ${this.name}, Get Environment Variables`, `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`, ""); + this.traverseObject(Store.Settings, (key, value) => { + //this.log(`🚧 ${this.name}, traverseObject`, `${key}: ${typeof value}`, `${key}: ${JSON.stringify(value)}`, ""); + if (value === "true" || value === "false") value = JSON.parse(value); // 字符串转Boolean + else if (typeof value === "string") { + if (value.includes(",")) value = value.split(",").map(item => this.string2number(item)); // 字符串转数组转数字 + else value = this.string2number(value); // 字符串转数字 + } return value; + }); + //this.log(`✅ ${this.name}, Get Environment Variables`, `Store: ${typeof Store.Caches}`, `Store内容: ${JSON.stringify(Store)}`, ""); + return Store; + }; + + /***************** function *****************/ + traverseObject(o, c) { for (var t in o) { var n = o[t]; o[t] = "object" == typeof n && null !== n ? this.traverseObject(n, c) : c(t, n); } return o } + string2number(string) { if (string && !isNaN(string)) string = parseInt(string, 10); return string } +} + +let URI$1 = class URI { + constructor(opts = []) { + this.name = "URI v1.2.6"; + this.opts = opts; + this.json = { scheme: "", host: "", path: "", query: {} }; + }; + + parse(url) { + const URLRegex = /(?:(?.+):\/\/(?[^/]+))?\/?(?[^?]+)?\??(?[^?]+)?/; + let json = url.match(URLRegex)?.groups ?? null; + if (json?.path) json.paths = json.path.split("/"); else json.path = ""; + //if (json?.paths?.at(-1)?.includes(".")) json.format = json.paths.at(-1).split(".").at(-1); + if (json?.paths) { + const fileName = json.paths[json.paths.length - 1]; + if (fileName?.includes(".")) { + const list = fileName.split("."); + json.format = list[list.length - 1]; + } + } + if (json?.query) json.query = Object.fromEntries(json.query.split("&").map((param) => param.split("="))); + return json + }; + + stringify(json = this.json) { + let url = ""; + if (json?.scheme && json?.host) url += json.scheme + "://" + json.host; + if (json?.path) url += (json?.host) ? "/" + json.path : json.path; + if (json?.query) url += "?" + Object.entries(json.query).map(param => param.join("=")).join("&"); + return url + }; +}; + +var Settings$1 = { + Switch: true +}; +var Default = { + Settings: Settings$1 +}; + +var Default$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + Settings: Settings$1, + default: Default +}); + +var Settings = { + Switch: true +}; +var WeChat = { + Settings: Settings +}; + +var WeChat$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + Settings: Settings, + default: WeChat +}); + +var Database$1 = Database = { + "Default": Default$1, + "WeChat": WeChat$1, +}; + +/** + * Set Environment Variables + * @author VirgilClyne + * @param {Object} $ - ENV + * @param {String} name - Persistent Store Key + * @param {Array} platforms - Platform Names + * @param {Object} database - Default DataBase + * @return {Object} { Settings, Caches, Configs } + */ +function setENV($, name, platforms, database) { + console.log(`☑️ Set Environment Variables`, ""); + let { Settings, Caches, Configs } = $.getENV(name, platforms, database); + /***************** Settings *****************/ + console.log(`✅ Set Environment Variables, Settings: ${typeof Settings}, Settings内容: ${JSON.stringify(Settings)}`, ""); + /***************** Caches *****************/ + //console.log(`✅ ${$.name}, Set Environment Variables`, `Caches: ${typeof Caches}`, `Caches内容: ${JSON.stringify(Caches)}`, ""); + /***************** Configs *****************/ + return { Settings, Caches, Configs }; +} + +const $ = new ENV("🍟 GetSomeFries: WeChat v0.1.2(1) request.beta"); +const URI = new URI$1(); + +// 构造回复数据 +let $response = undefined; + +/***************** Processing *****************/ +// 解构URL +const URL = URI.parse($request.url); +$.log(`⚠ URL: ${JSON.stringify(URL)}`, ""); +// 获取连接参数 +const METHOD = $request.method; URL.host; const PATH = URL.path; URL.paths; +$.log(`⚠ METHOD: ${METHOD}`, ""); +// 解析格式 +const FORMAT = ($request.headers?.["Content-Type"] ?? $request.headers?.["content-type"])?.split(";")?.[0]; +$.log(`⚠ FORMAT: ${FORMAT}`, ""); +(async () => { + const { Settings, Caches, Configs } = setENV($, "GetSomeFries", "WeChat", Database$1); + $.log(`⚠ ${$.name}`, `Settings.Switch: ${Settings?.Switch}`, ""); + switch (Settings.Switch) { + case true: + default: + // 创建空数据 + let body = {}; + // 方法判断 + switch (METHOD) { + case "POST": + case "PUT": + case "PATCH": + case "DELETE": + // 格式判断 + switch (FORMAT) { + case undefined: // 视为无body + break; + case "application/x-www-form-urlencoded": + case "text/plain": + default: + break; + case "application/x-mpegURL": + case "application/x-mpegurl": + case "application/vnd.apple.mpegurl": + case "audio/mpegurl": + //body = M3U8.parse($request.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = M3U8.stringify(body); + break; + case "text/xml": + case "text/html": + case "text/plist": + case "application/xml": + case "application/plist": + case "application/x-plist": + body = new DOMParser().parseFromString($response.body, FORMAT); + // 路径判断 + switch (PATH) { + case "cgi-bin/mmsupport-bin/readtemplate": + $.log(body); + break; + case "cgi-bin/mmspamsupport-bin/newredirectconfirmcgi": + $.log(body); + break; + } $response.body = new XMLSerializer().serializeToString(body); + break; + case "text/vtt": + case "application/vtt": + //body = VTT.parse($request.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = VTT.stringify(body); + break; + case "text/json": + case "application/json": + //body = JSON.parse($request.body ?? "{}"); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = JSON.stringify(body); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + break; + } //break; // 不中断,继续处理URL + case "GET": + case "HEAD": + case "OPTIONS": + case undefined: // QX牛逼,script-echo-response不返回method + default: + let newURL = {}; + // 路径判断 + switch (PATH) { + case "cgi-bin/mmsupport-bin/readtemplate": + if (URL.query?.url) newURL = URI.parse(decodeURIComponent(URL.query.url)); + break; + case "cgi-bin/mmspamsupport-bin/newredirectconfirmcgi": + if (URL.query?.url) newURL = URI.parse(decodeURIComponent(URL.query.url)); + //$request.url = "https://mp.weixin.qq.com/mp/spredirect?url=" + body?.redirect_url; + break; + } URI.scheme = newURL?.scheme ?? URI.scheme ?? "https"; + URI.host = newURL?.host ?? URI.host ?? "mp.weixin.qq.com"; + URI.path = newURL?.path ?? URI.path ?? "/mp/spredirect"; + URI.query = newURL?.query ?? URL.query ?? {}; + break; + case "CONNECT": + case "TRACE": + break; + } if ($request.headers?.Host) $request.headers.Host = URL.host; + $request.url = URI.stringify(URL); + $.log(`🚧 ${$.name}, 调试信息`, `$request.url: ${$request.url}`, ""); + break; + case false: + break; + }})() + .catch((e) => $.logErr(e)) + .finally(() => { + switch ($response) { + default: { // 有构造回复数据,返回构造的回复数据 + const FORMAT = ($response?.headers?.["content-type"])?.split(";")?.[0]; + $.log(`🎉 ${$.name}, finally`, `echo $response`, `FORMAT: ${FORMAT}`, ""); + if ($.isQuanX()) { + $response.status = "HTTP/1.1 200 OK"; + delete $response?.headers?.["Content-Length"]; + delete $response?.headers?.["content-length"]; + delete $response?.headers?.["Transfer-Encoding"]; + switch (FORMAT) { + case undefined: // 视为无body + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers }); + break; + default: + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers, body: $response.body }); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + // 返回二进制数据 + //$.log(`${$response.bodyBytes.byteLength}---${$response.bodyBytes.buffer.byteLength}`); + $.done({ status: $response.status, headers: $response.headers, bodyBytes: $response.bodyBytes }); + break; + } } else $.done({ response: $response }); + break; + } case undefined: { // 无构造回复数据,发送修改的请求数据 + //const FORMAT = ($request?.headers?.["Content-Type"] ?? $request?.headers?.["content-type"])?.split(";")?.[0]; + $.log(`🎉 ${$.name}, finally`, `$request`, `FORMAT: ${FORMAT}`, ""); + //$.log(`🚧 ${$.name}, finally`, `$request: ${JSON.stringify($request)}`, ""); + if ($.isQuanX()) { + switch (FORMAT) { + case undefined: // 视为无body + // 返回普通数据 + $.done({ url: $request.url, headers: $request.headers }); + break; + default: + // 返回普通数据 + $.done({ url: $request.url, headers: $request.headers, body: $request.body }); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "applecation/octet-stream": + // 返回二进制数据 + //$.log(`${$request.bodyBytes.byteLength}---${$request.bodyBytes.buffer.byteLength}`); + $.done({ url: $request.url, headers: $request.headers, bodyBytes: $request.bodyBytes.buffer.slice($request.bodyBytes.byteOffset, $request.bodyBytes.byteLength + $request.bodyBytes.byteOffset) }); + break; + } } else $.done($request); + break; + } } }); + +/***************** Function *****************/ diff --git a/js/WeChat.response.beta.js b/js/WeChat.response.beta.js new file mode 100644 index 00000000..d3d64027 --- /dev/null +++ b/js/WeChat.response.beta.js @@ -0,0 +1,900 @@ +/* README: https://github.com/VirgilClyne/GetSomeFries */ +class Lodash { + constructor() { + this.name = "Lodash"; + this.version = '1.0.0'; + console.log(`\n${this.name} v${this.version}\n`); + } + + get(object = {}, path = "", defaultValue = undefined) { + // translate array case to dot case, then split with . + // a[0].b -> a.0.b -> ['a', '0', 'b'] + if (!Array.isArray(path)) path = this.toPath(path); + + const result = path.reduce((previousValue, currentValue) => { + return Object(previousValue)[currentValue]; // null undefined get attribute will throwError, Object() can return a object + }, object); + return (result === undefined) ? defaultValue : result; + } + + set(object = {}, path = "", value) { + if (!Array.isArray(path)) path = this.toPath(path); + path + .slice(0, -1) + .reduce( + (previousValue, currentValue, currentIndex) => + (Object(previousValue[currentValue]) === previousValue[currentValue]) + ? previousValue[currentValue] + : previousValue[currentValue] = (/^\d+$/.test(path[currentIndex + 1]) ? [] : {}), + object + )[path[path.length - 1]] = value; + return object + } + + toPath(value) { + return value.replace(/\[(\d+)\]/g, '.$1').split('.').filter(Boolean); + } + +} + +class ENV { + constructor(name, opts) { + this.name = name; + this.version = '1.4.1'; + this.data = null; + this.dataFile = 'box.dat'; + this.logs = []; + this.isMute = false; + this.logSeparator = '\n'; + this.encoding = 'utf-8'; + this.startTime = new Date().getTime(); + Object.assign(this, opts); + this.log('', '🚩 开始!', `ENV v${this.version}`, ''); + this.lodash = new Lodash(this.name); + this.log('', this.name, ''); + } + + platform() { + if ('undefined' !== typeof $environment && $environment['surge-version']) + return 'Surge' + if ('undefined' !== typeof $environment && $environment['stash-version']) + return 'Stash' + if ('undefined' !== typeof module && !!module.exports) return 'Node.js' + if ('undefined' !== typeof $task) return 'Quantumult X' + if ('undefined' !== typeof $loon) return 'Loon' + if ('undefined' !== typeof $rocket) return 'Shadowrocket' + if ('undefined' !== typeof Egern) return 'Egern' + } + + isNode() { + return 'Node.js' === this.platform() + } + + isQuanX() { + return 'Quantumult X' === this.platform() + } + + isSurge() { + return 'Surge' === this.platform() + } + + isLoon() { + return 'Loon' === this.platform() + } + + isShadowrocket() { + return 'Shadowrocket' === this.platform() + } + + isStash() { + return 'Stash' === this.platform() + } + + isEgern() { + return 'Egern' === this.platform() + } + + toObj(str, defaultValue = null) { + try { + return JSON.parse(str) + } catch { + return defaultValue + } + } + + toStr(obj, defaultValue = null) { + try { + return JSON.stringify(obj) + } catch { + return defaultValue + } + } + + getjson(key, defaultValue) { + let json = defaultValue; + const val = this.getdata(key); + if (val) { + try { + json = JSON.parse(this.getdata(key)); + } catch { } + } + return json + } + + setjson(val, key) { + try { + return this.setdata(JSON.stringify(val), key) + } catch { + return false + } + } + + getScript(url) { + return new Promise((resolve) => { + this.get({ url }, (error, response, body) => resolve(body)); + }) + } + + runScript(script, runOpts) { + return new Promise((resolve) => { + let httpapi = this.getdata('@chavy_boxjs_userCfgs.httpapi'); + httpapi = httpapi ? httpapi.replace(/\n/g, '').trim() : httpapi; + let httpapi_timeout = this.getdata( + '@chavy_boxjs_userCfgs.httpapi_timeout' + ); + httpapi_timeout = httpapi_timeout ? httpapi_timeout * 1 : 20; + httpapi_timeout = + runOpts && runOpts.timeout ? runOpts.timeout : httpapi_timeout; + const [key, addr] = httpapi.split('@'); + const opts = { + url: `http://${addr}/v1/scripting/evaluate`, + body: { + script_text: script, + mock_type: 'cron', + timeout: httpapi_timeout + }, + headers: { 'X-Key': key, 'Accept': '*/*' }, + timeout: httpapi_timeout + }; + this.post(opts, (error, response, body) => resolve(body)); + }).catch((e) => this.logErr(e)) + } + + loaddata() { + if (this.isNode()) { + this.fs = this.fs ? this.fs : require('fs'); + this.path = this.path ? this.path : require('path'); + const curDirDataFilePath = this.path.resolve(this.dataFile); + const rootDirDataFilePath = this.path.resolve( + process.cwd(), + this.dataFile + ); + const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath); + const isRootDirDataFile = + !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath); + if (isCurDirDataFile || isRootDirDataFile) { + const datPath = isCurDirDataFile + ? curDirDataFilePath + : rootDirDataFilePath; + try { + return JSON.parse(this.fs.readFileSync(datPath)) + } catch (e) { + return {} + } + } else return {} + } else return {} + } + + writedata() { + if (this.isNode()) { + this.fs = this.fs ? this.fs : require('fs'); + this.path = this.path ? this.path : require('path'); + const curDirDataFilePath = this.path.resolve(this.dataFile); + const rootDirDataFilePath = this.path.resolve( + process.cwd(), + this.dataFile + ); + const isCurDirDataFile = this.fs.existsSync(curDirDataFilePath); + const isRootDirDataFile = + !isCurDirDataFile && this.fs.existsSync(rootDirDataFilePath); + const jsondata = JSON.stringify(this.data); + if (isCurDirDataFile) { + this.fs.writeFileSync(curDirDataFilePath, jsondata); + } else if (isRootDirDataFile) { + this.fs.writeFileSync(rootDirDataFilePath, jsondata); + } else { + this.fs.writeFileSync(curDirDataFilePath, jsondata); + } + } + } + getdata(key) { + let val = this.getval(key); + // 如果以 @ + if (/^@/.test(key)) { + const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key); + const objval = objkey ? this.getval(objkey) : ''; + if (objval) { + try { + const objedval = JSON.parse(objval); + val = objedval ? this.lodash.get(objedval, paths, '') : val; + } catch (e) { + val = ''; + } + } + } + return val + } + + setdata(val, key) { + let issuc = false; + if (/^@/.test(key)) { + const [, objkey, paths] = /^@(.*?)\.(.*?)$/.exec(key); + const objdat = this.getval(objkey); + const objval = objkey + ? objdat === 'null' + ? null + : objdat || '{}' + : '{}'; + try { + const objedval = JSON.parse(objval); + this.lodash.set(objedval, paths, val); + issuc = this.setval(JSON.stringify(objedval), objkey); + } catch (e) { + const objedval = {}; + this.lodash.set(objedval, paths, val); + issuc = this.setval(JSON.stringify(objedval), objkey); + } + } else { + issuc = this.setval(val, key); + } + return issuc + } + + getval(key) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + return $persistentStore.read(key) + case 'Quantumult X': + return $prefs.valueForKey(key) + case 'Node.js': + this.data = this.loaddata(); + return this.data[key] + default: + return (this.data && this.data[key]) || null + } + } + + setval(val, key) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + return $persistentStore.write(val, key) + case 'Quantumult X': + return $prefs.setValueForKey(val, key) + case 'Node.js': + this.data = this.loaddata(); + this.data[key] = val; + this.writedata(); + return true + default: + return (this.data && this.data[key]) || null + } + } + + initGotEnv(opts) { + this.got = this.got ? this.got : require('got'); + this.cktough = this.cktough ? this.cktough : require('tough-cookie'); + this.ckjar = this.ckjar ? this.ckjar : new this.cktough.CookieJar(); + if (opts) { + opts.headers = opts.headers ? opts.headers : {}; + if (undefined === opts.headers.Cookie && undefined === opts.cookieJar) { + opts.cookieJar = this.ckjar; + } + } + } + + async fetch(request = {} || "", option = {}) { + switch (request.constructor) { + case Object: + request = { ...request, ...option }; + break; + case String: + request = { "url": request, ...option }; + break; + } if (!request.method) { + request.method = "GET"; + if (request.body ?? request.bodyBytes) request.method = "POST"; + } delete request.headers?.['Content-Length']; + delete request.headers?.['content-length']; + const method = request.method.toLocaleLowerCase(); + switch (this.platform()) { + case 'Loon': + case 'Surge': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + default: + // 移除不可写字段 + delete request.id; + // 添加策略组 + if (request.policy) { + if (this.isLoon()) request.node = request.policy; + if (this.isStash()) this.lodash.set(request, "headers.X-Stash-Selected-Proxy", encodeURI(request.policy)); + } // 判断请求数据类型 + if (ArrayBuffer.isView(request.body)) request["binary-mode"] = true; + // 发送请求 + return await new Promise((resolve, reject) => { + $httpClient[method](request, (error, response, body) => { + if (error) reject(error); + else { + response.ok = /^2\d\d$/.test(response.status); + response.statusCode = response.status; + if (body) { + response.body = body; + if (request["binary-mode"] == true) response.bodyBytes = body; + } resolve(response); + } + }); + }); + case 'Quantumult X': + // 移除不可写字段 + delete request.scheme; + delete request.sessionIndex; + delete request.charset; + // 添加策略组 + if (request.policy) this.lodash.set(request, "opts.policy", request.policy); + // 判断请求数据类型 + switch ((request?.headers?.["Content-Type"] ?? request?.headers?.["content-type"])?.split(";")?.[0]) { + default: + // 返回普通数据 + delete request.bodyBytes; + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + // 返回二进制数据 + delete request.body; + if (ArrayBuffer.isView(request.bodyBytes)) request.bodyBytes = request.bodyBytes.buffer.slice(request.bodyBytes.byteOffset, request.bodyBytes.byteLength + request.bodyBytes.byteOffset); + break; + case undefined: // 视为构造请求或无body + // 返回普通数据 + break; + } // 发送请求 + return await $task.fetch(request).then( + response => { + response.ok = /^2\d\d$/.test(response.statusCode); + response.status = response.statusCode; + return response; + }, + reason => Promise.reject(reason.error)); + case 'Node.js': + let iconv = require('iconv-lite'); + this.initGotEnv(request); + const { url, ...option } = request; + return await this.got[method](url, option) + .on('redirect', (response, nextOpts) => { + try { + if (response.headers['set-cookie']) { + const ck = response.headers['set-cookie'] + .map(this.cktough.Cookie.parse) + .toString(); + if (ck) { + this.ckjar.setCookieSync(ck, null); + } + nextOpts.cookieJar = this.ckjar; + } + } catch (e) { + this.logErr(e); + } + // this.ckjar.setCookieSync(response.headers['set-cookie'].map(Cookie.parse).toString()) + }) + .then( + response => { + response.statusCode = response.status; + response.body = iconv.decode(response.rawBody, this.encoding); + response.bodyBytes = response.rawBody; + return response; + }, + error => Promise.reject(error.message)); + } }; + + /** + * + * 示例:$.time('yyyy-MM-dd qq HH:mm:ss.S') + * :$.time('yyyyMMddHHmmssS') + * y:年 M:月 d:日 q:季 H:时 m:分 s:秒 S:毫秒 + * 其中y可选0-4位占位符、S可选0-1位占位符,其余可选0-2位占位符 + * @param {string} format 格式化参数 + * @param {number} ts 可选: 根据指定时间戳返回格式化日期 + * + */ + time(format, ts = null) { + const date = ts ? new Date(ts) : new Date(); + let o = { + 'M+': date.getMonth() + 1, + 'd+': date.getDate(), + 'H+': date.getHours(), + 'm+': date.getMinutes(), + 's+': date.getSeconds(), + 'q+': Math.floor((date.getMonth() + 3) / 3), + 'S': date.getMilliseconds() + }; + if (/(y+)/.test(format)) + format = format.replace( + RegExp.$1, + (date.getFullYear() + '').substr(4 - RegExp.$1.length) + ); + for (let k in o) + if (new RegExp('(' + k + ')').test(format)) + format = format.replace( + RegExp.$1, + RegExp.$1.length == 1 + ? o[k] + : ('00' + o[k]).substr(('' + o[k]).length) + ); + return format + } + + /** + * 系统通知 + * + * > 通知参数: 同时支持 QuanX 和 Loon 两种格式, EnvJs根据运行环境自动转换, Surge 环境不支持多媒体通知 + * + * 示例: + * $.msg(title, subt, desc, 'twitter://') + * $.msg(title, subt, desc, { 'open-url': 'twitter://', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' }) + * $.msg(title, subt, desc, { 'open-url': 'https://bing.com', 'media-url': 'https://github.githubassets.com/images/modules/open_graph/github-mark.png' }) + * + * @param {*} title 标题 + * @param {*} subt 副标题 + * @param {*} desc 通知详情 + * @param {*} opts 通知参数 + * + */ + msg(title = name, subt = '', desc = '', opts) { + const toEnvOpts = (rawopts) => { + switch (typeof rawopts) { + case undefined: + return rawopts + case 'string': + switch (this.platform()) { + case 'Surge': + case 'Stash': + case 'Egern': + default: + return { url: rawopts } + case 'Loon': + case 'Shadowrocket': + return rawopts + case 'Quantumult X': + return { 'open-url': rawopts } + case 'Node.js': + return undefined + } + case 'object': + switch (this.platform()) { + case 'Surge': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + default: { + let openUrl = + rawopts.url || rawopts.openUrl || rawopts['open-url']; + return { url: openUrl } + } + case 'Loon': { + let openUrl = + rawopts.openUrl || rawopts.url || rawopts['open-url']; + let mediaUrl = rawopts.mediaUrl || rawopts['media-url']; + return { openUrl, mediaUrl } + } + case 'Quantumult X': { + let openUrl = + rawopts['open-url'] || rawopts.url || rawopts.openUrl; + let mediaUrl = rawopts['media-url'] || rawopts.mediaUrl; + let updatePasteboard = + rawopts['update-pasteboard'] || rawopts.updatePasteboard; + return { + 'open-url': openUrl, + 'media-url': mediaUrl, + 'update-pasteboard': updatePasteboard + } + } + case 'Node.js': + return undefined + } + default: + return undefined + } + }; + if (!this.isMute) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + default: + $notification.post(title, subt, desc, toEnvOpts(opts)); + break + case 'Quantumult X': + $notify(title, subt, desc, toEnvOpts(opts)); + break + case 'Node.js': + break + } + } + if (!this.isMuteLog) { + let logs = ['', '==============📣系统通知📣==============']; + logs.push(title); + subt ? logs.push(subt) : ''; + desc ? logs.push(desc) : ''; + console.log(logs.join('\n')); + this.logs = this.logs.concat(logs); + } + } + + log(...logs) { + if (logs.length > 0) { + this.logs = [...this.logs, ...logs]; + } + console.log(logs.join(this.logSeparator)); + } + + logErr(error) { + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + case 'Quantumult X': + default: + this.log('', `❗️ ${this.name}, 错误!`, error); + break + case 'Node.js': + this.log('', `❗️${this.name}, 错误!`, error.stack); + break + } + } + + wait(time) { + return new Promise((resolve) => setTimeout(resolve, time)) + } + + done(val = {}) { + const endTime = new Date().getTime(); + const costTime = (endTime - this.startTime) / 1000; + this.log('', `🚩 ${this.name}, 结束! 🕛 ${costTime} 秒`); + this.log(); + switch (this.platform()) { + case 'Surge': + case 'Loon': + case 'Stash': + case 'Egern': + case 'Shadowrocket': + case 'Quantumult X': + default: + $done(val); + break + case 'Node.js': + process.exit(1); + break + } + } + + /** + * Get Environment Variables + * @link https://github.com/VirgilClyne/GetSomeFries/blob/main/function/getENV/getENV.js + * @author VirgilClyne + * @param {String} key - Persistent Store Key + * @param {Array} names - Platform Names + * @param {Object} database - Default Database + * @return {Object} { Settings, Caches, Configs } + */ + getENV(key, names, database) { + //this.log(`☑️ ${this.name}, Get Environment Variables`, ""); + /***************** BoxJs *****************/ + // 包装为局部变量,用完释放内存 + // BoxJs的清空操作返回假值空字符串, 逻辑或操作符会在左侧操作数为假值时返回右侧操作数。 + let BoxJs = this.getjson(key, database); + //this.log(`🚧 ${this.name}, Get Environment Variables`, `BoxJs类型: ${typeof BoxJs}`, `BoxJs内容: ${JSON.stringify(BoxJs)}`, ""); + /***************** Argument *****************/ + let Argument = {}; + if (typeof $argument !== "undefined") { + if (Boolean($argument)) { + //this.log(`🎉 ${this.name}, $Argument`); + let arg = Object.fromEntries($argument.split("&").map((item) => item.split("=").map(i => i.replace(/\"/g, '')))); + //this.log(JSON.stringify(arg)); + for (let item in arg) this.lodash.set(Argument, item, arg[item]); + //this.log(JSON.stringify(Argument)); + } //this.log(`✅ ${this.name}, Get Environment Variables`, `Argument类型: ${typeof Argument}`, `Argument内容: ${JSON.stringify(Argument)}`, ""); + } /***************** Store *****************/ + const Store = { Settings: database?.Default?.Settings || {}, Configs: database?.Default?.Configs || {}, Caches: {} }; + if (!Array.isArray(names)) names = [names]; + //this.log(`🚧 ${this.name}, Get Environment Variables`, `names类型: ${typeof names}`, `names内容: ${JSON.stringify(names)}`, ""); + for (let name of names) { + Store.Settings = { ...Store.Settings, ...database?.[name]?.Settings, ...Argument, ...BoxJs?.[name]?.Settings }; + Store.Configs = { ...Store.Configs, ...database?.[name]?.Configs }; + if (BoxJs?.[name]?.Caches && typeof BoxJs?.[name]?.Caches === "string") BoxJs[name].Caches = JSON.parse(BoxJs?.[name]?.Caches); + Store.Caches = { ...Store.Caches, ...BoxJs?.[name]?.Caches }; + } //this.log(`🚧 ${this.name}, Get Environment Variables`, `Store.Settings类型: ${typeof Store.Settings}`, `Store.Settings: ${JSON.stringify(Store.Settings)}`, ""); + this.traverseObject(Store.Settings, (key, value) => { + //this.log(`🚧 ${this.name}, traverseObject`, `${key}: ${typeof value}`, `${key}: ${JSON.stringify(value)}`, ""); + if (value === "true" || value === "false") value = JSON.parse(value); // 字符串转Boolean + else if (typeof value === "string") { + if (value.includes(",")) value = value.split(",").map(item => this.string2number(item)); // 字符串转数组转数字 + else value = this.string2number(value); // 字符串转数字 + } return value; + }); + //this.log(`✅ ${this.name}, Get Environment Variables`, `Store: ${typeof Store.Caches}`, `Store内容: ${JSON.stringify(Store)}`, ""); + return Store; + }; + + /***************** function *****************/ + traverseObject(o, c) { for (var t in o) { var n = o[t]; o[t] = "object" == typeof n && null !== n ? this.traverseObject(n, c) : c(t, n); } return o } + string2number(string) { if (string && !isNaN(string)) string = parseInt(string, 10); return string } +} + +let URI$1 = class URI { + constructor(opts = []) { + this.name = "URI v1.2.6"; + this.opts = opts; + this.json = { scheme: "", host: "", path: "", query: {} }; + }; + + parse(url) { + const URLRegex = /(?:(?.+):\/\/(?[^/]+))?\/?(?[^?]+)?\??(?[^?]+)?/; + let json = url.match(URLRegex)?.groups ?? null; + if (json?.path) json.paths = json.path.split("/"); else json.path = ""; + //if (json?.paths?.at(-1)?.includes(".")) json.format = json.paths.at(-1).split(".").at(-1); + if (json?.paths) { + const fileName = json.paths[json.paths.length - 1]; + if (fileName?.includes(".")) { + const list = fileName.split("."); + json.format = list[list.length - 1]; + } + } + if (json?.query) json.query = Object.fromEntries(json.query.split("&").map((param) => param.split("="))); + return json + }; + + stringify(json = this.json) { + let url = ""; + if (json?.scheme && json?.host) url += json.scheme + "://" + json.host; + if (json?.path) url += (json?.host) ? "/" + json.path : json.path; + if (json?.query) url += "?" + Object.entries(json.query).map(param => param.join("=")).join("&"); + return url + }; +}; + +var Settings$1 = { + Switch: true +}; +var Default = { + Settings: Settings$1 +}; + +var Default$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + Settings: Settings$1, + default: Default +}); + +var Settings = { + Switch: true +}; +var WeChat = { + Settings: Settings +}; + +var WeChat$1 = /*#__PURE__*/Object.freeze({ + __proto__: null, + Settings: Settings, + default: WeChat +}); + +var Database$1 = Database = { + "Default": Default$1, + "WeChat": WeChat$1, +}; + +/** + * Set Environment Variables + * @author VirgilClyne + * @param {Object} $ - ENV + * @param {String} name - Persistent Store Key + * @param {Array} platforms - Platform Names + * @param {Object} database - Default DataBase + * @return {Object} { Settings, Caches, Configs } + */ +function setENV($, name, platforms, database) { + console.log(`☑️ Set Environment Variables`, ""); + let { Settings, Caches, Configs } = $.getENV(name, platforms, database); + /***************** Settings *****************/ + console.log(`✅ Set Environment Variables, Settings: ${typeof Settings}, Settings内容: ${JSON.stringify(Settings)}`, ""); + /***************** Caches *****************/ + //console.log(`✅ ${$.name}, Set Environment Variables`, `Caches: ${typeof Caches}`, `Caches内容: ${JSON.stringify(Caches)}`, ""); + /***************** Configs *****************/ + return { Settings, Caches, Configs }; +} + +const $ = new ENV("🍟 GetSomeFries: WeChat v0.2.1(1) response.beta"); +const URI = new URI$1(); + +/***************** Processing *****************/ +// 解构URL +const URL = URI.parse($request.url); +$.log(`⚠ URL: ${JSON.stringify(URL)}`, ""); +// 获取连接参数 +const METHOD = $request.method; URL.host; const PATH = URL.path; URL.paths; +$.log(`⚠ METHOD: ${METHOD}`, ""); +// 解析格式 +const FORMAT = ($response.headers?.["Content-Type"] ?? $response.headers?.["content-type"] ?? $request.headers?.Accept ?? $request.headers?.accept)?.split(";")?.[0]; +$.log(`⚠ FORMAT: ${FORMAT}`, ""); +!(async () => { + const { Settings, Caches, Configs } = setENV($, "GetSomeFries", "WeChat", Database$1); + $.log(`⚠ ${$.name}`, `Settings.Switch: ${Settings?.Switch}`, ""); + switch (Settings.Switch) { + case true: + default: + // 创建空数据 + let body = {}; + // 格式判断 + switch (FORMAT) { + case undefined: // 视为无body + break; + case "application/x-www-form-urlencoded": + case "text/plain": + default: + break; + case "application/x-mpegURL": + case "application/x-mpegurl": + case "application/vnd.apple.mpegurl": + case "audio/mpegurl": + //body = M3U8.parse($response.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$response.body = M3U8.stringify(body); + break; + case "text/xml": + case "text/html": + case "text/plist": + case "application/xml": + case "application/plist": + case "application/x-plist": + $.log(`🚧 ${$.name}`, `body: ${$response.body}`, ""); + body = new DOMParser().parseFromString($response.body, FORMAT); + $.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + // 路径判断 + switch (PATH) { + case "cgi-bin/mmsupport-bin/readtemplate": + break; + case "cgi-bin/mmspamsupport-bin/newredirectconfirmcgi": + let script = body?.querySelector("script")?.textContent?.trim(); + $.log(`🚧 ${$.name}`, `script: ${JSON.stringify(script)}`, ""); + eval(script); + //Function(`"use strict";return (${script})`)(); + $.log(`🚧 ${$.name}`, `cgiData: ${JSON.stringify(cgiData ?? undefined)}`, ""); + if (cgiData?.url) { + let url = URI.parse(cgiData.url); + switch (url?.host) { + case "mp.weixin.qq.com": + default: + break; + case "qr.alipay.com": + //$request.url = `alipays://platformapi/startapp?appId=20000067&url=${cgiData.url}`; + url.scheme = "alipays"; + url.host = "platformapi"; + url.path = "startapp"; + url.query = { + "appId": 20000067, + "url": encodeURIComponent(cgiData.url) + }; + break; + case "www.taobao.com": + case "taobao.com": + case "www.tmall.com": + case "tmall.com": + case "c.tb.cn": + case "m.tb.cn": + case "s.tb.cn": + case "t.tb.cn": + case "tb.cn": + url.scheme = "taobao"; + break; + } switch (url?.scheme) { + case "alipays": + case "taobao": + default: + switch ($.platform()) { + case "Quantumult X": + $response.status = "HTTP/1.1 302 Temporary Redirect"; + break; + case "Surge": + case "Loon": + case "Stash": + case "Shadowrocket": + default: + $response.status = 302; + break; + } $response.headers = { Location: URI.stringify(url) }; + delete $response.body; + break; + case "http": + case "https": + $response = await $.fetch(cgiData.url); + } } + break; + } //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$response.body = new XMLSerializer().serializeToString(body); + break; + case "text/vtt": + case "application/vtt": + //body = VTT.parse($response.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$response.body = VTT.stringify(body); + break; + case "text/json": + case "application/json": + //body = JSON.parse($request.body ?? "{}"); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = JSON.stringify(body); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + break; + } + break; + case false: + break; + }})() +.catch((e) => $.logErr(e)) +.finally(() => { + switch ($response) { + default: { // 有回复数据,返回回复数据 + //const FORMAT = ($response?.headers?.["Content-Type"] ?? $response?.headers?.["content-type"])?.split(";")?.[0]; + $.log(`🎉 ${$.name}, finally`, `$response`, `FORMAT: ${FORMAT}`, ""); + //$.log(`🚧 ${$.name}, finally`, `$response: ${JSON.stringify($response)}`, ""); + if ($response?.headers?.["Content-Encoding"]) $response.headers["Content-Encoding"] = "identity"; + if ($response?.headers?.["content-encoding"]) $response.headers["content-encoding"] = "identity"; + if ($.isQuanX()) { + switch (FORMAT) { + case undefined: // 视为无body + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers }); + break; + default: + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers, body: $response.body }); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + // 返回二进制数据 + //$.log(`${$response.bodyBytes.byteLength}---${$response.bodyBytes.buffer.byteLength}`); + $.done({ status: $response.status, headers: $response.headers, bodyBytes: $response.bodyBytes.buffer.slice($response.bodyBytes.byteOffset, $response.bodyBytes.byteLength + $response.bodyBytes.byteOffset) }); + break; + } } else $.done($response); + break; + } case undefined: { // 无回复数据 + break; + } }}); + +/***************** Function *****************/ diff --git a/js/WeChat.response.js b/js/WeChat.response.js new file mode 100644 index 00000000..48f7ef5d --- /dev/null +++ b/js/WeChat.response.js @@ -0,0 +1 @@ +class Lodash{constructor(){this.name="Lodash",this.version="1.0.0",console.log(`\n${this.name} v${this.version}\n`)}get(e={},t="",s=void 0){Array.isArray(t)||(t=this.toPath(t));const a=t.reduce(((e,t)=>Object(e)[t]),e);return void 0===a?s:a}set(e={},t="",s){return Array.isArray(t)||(t=this.toPath(t)),t.slice(0,-1).reduce(((e,s,a)=>Object(e[s])===e[s]?e[s]:e[s]=/^\d+$/.test(t[a+1])?[]:{}),e)[t[t.length-1]]=s,e}toPath(e){return e.replace(/\[(\d+)\]/g,".$1").split(".").filter(Boolean)}}class ENV{constructor(e,t){this.name=e,this.version="1.4.1",this.data=null,this.dataFile="box.dat",this.logs=[],this.isMute=!1,this.logSeparator="\n",this.encoding="utf-8",this.startTime=(new Date).getTime(),Object.assign(this,t),this.log("","🚩 开始!",`ENV v${this.version}`,""),this.lodash=new Lodash(this.name),this.log("",this.name,"")}platform(){return"undefined"!=typeof $environment&&$environment["surge-version"]?"Surge":"undefined"!=typeof $environment&&$environment["stash-version"]?"Stash":"undefined"!=typeof module&&module.exports?"Node.js":"undefined"!=typeof $task?"Quantumult X":"undefined"!=typeof $loon?"Loon":"undefined"!=typeof $rocket?"Shadowrocket":"undefined"!=typeof Egern?"Egern":void 0}isNode(){return"Node.js"===this.platform()}isQuanX(){return"Quantumult X"===this.platform()}isSurge(){return"Surge"===this.platform()}isLoon(){return"Loon"===this.platform()}isShadowrocket(){return"Shadowrocket"===this.platform()}isStash(){return"Stash"===this.platform()}isEgern(){return"Egern"===this.platform()}toObj(e,t=null){try{return JSON.parse(e)}catch{return t}}toStr(e,t=null){try{return JSON.stringify(e)}catch{return t}}getjson(e,t){let s=t;if(this.getdata(e))try{s=JSON.parse(this.getdata(e))}catch{}return s}setjson(e,t){try{return this.setdata(JSON.stringify(e),t)}catch{return!1}}getScript(e){return new Promise((t=>{this.get({url:e},((e,s,a)=>t(a)))}))}runScript(e,t){return new Promise((s=>{let a=this.getdata("@chavy_boxjs_userCfgs.httpapi");a=a?a.replace(/\n/g,"").trim():a;let o=this.getdata("@chavy_boxjs_userCfgs.httpapi_timeout");o=o?1*o:20,o=t&&t.timeout?t.timeout:o;const[r,i]=a.split("@"),n={url:`http://${i}/v1/scripting/evaluate`,body:{script_text:e,mock_type:"cron",timeout:o},headers:{"X-Key":r,Accept:"*/*"},timeout:o};this.post(n,((e,t,a)=>s(a)))})).catch((e=>this.logErr(e)))}loaddata(){if(!this.isNode())return{};{this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const e=this.path.resolve(this.dataFile),t=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(e),a=!s&&this.fs.existsSync(t);if(!s&&!a)return{};{const a=s?e:t;try{return JSON.parse(this.fs.readFileSync(a))}catch(e){return{}}}}}writedata(){if(this.isNode()){this.fs=this.fs?this.fs:require("fs"),this.path=this.path?this.path:require("path");const e=this.path.resolve(this.dataFile),t=this.path.resolve(process.cwd(),this.dataFile),s=this.fs.existsSync(e),a=!s&&this.fs.existsSync(t),o=JSON.stringify(this.data);s?this.fs.writeFileSync(e,o):a?this.fs.writeFileSync(t,o):this.fs.writeFileSync(e,o)}}getdata(e){let t=this.getval(e);if(/^@/.test(e)){const[,s,a]=/^@(.*?)\.(.*?)$/.exec(e),o=s?this.getval(s):"";if(o)try{const e=JSON.parse(o);t=e?this.lodash.get(e,a,""):t}catch(e){t=""}}return t}setdata(e,t){let s=!1;if(/^@/.test(t)){const[,a,o]=/^@(.*?)\.(.*?)$/.exec(t),r=this.getval(a),i=a?"null"===r?null:r||"{}":"{}";try{const t=JSON.parse(i);this.lodash.set(t,o,e),s=this.setval(JSON.stringify(t),a)}catch(t){const r={};this.lodash.set(r,o,e),s=this.setval(JSON.stringify(r),a)}}else s=this.setval(e,t);return s}getval(e){switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":return $persistentStore.read(e);case"Quantumult X":return $prefs.valueForKey(e);case"Node.js":return this.data=this.loaddata(),this.data[e];default:return this.data&&this.data[e]||null}}setval(e,t){switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":return $persistentStore.write(e,t);case"Quantumult X":return $prefs.setValueForKey(e,t);case"Node.js":return this.data=this.loaddata(),this.data[t]=e,this.writedata(),!0;default:return this.data&&this.data[t]||null}}initGotEnv(e){this.got=this.got?this.got:require("got"),this.cktough=this.cktough?this.cktough:require("tough-cookie"),this.ckjar=this.ckjar?this.ckjar:new this.cktough.CookieJar,e&&(e.headers=e.headers?e.headers:{},void 0===e.headers.Cookie&&void 0===e.cookieJar&&(e.cookieJar=this.ckjar))}async fetch(e={}||"",t={}){switch(e.constructor){case Object:e={...e,...t};break;case String:e={url:e,...t}}e.method||(e.method="GET",(e.body??e.bodyBytes)&&(e.method="POST")),delete e.headers?.["Content-Length"],delete e.headers?.["content-length"];const s=e.method.toLocaleLowerCase();switch(this.platform()){case"Loon":case"Surge":case"Stash":case"Egern":case"Shadowrocket":default:return delete e.id,e.policy&&(this.isLoon()&&(e.node=e.policy),this.isStash()&&this.lodash.set(e,"headers.X-Stash-Selected-Proxy",encodeURI(e.policy))),ArrayBuffer.isView(e.body)&&(e["binary-mode"]=!0),await new Promise(((t,a)=>{$httpClient[s](e,((s,o,r)=>{s?a(s):(o.ok=/^2\d\d$/.test(o.status),o.statusCode=o.status,r&&(o.body=r,1==e["binary-mode"]&&(o.bodyBytes=r)),t(o))}))}));case"Quantumult X":switch(delete e.scheme,delete e.sessionIndex,delete e.charset,e.policy&&this.lodash.set(e,"opts.policy",e.policy),(e?.headers?.["Content-Type"]??e?.headers?.["content-type"])?.split(";")?.[0]){default:delete e.bodyBytes;break;case"application/protobuf":case"application/x-protobuf":case"application/vnd.google.protobuf":case"application/grpc":case"application/grpc+proto":case"application/octet-stream":delete e.body,ArrayBuffer.isView(e.bodyBytes)&&(e.bodyBytes=e.bodyBytes.buffer.slice(e.bodyBytes.byteOffset,e.bodyBytes.byteLength+e.bodyBytes.byteOffset));case void 0:}return await $task.fetch(e).then((e=>(e.ok=/^2\d\d$/.test(e.statusCode),e.status=e.statusCode,e)),(e=>Promise.reject(e.error)));case"Node.js":let t=require("iconv-lite");this.initGotEnv(e);const{url:a,...o}=e;return await this.got[s](a,o).on("redirect",((e,t)=>{try{if(e.headers["set-cookie"]){const s=e.headers["set-cookie"].map(this.cktough.Cookie.parse).toString();s&&this.ckjar.setCookieSync(s,null),t.cookieJar=this.ckjar}}catch(e){this.logErr(e)}})).then((e=>(e.statusCode=e.status,e.body=t.decode(e.rawBody,this.encoding),e.bodyBytes=e.rawBody,e)),(e=>Promise.reject(e.message)))}}time(e,t=null){const s=t?new Date(t):new Date;let a={"M+":s.getMonth()+1,"d+":s.getDate(),"H+":s.getHours(),"m+":s.getMinutes(),"s+":s.getSeconds(),"q+":Math.floor((s.getMonth()+3)/3),S:s.getMilliseconds()};/(y+)/.test(e)&&(e=e.replace(RegExp.$1,(s.getFullYear()+"").substr(4-RegExp.$1.length)));for(let t in a)new RegExp("("+t+")").test(e)&&(e=e.replace(RegExp.$1,1==RegExp.$1.length?a[t]:("00"+a[t]).substr((""+a[t]).length)));return e}msg(e=name,t="",s="",a){const o=e=>{switch(typeof e){case void 0:return e;case"string":switch(this.platform()){case"Surge":case"Stash":case"Egern":default:return{url:e};case"Loon":case"Shadowrocket":return e;case"Quantumult X":return{"open-url":e};case"Node.js":return}case"object":switch(this.platform()){case"Surge":case"Stash":case"Egern":case"Shadowrocket":default:return{url:e.url||e.openUrl||e["open-url"]};case"Loon":return{openUrl:e.openUrl||e.url||e["open-url"],mediaUrl:e.mediaUrl||e["media-url"]};case"Quantumult X":return{"open-url":e["open-url"]||e.url||e.openUrl,"media-url":e["media-url"]||e.mediaUrl,"update-pasteboard":e["update-pasteboard"]||e.updatePasteboard};case"Node.js":return}default:return}};if(!this.isMute)switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":default:$notification.post(e,t,s,o(a));break;case"Quantumult X":$notify(e,t,s,o(a));case"Node.js":}if(!this.isMuteLog){let a=["","==============📣系统通知📣=============="];a.push(e),t&&a.push(t),s&&a.push(s),console.log(a.join("\n")),this.logs=this.logs.concat(a)}}log(...e){e.length>0&&(this.logs=[...this.logs,...e]),console.log(e.join(this.logSeparator))}logErr(e){switch(this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Quantumult X":default:this.log("",`❗️ ${this.name}, 错误!`,e);break;case"Node.js":this.log("",`❗️${this.name}, 错误!`,e.stack)}}wait(e){return new Promise((t=>setTimeout(t,e)))}done(e={}){const t=((new Date).getTime()-this.startTime)/1e3;switch(this.log("",`🚩 ${this.name}, 结束! 🕛 ${t} 秒`),this.log(),this.platform()){case"Surge":case"Loon":case"Stash":case"Egern":case"Shadowrocket":case"Quantumult X":default:$done(e);break;case"Node.js":process.exit(1)}}getENV(e,t,s){let a=this.getjson(e,s),o={};if("undefined"!=typeof $argument&&Boolean($argument)){let e=Object.fromEntries($argument.split("&").map((e=>e.split("=").map((e=>e.replace(/\"/g,""))))));for(let t in e)this.lodash.set(o,t,e[t])}const r={Settings:s?.Default?.Settings||{},Configs:s?.Default?.Configs||{},Caches:{}};Array.isArray(t)||(t=[t]);for(let e of t)r.Settings={...r.Settings,...s?.[e]?.Settings,...o,...a?.[e]?.Settings},r.Configs={...r.Configs,...s?.[e]?.Configs},a?.[e]?.Caches&&"string"==typeof a?.[e]?.Caches&&(a[e].Caches=JSON.parse(a?.[e]?.Caches)),r.Caches={...r.Caches,...a?.[e]?.Caches};return this.traverseObject(r.Settings,((e,t)=>("true"===t||"false"===t?t=JSON.parse(t):"string"==typeof t&&(t=t.includes(",")?t.split(",").map((e=>this.string2number(e))):this.string2number(t)),t))),r}traverseObject(e,t){for(var s in e){var a=e[s];e[s]="object"==typeof a&&null!==a?this.traverseObject(a,t):t(s,a)}return e}string2number(e){return e&&!isNaN(e)&&(e=parseInt(e,10)),e}}let URI$1=class{constructor(e=[]){this.name="URI v1.2.6",this.opts=e,this.json={scheme:"",host:"",path:"",query:{}}}parse(e){let t=e.match(/(?:(?.+):\/\/(?[^/]+))?\/?(?[^?]+)?\??(?[^?]+)?/)?.groups??null;if(t?.path?t.paths=t.path.split("/"):t.path="",t?.paths){const e=t.paths[t.paths.length-1];if(e?.includes(".")){const s=e.split(".");t.format=s[s.length-1]}}return t?.query&&(t.query=Object.fromEntries(t.query.split("&").map((e=>e.split("="))))),t}stringify(e=this.json){let t="";return e?.scheme&&e?.host&&(t+=e.scheme+"://"+e.host),e?.path&&(t+=e?.host?"/"+e.path:e.path),e?.query&&(t+="?"+Object.entries(e.query).map((e=>e.join("="))).join("&")),t}};var Settings$1={Switch:!0},Default={Settings:Settings$1},Default$1=Object.freeze({__proto__:null,Settings:Settings$1,default:Default}),Settings={Switch:!0},WeChat={Settings:Settings},WeChat$1=Object.freeze({__proto__:null,Settings:Settings,default:WeChat}),Database$1=Database={Default:Default$1,WeChat:WeChat$1};function setENV(e,t,s,a){console.log("☑️ Set Environment Variables","");let{Settings:o,Caches:r,Configs:i}=e.getENV(t,s,a);return console.log(`✅ Set Environment Variables, Settings: ${typeof o}, Settings内容: ${JSON.stringify(o)}`,""),{Settings:o,Caches:r,Configs:i}}const $=new ENV("🍟 GetSomeFries: WeChat v0.2.1(1) response"),URI=new URI$1,URL=URI.parse($request.url);$.log(`⚠ URL: ${JSON.stringify(URL)}`,"");const METHOD=$request.method;URL.host;const PATH=URL.path;URL.paths,$.log(`⚠ METHOD: ${METHOD}`,"");const FORMAT=($response.headers?.["Content-Type"]??$response.headers?.["content-type"]??$request.headers?.Accept??$request.headers?.accept)?.split(";")?.[0];$.log(`⚠ FORMAT: ${FORMAT}`,""),(async()=>{const{Settings:Settings,Caches:Caches,Configs:Configs}=setENV($,"GetSomeFries","WeChat",Database$1);switch($.log(`⚠ ${$.name}`,`Settings.Switch: ${Settings?.Switch}`,""),Settings.Switch){case!0:default:let body={};switch(FORMAT){case void 0:case"application/x-www-form-urlencoded":case"text/plain":default:case"application/x-mpegURL":case"application/x-mpegurl":case"application/vnd.apple.mpegurl":case"audio/mpegurl":break;case"text/xml":case"text/html":case"text/plist":case"application/xml":case"application/plist":case"application/x-plist":switch(body=(new DOMParser).parseFromString($response.body,FORMAT),PATH){case"cgi-bin/mmsupport-bin/readtemplate":break;case"cgi-bin/mmspamsupport-bin/newredirectconfirmcgi":let script=body?.querySelector("script")?.textContent?.trim();if(eval(script),cgiData?.url){let e=URI.parse(cgiData.url);switch(e?.host){case"mp.weixin.qq.com":default:break;case"qr.alipay.com":e.scheme="alipays",e.host="platformapi",e.path="startapp",e.query={appId:20000067,url:encodeURIComponent(cgiData.url)};break;case"www.taobao.com":case"taobao.com":case"www.tmall.com":case"tmall.com":case"c.tb.cn":case"m.tb.cn":case"s.tb.cn":case"t.tb.cn":case"tb.cn":e.scheme="taobao"}switch(e?.scheme){case"alipays":case"taobao":default:if("Quantumult X"===$.platform())$response.status="HTTP/1.1 302 Temporary Redirect";else $response.status=302;$response.headers={Location:URI.stringify(e)},delete $response.body;break;case"http":case"https":$response=await $.fetch(cgiData.url)}}}case"text/vtt":case"application/vtt":case"text/json":case"application/json":case"application/protobuf":case"application/x-protobuf":case"application/vnd.google.protobuf":case"application/grpc":case"application/grpc+proto":case"application/octet-stream":}case!1:}})().catch((e=>$.logErr(e))).finally((()=>{if(void 0!==$response)if($.log(`🎉 ${$.name}, finally`,"$response",`FORMAT: ${FORMAT}`,""),$response?.headers?.["Content-Encoding"]&&($response.headers["Content-Encoding"]="identity"),$response?.headers?.["content-encoding"]&&($response.headers["content-encoding"]="identity"),$.isQuanX())switch(FORMAT){case void 0:$.done({status:$response.status,headers:$response.headers});break;default:$.done({status:$response.status,headers:$response.headers,body:$response.body});break;case"application/protobuf":case"application/x-protobuf":case"application/vnd.google.protobuf":case"application/grpc":case"application/grpc+proto":case"application/octet-stream":$.done({status:$response.status,headers:$response.headers,bodyBytes:$response.bodyBytes.buffer.slice($response.bodyBytes.byteOffset,$response.bodyBytes.byteLength+$response.bodyBytes.byteOffset)})}else $.done($response)})); diff --git a/js/Fries.WeChat.request.beta.js b/js/archive/Fries.WeChat.request.beta.js similarity index 100% rename from js/Fries.WeChat.request.beta.js rename to js/archive/Fries.WeChat.request.beta.js diff --git a/js/Fries.WeChat.response.beta.js b/js/archive/Fries.WeChat.response.beta.js similarity index 100% rename from js/Fries.WeChat.response.beta.js rename to js/archive/Fries.WeChat.response.beta.js diff --git a/js/Fries.WeChat.response.js b/js/archive/Fries.WeChat.response.js similarity index 100% rename from js/Fries.WeChat.response.js rename to js/archive/Fries.WeChat.response.js diff --git a/modules/Fries.WeChat.beta.sgmodule b/modules/Fries.WeChat.beta.sgmodule index 667a2c6c..b7d753a7 100644 --- a/modules/Fries.WeChat.beta.sgmodule +++ b/modules/Fries.WeChat.beta.sgmodule @@ -8,7 +8,7 @@ #!category=🍟 Fries [Script] -WeChat.mmspamsupport.response = type=http-response, pattern=^https?:\/\/weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi(\?.*)?$, requires-body=1, debug=1, script-path=https://raw.githubusercontent.com/VirgilClyne/GetSomeFries/beta/js/Fries.WeChat.response.beta.js, argument= +WeChat.mmspamsupport.response = type=http-response, pattern=^https?:\/\/weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi(\?.*)?$, requires-body=1, debug=1, script-path=https://raw.githubusercontent.com/VirgilClyne/GetSomeFries/beta/js/WeChat.response.beta.js, argument= [MITM] hostname = %APPEND% szsupport.weixin.qq.com, weixin110.qq.com diff --git a/modules/Fries.WeChat.sgmodule b/modules/Fries.WeChat.sgmodule index b6fe87ea..7f1ae269 100644 --- a/modules/Fries.WeChat.sgmodule +++ b/modules/Fries.WeChat.sgmodule @@ -8,7 +8,7 @@ #!category=🍟 Fries [Script] -WeChat.mmspamsupport.response = type=http-response, pattern=^https?:\/\/weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi(\?.*)?$, requires-body=1, script-path=https://raw.githubusercontent.com/VirgilClyne/GetSomeFries/beta/js/Fries.WeChat.response.js, argument= +WeChat.mmspamsupport.response = type=http-response, pattern=^https?:\/\/weixin110\.qq\.com\/cgi-bin\/mmspamsupport-bin\/newredirectconfirmcgi(\?.*)?$, requires-body=1, script-path=https://raw.githubusercontent.com/VirgilClyne/GetSomeFries/main/js/WeChat.response.js, argument= [MITM] hostname = %APPEND% weixin110.qq.com diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..3f58b7fc --- /dev/null +++ b/package-lock.json @@ -0,0 +1,620 @@ +{ + "name": "getsomefries", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "getsomefries", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-terser": "^0.4.4", + "rollup": "^4.9.6" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz", + "integrity": "sha512-Oud2QPM5dHviZNn4y/WhhYKSXksv+1xLEIsNrAbGcFzUN3ubqWRFT5gwPchNc5NuzILOU4tPBDTZ4VwhL8Y7cw==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", + "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", + "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz", + "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz", + "integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz", + "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz", + "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz", + "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz", + "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz", + "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", + "integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz", + "integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz", + "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz", + "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz", + "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/magic-string": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rollup": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz", + "integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.12.0", + "@rollup/rollup-android-arm64": "4.12.0", + "@rollup/rollup-darwin-arm64": "4.12.0", + "@rollup/rollup-darwin-x64": "4.12.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.12.0", + "@rollup/rollup-linux-arm64-gnu": "4.12.0", + "@rollup/rollup-linux-arm64-musl": "4.12.0", + "@rollup/rollup-linux-riscv64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-gnu": "4.12.0", + "@rollup/rollup-linux-x64-musl": "4.12.0", + "@rollup/rollup-win32-arm64-msvc": "4.12.0", + "@rollup/rollup-win32-ia32-msvc": "4.12.0", + "@rollup/rollup-win32-x64-msvc": "4.12.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/smob": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", + "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", + "dev": true + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/terser": { + "version": "5.28.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", + "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..10dcf61e --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "getsomefries", + "version": "1.0.0", + "description": "GetSomeFries", + "type": "module", + "repository": { + "type": "git", + "url": "https://github.com/VirgilClyne/GetSomeFries.git" + }, + "directories": { + "example": "example" + }, + "scripts": { + "build": "rollup -c", + "test": "rollup --config --configDebug" + }, + "browserslist": [ + "iOS >= 15" + ], + "keywords": [], + "author": "VirgilClyne", + "license": "Apache-2.0", + "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-terser": "^0.4.4", + "rollup": "^4.9.6" + } +} diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..9abc81dd --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,9 @@ +import defaultConfig from './rollup.default.config.js'; +import debugConfig from './rollup.debug.config.js'; + +export default commandLineArgs => { + if (commandLineArgs.configDebug === true) { + return debugConfig; + } + return defaultConfig; +}; diff --git a/rollup.debug.config.js b/rollup.debug.config.js new file mode 100644 index 00000000..dc56d102 --- /dev/null +++ b/rollup.debug.config.js @@ -0,0 +1,24 @@ +import json from '@rollup/plugin-json'; +import commonjs from "@rollup/plugin-commonjs"; + +export default [ + { + input: 'src/WeChat.request.beta.js', + output: { + file: 'js/WeChat.request.beta.js', + banner: '/* README: https://github.com/VirgilClyne/GetSomeFries */', + format: 'es' + }, + plugins: [json(), commonjs()], + + }, + { + input: 'src/WeChat.response.beta.js', + output: { + file: 'js/WeChat.response.beta.js', + banner: '/* README: https://github.com/VirgilClyne/GetSomeFries */', + format: 'es' + }, + plugins: [json(), commonjs()], + }, +]; diff --git a/rollup.default.config.js b/rollup.default.config.js new file mode 100644 index 00000000..b460e50b --- /dev/null +++ b/rollup.default.config.js @@ -0,0 +1,15 @@ +import json from '@rollup/plugin-json'; +import commonjs from "@rollup/plugin-commonjs"; +import terser from '@rollup/plugin-terser'; + +export default [ + { + input: 'src/WeChat.response.js', + output: { + file: 'js/WeChat.response.js', + banner: '/* README: https://github.com/VirgilClyne/GetSomeFries */', + format: 'es' + }, + plugins: [json(), commonjs(), terser()] + }, +]; diff --git a/src/ENV b/src/ENV new file mode 160000 index 00000000..11b0a98b --- /dev/null +++ b/src/ENV @@ -0,0 +1 @@ +Subproject commit 11b0a98ba39f6ed6a156d9e462b3b4e92c8bedac diff --git a/src/URI b/src/URI new file mode 160000 index 00000000..f2a074c3 --- /dev/null +++ b/src/URI @@ -0,0 +1 @@ +Subproject commit f2a074c32d1ad3143d8d4be372ccc1b51cc99e0d diff --git a/src/WeChat.request.beta.js b/src/WeChat.request.beta.js new file mode 100644 index 00000000..80af5fde --- /dev/null +++ b/src/WeChat.request.beta.js @@ -0,0 +1,193 @@ +import ENVs from "./ENV/ENV.mjs"; +import URIs from "./URI/URI.mjs"; + +import Database from "./database/index.mjs"; +import setENV from "./function/setENV.mjs"; + +const $ = new ENVs("🍟 GetSomeFries: WeChat v0.1.2(1) request.beta"); +const URI = new URIs(); + +// 构造回复数据 +let $response = undefined; + +/***************** Processing *****************/ +// 解构URL +const URL = URI.parse($request.url); +$.log(`⚠ URL: ${JSON.stringify(URL)}`, ""); +// 获取连接参数 +const METHOD = $request.method, HOST = URL.host, PATH = URL.path, PATHs = URL.paths; +$.log(`⚠ METHOD: ${METHOD}`, ""); +// 解析格式 +const FORMAT = ($request.headers?.["Content-Type"] ?? $request.headers?.["content-type"])?.split(";")?.[0]; +$.log(`⚠ FORMAT: ${FORMAT}`, ""); +(async () => { + const { Settings, Caches, Configs } = setENV($, "GetSomeFries", "WeChat", Database); + $.log(`⚠ ${$.name}`, `Settings.Switch: ${Settings?.Switch}`, ""); + switch (Settings.Switch) { + case true: + default: + // 创建空数据 + let body = {}; + // 方法判断 + switch (METHOD) { + case "POST": + case "PUT": + case "PATCH": + case "DELETE": + // 格式判断 + switch (FORMAT) { + case undefined: // 视为无body + break; + case "application/x-www-form-urlencoded": + case "text/plain": + default: + break; + case "application/x-mpegURL": + case "application/x-mpegurl": + case "application/vnd.apple.mpegurl": + case "audio/mpegurl": + //body = M3U8.parse($request.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = M3U8.stringify(body); + break; + case "text/xml": + case "text/html": + case "text/plist": + case "application/xml": + case "application/plist": + case "application/x-plist": + body = new DOMParser().parseFromString($response.body, FORMAT); + // 路径判断 + switch (PATH) { + case "cgi-bin/mmsupport-bin/readtemplate": + $.log(body); + break; + case "cgi-bin/mmspamsupport-bin/newredirectconfirmcgi": + $.log(body); + break; + }; + $response.body = new XMLSerializer().serializeToString(body); + break; + case "text/vtt": + case "application/vtt": + //body = VTT.parse($request.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = VTT.stringify(body); + break; + case "text/json": + case "application/json": + //body = JSON.parse($request.body ?? "{}"); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = JSON.stringify(body); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + break; + }; + //break; // 不中断,继续处理URL + case "GET": + case "HEAD": + case "OPTIONS": + case undefined: // QX牛逼,script-echo-response不返回method + default: + let newURL = {}; + // 路径判断 + switch (PATH) { + case "cgi-bin/mmsupport-bin/readtemplate": + if (URL.query?.url) newURL = URI.parse(decodeURIComponent(URL.query.url)); + break; + case "cgi-bin/mmspamsupport-bin/newredirectconfirmcgi": + if (URL.query?.url) newURL = URI.parse(decodeURIComponent(URL.query.url)); + //$request.url = "https://mp.weixin.qq.com/mp/spredirect?url=" + body?.redirect_url; + break; + }; + URI.scheme = newURL?.scheme ?? URI.scheme ?? "https"; + URI.host = newURL?.host ?? URI.host ?? "mp.weixin.qq.com"; + URI.path = newURL?.path ?? URI.path ?? "/mp/spredirect"; + URI.query = newURL?.query ?? URL.query ?? {}; + break; + case "CONNECT": + case "TRACE": + break; + }; + if ($request.headers?.Host) $request.headers.Host = URL.host; + $request.url = URI.stringify(URL); + $.log(`🚧 ${$.name}, 调试信息`, `$request.url: ${$request.url}`, ""); + break; + case false: + break; + }; +})() + .catch((e) => $.logErr(e)) + .finally(() => { + switch ($response) { + default: { // 有构造回复数据,返回构造的回复数据 + const FORMAT = ($response?.headers?.["Content-Type"] ?? $response?.headers?.["content-type"])?.split(";")?.[0]; + $.log(`🎉 ${$.name}, finally`, `echo $response`, `FORMAT: ${FORMAT}`, ""); + //$.log(`🚧 ${$.name}, finally`, `echo $response: ${JSON.stringify($response)}`, ""); + if ($response?.headers?.["Content-Encoding"]) $response.headers["Content-Encoding"] = "identity"; + if ($response?.headers?.["content-encoding"]) $response.headers["content-encoding"] = "identity"; + if ($.isQuanX()) { + $response.status = "HTTP/1.1 200 OK"; + delete $response?.headers?.["Content-Length"]; + delete $response?.headers?.["content-length"]; + delete $response?.headers?.["Transfer-Encoding"]; + switch (FORMAT) { + case undefined: // 视为无body + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers }); + break; + default: + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers, body: $response.body }); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + // 返回二进制数据 + //$.log(`${$response.bodyBytes.byteLength}---${$response.bodyBytes.buffer.byteLength}`); + $.done({ status: $response.status, headers: $response.headers, bodyBytes: $response.bodyBytes }); + break; + }; + } else $.done({ response: $response }); + break; + }; + case undefined: { // 无构造回复数据,发送修改的请求数据 + //const FORMAT = ($request?.headers?.["Content-Type"] ?? $request?.headers?.["content-type"])?.split(";")?.[0]; + $.log(`🎉 ${$.name}, finally`, `$request`, `FORMAT: ${FORMAT}`, ""); + //$.log(`🚧 ${$.name}, finally`, `$request: ${JSON.stringify($request)}`, ""); + if ($.isQuanX()) { + switch (FORMAT) { + case undefined: // 视为无body + // 返回普通数据 + $.done({ url: $request.url, headers: $request.headers }) + break; + default: + // 返回普通数据 + $.done({ url: $request.url, headers: $request.headers, body: $request.body }) + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "applecation/octet-stream": + // 返回二进制数据 + //$.log(`${$request.bodyBytes.byteLength}---${$request.bodyBytes.buffer.byteLength}`); + $.done({ url: $request.url, headers: $request.headers, bodyBytes: $request.bodyBytes.buffer.slice($request.bodyBytes.byteOffset, $request.bodyBytes.byteLength + $request.bodyBytes.byteOffset) }); + break; + }; + } else $.done($request); + break; + }; + }; + }) + +/***************** Function *****************/ diff --git a/src/WeChat.response.beta.js b/src/WeChat.response.beta.js new file mode 100644 index 00000000..b8bc5049 --- /dev/null +++ b/src/WeChat.response.beta.js @@ -0,0 +1,185 @@ +import ENVs from "./ENV/ENV.mjs"; +import URIs from "./URI/URI.mjs"; + +import Database from "./database/index.mjs"; +import setENV from "./function/setENV.mjs"; + +const $ = new ENVs("🍟 GetSomeFries: WeChat v0.2.1(1) response.beta"); +const URI = new URIs(); + +/***************** Processing *****************/ +// 解构URL +const URL = URI.parse($request.url); +$.log(`⚠ URL: ${JSON.stringify(URL)}`, ""); +// 获取连接参数 +const METHOD = $request.method, HOST = URL.host, PATH = URL.path, PATHs = URL.paths; +$.log(`⚠ METHOD: ${METHOD}`, ""); +// 解析格式 +const FORMAT = ($response.headers?.["Content-Type"] ?? $response.headers?.["content-type"] ?? $request.headers?.Accept ?? $request.headers?.accept)?.split(";")?.[0]; +$.log(`⚠ FORMAT: ${FORMAT}`, ""); +!(async () => { + const { Settings, Caches, Configs } = setENV($, "GetSomeFries", "WeChat", Database); + $.log(`⚠ ${$.name}`, `Settings.Switch: ${Settings?.Switch}`, ""); + switch (Settings.Switch) { + case true: + default: + // 创建空数据 + let body = {}; + // 格式判断 + switch (FORMAT) { + case undefined: // 视为无body + break; + case "application/x-www-form-urlencoded": + case "text/plain": + default: + break; + case "application/x-mpegURL": + case "application/x-mpegurl": + case "application/vnd.apple.mpegurl": + case "audio/mpegurl": + //body = M3U8.parse($response.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$response.body = M3U8.stringify(body); + break; + case "text/xml": + case "text/html": + case "text/plist": + case "application/xml": + case "application/plist": + case "application/x-plist": + $.log(`🚧 ${$.name}`, `body: ${$response.body}`, ""); + body = new DOMParser().parseFromString($response.body, FORMAT); + $.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + // 路径判断 + switch (PATH) { + case "cgi-bin/mmsupport-bin/readtemplate": + break; + case "cgi-bin/mmspamsupport-bin/newredirectconfirmcgi": + let script = body?.querySelector("script")?.textContent?.trim(); + $.log(`🚧 ${$.name}`, `script: ${JSON.stringify(script)}`, ""); + eval(script); + //Function(`"use strict";return (${script})`)(); + $.log(`🚧 ${$.name}`, `cgiData: ${JSON.stringify(cgiData ?? undefined)}`, ""); + if (cgiData?.url) { + let url = URI.parse(cgiData.url); + switch (url?.host) { + case "mp.weixin.qq.com": + default: + break; + case "qr.alipay.com": + //$request.url = `alipays://platformapi/startapp?appId=20000067&url=${cgiData.url}`; + url.scheme = "alipays"; + url.host = "platformapi"; + url.path = "startapp"; + url.query = { + "appId": 20000067, + "url": encodeURIComponent(cgiData.url) + }; + break; + case "www.taobao.com": + case "taobao.com": + case "www.tmall.com": + case "tmall.com": + case "c.tb.cn": + case "m.tb.cn": + case "s.tb.cn": + case "t.tb.cn": + case "tb.cn": + url.scheme = "taobao"; + break; + }; + switch (url?.scheme) { + case "alipays": + case "taobao": + default: + switch ($.platform()) { + case "Quantumult X": + $response.status = "HTTP/1.1 302 Temporary Redirect"; + break; + case "Surge": + case "Loon": + case "Stash": + case "Shadowrocket": + default: + $response.status = 302; + break; + }; + $response.headers = { Location: URI.stringify(url) }; + delete $response.body; + break; + case "http": + case "https": + $response = await $.fetch(cgiData.url); + }; + } + break; + }; + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$response.body = new XMLSerializer().serializeToString(body); + break; + case "text/vtt": + case "application/vtt": + //body = VTT.parse($response.body); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$response.body = VTT.stringify(body); + break; + case "text/json": + case "application/json": + //body = JSON.parse($request.body ?? "{}"); + //$.log(`🚧 ${$.name}`, `body: ${JSON.stringify(body)}`, ""); + //$request.body = JSON.stringify(body); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + break; + }; + + break; + case false: + break; + }; +})() +.catch((e) => $.logErr(e)) +.finally(() => { + switch ($response) { + default: { // 有回复数据,返回回复数据 + //const FORMAT = ($response?.headers?.["Content-Type"] ?? $response?.headers?.["content-type"])?.split(";")?.[0]; + $.log(`🎉 ${$.name}, finally`, `$response`, `FORMAT: ${FORMAT}`, ""); + //$.log(`🚧 ${$.name}, finally`, `$response: ${JSON.stringify($response)}`, ""); + if ($response?.headers?.["Content-Encoding"]) $response.headers["Content-Encoding"] = "identity"; + if ($response?.headers?.["content-encoding"]) $response.headers["content-encoding"] = "identity"; + if ($.isQuanX()) { + switch (FORMAT) { + case undefined: // 视为无body + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers }); + break; + default: + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers, body: $response.body }); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + // 返回二进制数据 + //$.log(`${$response.bodyBytes.byteLength}---${$response.bodyBytes.buffer.byteLength}`); + $.done({ status: $response.status, headers: $response.headers, bodyBytes: $response.bodyBytes.buffer.slice($response.bodyBytes.byteOffset, $response.bodyBytes.byteLength + $response.bodyBytes.byteOffset) }); + break; + }; + } else $.done($response); + break; + }; + case undefined: { // 无回复数据 + break; + }; + }; +}) + +/***************** Function *****************/ diff --git a/src/WeChat.response.js b/src/WeChat.response.js new file mode 100644 index 00000000..f850efcc --- /dev/null +++ b/src/WeChat.response.js @@ -0,0 +1,165 @@ +import ENVs from "./ENV/ENV.mjs"; +import URIs from "./URI/URI.mjs"; + +import Database from "./database/index.mjs"; +import setENV from "./function/setENV.mjs"; + +const $ = new ENVs("🍟 GetSomeFries: WeChat v0.2.1(1) response"); +const URI = new URIs(); + +/***************** Processing *****************/ +// 解构URL +const URL = URI.parse($request.url); +$.log(`⚠ URL: ${JSON.stringify(URL)}`, ""); +// 获取连接参数 +const METHOD = $request.method, HOST = URL.host, PATH = URL.path, PATHs = URL.paths; +$.log(`⚠ METHOD: ${METHOD}`, ""); +// 解析格式 +const FORMAT = ($response.headers?.["Content-Type"] ?? $response.headers?.["content-type"] ?? $request.headers?.Accept ?? $request.headers?.accept)?.split(";")?.[0]; +$.log(`⚠ FORMAT: ${FORMAT}`, ""); +!(async () => { + const { Settings, Caches, Configs } = setENV($, "GetSomeFries", "WeChat", Database); + $.log(`⚠ ${$.name}`, `Settings.Switch: ${Settings?.Switch}`, ""); + switch (Settings.Switch) { + case true: + default: + // 创建空数据 + let body = {}; + // 格式判断 + switch (FORMAT) { + case undefined: // 视为无body + break; + case "application/x-www-form-urlencoded": + case "text/plain": + default: + break; + case "application/x-mpegURL": + case "application/x-mpegurl": + case "application/vnd.apple.mpegurl": + case "audio/mpegurl": + break; + case "text/xml": + case "text/html": + case "text/plist": + case "application/xml": + case "application/plist": + case "application/x-plist": + body = new DOMParser().parseFromString($response.body, FORMAT); + // 路径判断 + switch (PATH) { + case "cgi-bin/mmsupport-bin/readtemplate": + break; + case "cgi-bin/mmspamsupport-bin/newredirectconfirmcgi": + let script = body?.querySelector("script")?.textContent?.trim(); + eval(script); + if (cgiData?.url) { + let url = URI.parse(cgiData.url); + switch (url?.host) { + case "mp.weixin.qq.com": + default: + break; + case "qr.alipay.com": + url.scheme = "alipays"; + url.host = "platformapi"; + url.path = "startapp"; + url.query = { + "appId": 20000067, + "url": encodeURIComponent(cgiData.url) + }; + break; + case "www.taobao.com": + case "taobao.com": + case "www.tmall.com": + case "tmall.com": + case "c.tb.cn": + case "m.tb.cn": + case "s.tb.cn": + case "t.tb.cn": + case "tb.cn": + url.scheme = "taobao"; + break; + }; + switch (url?.scheme) { + case "alipays": + case "taobao": + default: + switch ($.platform()) { + case "Quantumult X": + $response.status = "HTTP/1.1 302 Temporary Redirect"; + break; + case "Surge": + case "Loon": + case "Stash": + case "Shadowrocket": + default: + $response.status = 302; + break; + }; + $response.headers = { Location: URI.stringify(url) }; + delete $response.body; + break; + case "http": + case "https": + $response = await $.fetch(cgiData.url); + }; + } + break; + }; + break; + case "text/vtt": + case "application/vtt": + break; + case "text/json": + case "application/json": + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + break; + }; + + break; + case false: + break; + }; +})() +.catch((e) => $.logErr(e)) +.finally(() => { + switch ($response) { + default: { // 有回复数据,返回回复数据 + $.log(`🎉 ${$.name}, finally`, `$response`, `FORMAT: ${FORMAT}`, ""); + if ($response?.headers?.["Content-Encoding"]) $response.headers["Content-Encoding"] = "identity"; + if ($response?.headers?.["content-encoding"]) $response.headers["content-encoding"] = "identity"; + if ($.isQuanX()) { + switch (FORMAT) { + case undefined: // 视为无body + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers }); + break; + default: + // 返回普通数据 + $.done({ status: $response.status, headers: $response.headers, body: $response.body }); + break; + case "application/protobuf": + case "application/x-protobuf": + case "application/vnd.google.protobuf": + case "application/grpc": + case "application/grpc+proto": + case "application/octet-stream": + // 返回二进制数据 + $.done({ status: $response.status, headers: $response.headers, bodyBytes: $response.bodyBytes.buffer.slice($response.bodyBytes.byteOffset, $response.bodyBytes.byteLength + $response.bodyBytes.byteOffset) }); + break; + }; + } else $.done($response); + break; + }; + case undefined: { // 无回复数据 + break; + }; + }; +}) + +/***************** Function *****************/ diff --git a/src/database/Default.json b/src/database/Default.json new file mode 100644 index 00000000..94bd0890 --- /dev/null +++ b/src/database/Default.json @@ -0,0 +1,5 @@ +{ + "Settings": { + "Switch": true + } +} diff --git a/src/database/WeChat.json b/src/database/WeChat.json new file mode 100644 index 00000000..94bd0890 --- /dev/null +++ b/src/database/WeChat.json @@ -0,0 +1,5 @@ +{ + "Settings": { + "Switch": true + } +} diff --git a/src/database/index.mjs b/src/database/index.mjs new file mode 100644 index 00000000..2b151a51 --- /dev/null +++ b/src/database/index.mjs @@ -0,0 +1,7 @@ +import * as Default from "./Default.json"; +import * as WeChat from "./WeChat.json"; + +export default Database = { + "Default": Default, + "WeChat": WeChat, +}; diff --git a/src/function/setENV.mjs b/src/function/setENV.mjs new file mode 100644 index 00000000..903704be --- /dev/null +++ b/src/function/setENV.mjs @@ -0,0 +1,19 @@ +/** + * Set Environment Variables + * @author VirgilClyne + * @param {Object} $ - ENV + * @param {String} name - Persistent Store Key + * @param {Array} platforms - Platform Names + * @param {Object} database - Default DataBase + * @return {Object} { Settings, Caches, Configs } + */ +export default function setENV($, name, platforms, database) { + console.log(`☑️ Set Environment Variables`, ""); + let { Settings, Caches, Configs } = $.getENV(name, platforms, database); + /***************** Settings *****************/ + console.log(`✅ Set Environment Variables, Settings: ${typeof Settings}, Settings内容: ${JSON.stringify(Settings)}`, ""); + /***************** Caches *****************/ + //console.log(`✅ ${$.name}, Set Environment Variables`, `Caches: ${typeof Caches}`, `Caches内容: ${JSON.stringify(Caches)}`, ""); + /***************** Configs *****************/ + return { Settings, Caches, Configs }; +};