├── .github └── workflows │ └── build.yml ├── Dockerfile ├── README.md ├── client ├── .gitignore ├── .vscode │ └── extensions.json ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public │ └── vite.svg ├── src │ ├── App.vue │ ├── assets │ │ ├── Captcha.js │ │ ├── HttpRequest.js │ │ ├── Request.js │ │ ├── Utils.js │ │ └── vue.svg │ ├── components │ │ ├── Admin.vue │ │ ├── AliCaptcha.vue │ │ ├── Default.vue │ │ ├── Dialog.vue │ │ ├── Geetest3Captcha.vue │ │ ├── Geetest4Captcha.vue │ │ ├── ImageCaptcha.vue │ │ ├── Login.vue │ │ ├── Message.vue │ │ ├── Notification.vue │ │ ├── TencentCaptcha.vue │ │ └── YiDunCapacha.vue │ ├── main.js │ ├── router │ │ └── router.js │ ├── stores │ │ └── counter.js │ └── style.css └── vite.config.js └── server ├── Funtion ├── jwt.js ├── key.js ├── ql.js ├── utils.js ├── valueApi.js └── webApi.js ├── WXAuth └── gacmotor.js ├── apps ├── apps.js ├── beijingev.js ├── bilibili.js ├── crazyreader.js ├── gacmotor.js ├── geega.js └── geely.js ├── data.json ├── data_gac.json ├── dist └── .md ├── index.js ├── jwt.key ├── package-lock.json ├── package.json ├── utils ├── checkParams.js ├── crypto.js ├── httpRequest.js ├── sign.js └── utils.js └── value.json /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Vue and Move to Server 2 | 3 | on: 4 | push: 5 | branches: 6 | - main # 在 push 到 main 分支时触发 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout Repository 14 | uses: actions/checkout@v4 15 | - name: Set timezone to Asia/Shanghai 16 | run: | 17 | sudo timedatectl set-timezone Asia/Shanghai 18 | date 19 | - name: Set up QEMU 20 | uses: docker/setup-qemu-action@v3 21 | 22 | - name: Set up Docker Buildx 23 | uses: docker/setup-buildx-action@v3 24 | - name: Set up Node.js 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: "20" 28 | 29 | - name: Install Dependencies 30 | run: cd ./client && npm install && npm run build 31 | 32 | - name: Move build to server dist 33 | run: mv ./client/dist/* ./server/dist/ 34 | - name: server install 35 | run: cd ./server && npm install 36 | - name: Login to Docker Hub 37 | uses: docker/login-action@v3 38 | with: 39 | username: ${{ secrets.DOCKER_USERNAME }} 40 | password: ${{ secrets.DOCKER_PASSWORD }} 41 | 42 | - name: Build and push Docker image 43 | uses: docker/build-push-action@v6 44 | with: 45 | context: . 46 | platforms: linux/amd64,linux/arm64 47 | push: true 48 | tags: ${{ secrets.DOCKER_USERNAME }}/woolweb:latest -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine 2 | 3 | WORKDIR /app 4 | 5 | COPY ./server/package*.json ./ 6 | 7 | RUN npm install 8 | 9 | COPY ./server . 10 | 11 | EXPOSE 1433 12 | 13 | # 启动应用 14 | CMD ["node", "index.js"] 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ```yml 2 | services: 3 | woolweb: 4 | image: dockerpull.com/smallfawn/woolweb 5 | ports: 6 | - "1433:1433" # 映射 1433 端口 7 | volumes: 8 | - ./data.json:/app/data.json # 映射 data.json 9 | - ./value.json:/app/value.json # 映射 value.json 10 | ``` 11 | 12 | # QLScriptpublic 13 | # JD 京东账密登录协议版本已发布 DOCKER一键部署 对接青龙 对接BOT 14 | 购买地址 15 | http://smshop.back1.idcfengye.com/ 16 | 17 | 体验地址 18 | http://smjd.back1.idcfengye.com/ 19 | # data.json 后台http://127.0.0.1:1433/#/admin 先注册后登录 然后必填qinglong配置 20 | ```json 21 | { 22 | "web": { 23 | "name": "A", 24 | "notice": "A" 25 | }, 26 | "qinglong": { 27 | "url": "", 28 | "id": "", 29 | "secret": "", 30 | "version": "new" 31 | }, 32 | "admin": { 33 | "username": "", 34 | "password": "" 35 | } 36 | } 37 | ``` 38 | # value.json 配置 不懂不要动 39 | ```json 40 | { 41 | "applist": [ 42 | { 43 | "name": "测试", 44 | "variable": "demoaaaa", 45 | "test": "测试哦", 46 | "regular": "", 47 | "envSplitor": null 48 | } 49 | ] 50 | } 51 | ``` 52 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /client/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # WoolWeb 2 | 3 | 🟢: 已完成 🔴: 未完成 🟡: 正开发 4 | 5 | | 状态 | 功能 | 详细 | 版本代号 | 6 | | --- | --- | --- | --- | 7 | | 🟢 | Docker搭建 | 使用Docker一键搭建 | docker正式版-V1 | 8 | | 🟢 | 对接青龙面板 | 上传变量(V2.11青龙) | docker正式版-V1 | 9 | | 🟢️ | 管理员注册与登录 | 管理员页面 | docker正式版-V1 | 10 | | 🟢 | 二维码登录 | 实现扫描二维码获取COOKIE | docker正式版-V1 | 11 | | 🟢 | 短信登录 | 实现扫描二维码获取COOKIE | docker正式版-V1 | 12 | | 🟢 | 账号密码登录 | 实现扫描二维码获取COOKIE | docker正式版-V1 | 13 | | 🟢 | 自定义变量上传 | 实现自定义变量上传到青龙 | docker正式版-V1 | 14 | | 🟢 | 单独变量模式 | 账号一对一变量 | docker正式版-V1.3 | 15 | 16 | | 状态 | APP | COOKIE | 版本代号 | 17 | | --- | --- | --- | --- | 18 | | 🟢 | 哔哩哔哩 | 接口返回 | test | 19 | | 🟢️ | 广汽传祺 | 接口返回 | test | 20 | | 🟢 | 吉利汽车 | 接口返回 | test | 21 | | 🟢 | 北京汽车 | 接口返回 | test | 22 | | 🟢 | 疯读小说 | 接口返回 | test | 23 | | 🔴 | 待增加 | 接口返回 | test | 24 | | 🔴 | 金彩云 | 接口返回 | test | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | WoolWeb -- 您的好帮手 9 | 10 | 11 | 12 |
13 | 14 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "axios": "^1.5.1", 13 | "crypto-js": "^4.2.0", 14 | "element-plus": "^2.4.1", 15 | "pinia": "^2.1.7", 16 | "qrcode": "^1.5.3", 17 | "vue": "^3.3.4", 18 | "vue-router": "^4.2.5" 19 | }, 20 | "devDependencies": { 21 | "@vitejs/plugin-vue": "^4.2.3", 22 | "vite": "^4.4.5" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /client/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /client/src/assets/Captcha.js: -------------------------------------------------------------------------------- 1 | /* 2 | WoolWeb Captcha 3 | */ 4 | export { 5 | setCaptcha, 6 | } 7 | const Captcha_Config = { 8 | "TencentCaptcha": { 9 | ScriptUrl: "https://turing.captcha.qcloud.com/TCaptcha.js", 10 | ElementId: "TencentCaptcha" 11 | }, 12 | "YiDunCaptcha": { 13 | ScriptUrl: "https://cstaticdun.126.net/load.min.js", 14 | ElementId: "YiDunCaptcha" 15 | }, 16 | "Geetest4Captcha": { 17 | ScriptUrl: "https://static.geetest.com/v4/gt4.js", 18 | ElementId: "Geetest4Captcha" 19 | }, 20 | "Geetest3Captcha": { 21 | ScriptUrl: "https://static.geetest.com/static/js/gt.0.4.9.js", 22 | ElementId: "Geetest3Captcha" 23 | }, 24 | "AliCaptcha": { 25 | ScriptUrl: "https://g.alicdn.com/AWSC/AWSC/awsc.js", 26 | ElementId: "AliCaptcha" 27 | } 28 | } 29 | 30 | async function setCaptcha(type) { 31 | // 判断是否已经引入对应的ScriptUrl 32 | if (document.querySelector(`script[src="${Captcha_Config[type]["ScriptUrl"]}"]`)) { 33 | //console.log("JS已存在,无需加载"); 34 | return true 35 | } else { 36 | let script = document.createElement("script"); 37 | script.type = "text/javascript"; 38 | script.src = Captcha_Config[type]["ScriptUrl"]; 39 | document.head.appendChild(script); 40 | let result = await scriptLoadStatus(script); 41 | return result; 42 | } 43 | } 44 | 45 | 46 | function scriptLoadStatus(script) { 47 | return new Promise((resolve, reject) => { 48 | script.onload = () => { 49 | resolve(true) 50 | } 51 | script.onerror = () => { 52 | reject(false) 53 | } 54 | }) 55 | } -------------------------------------------------------------------------------- /client/src/assets/HttpRequest.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { getTimeStamp, getRandomString } from './Utils' 3 | let ab = [] 4 | for (let i = 97; i <= 122; i++) { 5 | ab.push(String.fromCharCode(i)); 6 | } 7 | function httpRequest(options) { 8 | let t = getTimeStamp() 9 | let n = getRandomString(10) 10 | options.headers["t"] = t 11 | options.headers["n"] = n 12 | options.headers["s"] = gs(options) 13 | return new Promise((resolve, reject) => { 14 | axios(options).then(res => { 15 | resolve(res) 16 | }).catch(err => { 17 | reject(err) 18 | }) 19 | }) 20 | } 21 | function gs(req) { 22 | const { url, method, data } = req; 23 | let k = "a1752adfba6ebf0f0423654973ecee84" 24 | let t = req.headers.t 25 | let n = req.headers.n 26 | let u = url 27 | let m = method 28 | let b = JSON.stringify(data) 29 | let r = m + u + b + t + n + k 30 | return hs(r) 31 | } 32 | function hs(a) { 33 | a = a.toString() 34 | function b(a, b) { 35 | return (a << b) | (a >>> (32 - b)); 36 | } 37 | function c(a, b) { 38 | var c, d, e, f, g; 39 | return ( 40 | (e = 2147483648 & a), 41 | (f = 2147483648 & b), 42 | (c = 1073741824 & a), 43 | (d = 1073741824 & b), 44 | (g = (1073741823 & a) + (1073741823 & b)), 45 | c & d 46 | ? 2147483648 ^ g ^ e ^ f 47 | : c | d 48 | ? 1073741824 & g 49 | ? 3221225472 ^ g ^ e ^ f 50 | : 1073741824 ^ g ^ e ^ f 51 | : g ^ e ^ f 52 | ); 53 | } 54 | function d(a, b, c) { 55 | return (a & b) | (~a & c); 56 | } 57 | function e(a, b, c) { 58 | return (a & c) | (b & ~c); 59 | } 60 | function f(a, b, c) { 61 | return a ^ b ^ c; 62 | } 63 | function g(a, b, c) { 64 | return b ^ (a | ~c); 65 | } 66 | function h(a, e, f, g, h, i, j) { 67 | return (a = c(a, c(c(d(e, f, g), h), j))), c(b(a, i), e); 68 | } 69 | function i(a, d, f, g, h, i, j) { 70 | return (a = c(a, c(c(e(d, f, g), h), j))), c(b(a, i), d); 71 | } 72 | function j(a, d, e, g, h, i, j) { 73 | return (a = c(a, c(c(f(d, e, g), h), j))), c(b(a, i), d); 74 | } 75 | function k(a, d, e, f, h, i, j) { 76 | return (a = c(a, c(c(g(d, e, f), h), j))), c(b(a, i), d); 77 | } 78 | function l(a) { 79 | for ( 80 | var b, 81 | c = a.length, 82 | d = c + 8, 83 | e = (d - (d % 64)) / 64, 84 | f = 16 * (e + 1), 85 | g = new Array(f - 1), 86 | h = 0, 87 | i = 0; 88 | c > i; 89 | 90 | ) 91 | (b = (i - (i % 4)) / 4), 92 | (h = (i % 4) * 8), 93 | (g[b] = g[b] | (a.charCodeAt(i) << h)), 94 | i++; 95 | return ( 96 | (b = (i - (i % 4)) / 4), 97 | (h = (i % 4) * 8), 98 | (g[b] = g[b] | (128 << h)), 99 | (g[f - 2] = c << 3), 100 | (g[f - 1] = c >>> 29), 101 | g 102 | ); 103 | } 104 | function m(a) { 105 | var b, 106 | c, 107 | d = "", 108 | e = ""; 109 | for (c = 0; 3 >= c; c++) 110 | (b = (a >>> (8 * c)) & 255), 111 | (e = "0" + b.toString(16)), 112 | (d += e.substr(e.length - 2, 2)); 113 | return d; 114 | } 115 | function n(a) { 116 | a = a.replace(/\r\n/g, "\n"); 117 | for (var b = "", c = 0; c < a.length; c++) { 118 | var d = a.charCodeAt(c); 119 | 128 > d 120 | ? (b += String.fromCharCode(d)) 121 | : d > 127 && 2048 > d 122 | ? ((b += String.fromCharCode((d >> 6) | 192)), 123 | (b += String.fromCharCode((63 & d) | 128))) 124 | : ((b += String.fromCharCode((d >> 12) | 224)), 125 | (b += String.fromCharCode(((d >> 6) & 63) | 128)), 126 | (b += String.fromCharCode((63 & d) | 128))); 127 | } 128 | return b; 129 | } 130 | var o, 131 | p, 132 | q, 133 | r, 134 | s, 135 | t, 136 | u, 137 | v, 138 | w, 139 | x = [], 140 | y = 7, 141 | z = 12, 142 | A = 17, 143 | B = 22, 144 | C = 5, 145 | D = 9, 146 | E = 14, 147 | F = 20, 148 | G = 4, 149 | H = 11, 150 | I = 16, 151 | J = 23, 152 | K = 6, 153 | L = 10, 154 | M = 15, 155 | N = 21; 156 | for ( 157 | a = n(a), 158 | x = l(a), 159 | t = 1414213562, 160 | u = 3141592653, 161 | v = 2718281828, 162 | w = 1234567890, 163 | o = 0; 164 | o < x.length; 165 | o += 16 166 | ) 167 | (p = t), 168 | (q = u), 169 | (r = v), 170 | (s = w), 171 | (t = h(t, u, v, w, x[o + 0], y, 3614090360)), 172 | (w = h(w, t, u, v, x[o + 1], z, 3905402710)), 173 | (v = h(v, w, t, u, x[o + 2], A, 606105819)), 174 | (u = h(u, v, w, t, x[o + 3], B, 3250441966)), 175 | (t = h(t, u, v, w, x[o + 4], y, 4118548399)), 176 | (w = h(w, t, u, v, x[o + 5], z, 1200080426)), 177 | (v = h(v, w, t, u, x[o + 6], A, 2821735955)), 178 | (u = h(u, v, w, t, x[o + 7], B, 4249261313)), 179 | (t = h(t, u, v, w, x[o + 8], y, 1770035416)), 180 | (w = h(w, t, u, v, x[o + 9], z, 2336552879)), 181 | (v = h(v, w, t, u, x[o + 10], A, 4294925233)), 182 | (u = h(u, v, w, t, x[o + 11], B, 2304563134)), 183 | (t = h(t, u, v, w, x[o + 12], y, 1804603682)), 184 | (w = h(w, t, u, v, x[o + 13], z, 4254626195)), 185 | (v = h(v, w, t, u, x[o + 14], A, 2792965006)), 186 | (u = h(u, v, w, t, x[o + 15], B, 1236535329)), 187 | (t = i(t, u, v, w, x[o + 1], C, 4129170786)), 188 | (w = i(w, t, u, v, x[o + 6], D, 3225465664)), 189 | (v = i(v, w, t, u, x[o + 11], E, 643717713)), 190 | (u = i(u, v, w, t, x[o + 0], F, 3921069994)), 191 | (t = i(t, u, v, w, x[o + 5], C, 3593408605)), 192 | (w = i(w, t, u, v, x[o + 10], D, 38016083)), 193 | (v = i(v, w, t, u, x[o + 15], E, 3634488961)), 194 | (u = i(u, v, w, t, x[o + 4], F, 3889429448)), 195 | (t = i(t, u, v, w, x[o + 9], C, 568446438)), 196 | (w = i(w, t, u, v, x[o + 14], D, 3275163606)), 197 | (v = i(v, w, t, u, x[o + 3], E, 4107603335)), 198 | (u = i(u, v, w, t, x[o + 8], F, 1163531501)), 199 | (t = i(t, u, v, w, x[o + 13], C, 2850285829)), 200 | (w = i(w, t, u, v, x[o + 2], D, 4243563512)), 201 | (v = i(v, w, t, u, x[o + 7], E, 1735328473)), 202 | (u = i(u, v, w, t, x[o + 12], F, 2368359562)), 203 | (t = j(t, u, v, w, x[o + 5], G, 4294588738)), 204 | (w = j(w, t, u, v, x[o + 8], H, 2272392833)), 205 | (v = j(v, w, t, u, x[o + 11], I, 1839030562)), 206 | (u = j(u, v, w, t, x[o + 14], J, 4259657740)), 207 | (t = j(t, u, v, w, x[o + 1], G, 2763975236)), 208 | (w = j(w, t, u, v, x[o + 4], H, 1272893353)), 209 | (v = j(v, w, t, u, x[o + 7], I, 4139469664)), 210 | (u = j(u, v, w, t, x[o + 10], J, 3200236656)), 211 | (t = j(t, u, v, w, x[o + 13], G, 681279174)), 212 | (w = j(w, t, u, v, x[o + 0], H, 3936430074)), 213 | (v = j(v, w, t, u, x[o + 3], I, 3572445317)), 214 | (u = j(u, v, w, t, x[o + 6], J, 76029189)), 215 | (t = j(t, u, v, w, x[o + 9], G, 3654602809)), 216 | (w = j(w, t, u, v, x[o + 12], H, 3873151461)), 217 | (v = j(v, w, t, u, x[o + 15], I, 530742520)), 218 | (u = j(u, v, w, t, x[o + 2], J, 3299628645)), 219 | (t = k(t, u, v, w, x[o + 0], K, 4096336452)), 220 | (w = k(w, t, u, v, x[o + 7], L, 1126891415)), 221 | (v = k(v, w, t, u, x[o + 14], M, 2878612391)), 222 | (u = k(u, v, w, t, x[o + 5], N, 4237533241)), 223 | (t = k(t, u, v, w, x[o + 12], K, 1700485571)), 224 | (w = k(w, t, u, v, x[o + 3], L, 2399980690)), 225 | (v = k(v, w, t, u, x[o + 10], M, 4293915773)), 226 | (u = k(u, v, w, t, x[o + 1], N, 2240044497)), 227 | (t = k(t, u, v, w, x[o + 8], K, 1873313359)), 228 | (w = k(w, t, u, v, x[o + 15], L, 4264355552)), 229 | (v = k(v, w, t, u, x[o + 6], M, 2734768916)), 230 | (u = k(u, v, w, t, x[o + 13], N, 1309151649)), 231 | (t = k(t, u, v, w, x[o + 4], K, 4149444226)), 232 | (w = k(w, t, u, v, x[o + 11], L, 3174756917)), 233 | (v = k(v, w, t, u, x[o + 2], M, 718787259)), 234 | (u = k(u, v, w, t, x[o + 9], N, 3951481745)), 235 | (t = c(t, p)), 236 | (u = c(u, q)), 237 | (v = c(v, r)), 238 | (w = c(w, s)); 239 | var O = m(t) + m(u) + m(v) + m(w); 240 | return O.toLowerCase().split('').reverse().join(''); 241 | } 242 | export default httpRequest -------------------------------------------------------------------------------- /client/src/assets/Request.js: -------------------------------------------------------------------------------- 1 | import HttpRequest from "./HttpRequest" 2 | 3 | export { appsApi, adminLogin, adminRegister, adminGet, adminSet, getWeb, up, loginRequest, sendSMSRequest, updateValue, qrcodeGetApi, qrcodeLoginApi, testQingLong, } 4 | const appsApi = async function (type, data) { 5 | let options = { 6 | method: 'GET', 7 | url: `/api/main/apps?type=${type}&data=${data}`, 8 | headers: {} 9 | } 10 | let { data: result } = await HttpRequest(options) 11 | return result 12 | } 13 | const qrcodeGetApi = async function (appname) { 14 | let options = { 15 | method: 'GET', 16 | url: `/api/main/qrcode/get?app=${appname}`, 17 | headers: { 18 | 19 | } 20 | } 21 | let { data: result } = await HttpRequest(options) 22 | return result 23 | } 24 | const qrcodeLoginApi = async function (appname, value) { 25 | let options = { 26 | url: `/api/main/qrcode/login`, 27 | method: 'POST', 28 | headers: { 'Content-Type': 'application/json; charset=UTF-8' }, 29 | data: JSON.stringify({ app: appname, value: value }) 30 | } 31 | let { data: result } = await HttpRequest(options) 32 | return result 33 | } 34 | 35 | 36 | const testQingLong = async function (options) { 37 | let url = options.url 38 | let id = options.id 39 | let secret = options.secret 40 | let { data: result } = await HttpRequest({ 41 | url: `/api/user/test`, 42 | method: 'POST', 43 | headers: { 'Content-Type': 'application/json; charset=UTF-8' }, 44 | data: JSON.stringify({ url: url, id: id, secret: secret }) 45 | }) 46 | return result 47 | } 48 | const updateValue = async function (options) { 49 | let { data: result } = await HttpRequest({ 50 | url: `/api/user/value/update`, method: 'POST', 51 | headers: { 52 | 'Content-Type': 'application/json; charset=UTF-8', 53 | token: localStorage.getItem("WoolWebAdminToken") 54 | }, 55 | data: JSON.stringify(options) 56 | }) 57 | return result 58 | } 59 | /** 60 | * 发送短信通用API 61 | * @param {*} request_body 其他组件构建的body 62 | * @returns 63 | */ 64 | const sendSMSRequest = async function (request_body) { 65 | let options = { 66 | url: `/api/main/sms`, 67 | method: "POST", 68 | headers: { "Content-Type": "application/json" }, 69 | data: JSON.stringify(request_body), 70 | } 71 | let { data: result } = await HttpRequest(options) 72 | return result 73 | } 74 | /** 75 | * 登录通用API 76 | * @param {*} request_body 其他组件构建的body 77 | * @returns 78 | */ 79 | const loginRequest = async function (request_body) { 80 | //console.log(request_body); 81 | let options = { 82 | url: `/api/main/login`, 83 | method: "POST", 84 | headers: { "Content-Type": "application/json" }, 85 | data: JSON.stringify(request_body), 86 | } 87 | let { data: result } = await HttpRequest(options) 88 | return result 89 | } 90 | /** 91 | * 后台登陆 92 | * @param {*} username 用户名 93 | * @param {*} password 密码 94 | * @returns token 95 | */ 96 | const adminLogin = async function (username, password) { 97 | let options = { 98 | url: "/api/user/login", 99 | method: "POST", 100 | headers: { "Content-Type": "application/json" }, 101 | data: JSON.stringify({ username: username, password: password }), 102 | } 103 | let { data: result } = await HttpRequest(options) 104 | return result 105 | } 106 | /** 107 | * 后台注册 108 | * @param {*} username 用户名 109 | * @param {*} password 密码 110 | * @returns 状态 111 | */ 112 | const adminRegister = async function (username, password) { 113 | let options = { 114 | url: "/api/user/register", 115 | method: "POST", 116 | headers: { "Content-Type": "application/json" }, 117 | data: JSON.stringify({ username: username, password: password }), 118 | } 119 | let { data: result } = await HttpRequest(options) 120 | return result 121 | } 122 | /** 123 | * 获取后台设置的数据 124 | * @param {*} variable 键 125 | * @returns 值 126 | */ 127 | const adminGet = async function (variable) { 128 | let options = { 129 | url: "/api/user/get", 130 | method: "POST", 131 | headers: { "Content-Type": "application/json", token: localStorage.getItem("WoolWebAdminToken") }, 132 | data: JSON.stringify({ variable: variable }), 133 | } 134 | let { data: result } = await HttpRequest(options) 135 | return result 136 | } 137 | 138 | /** 139 | * 设置数据 140 | * @param {*} variable 键 141 | * @param {*} value 值 142 | * @returns 状态 143 | */ 144 | const adminSet = async function (variable, value) { 145 | let options = { 146 | url: "/api/user/set", 147 | method: "POST", 148 | headers: { "Content-Type": "application/json", token: localStorage.getItem("WoolWebAdminToken") }, 149 | data: JSON.stringify({ variable: variable, value: value }), 150 | } 151 | let { data: result } = await HttpRequest(options) 152 | return result 153 | } 154 | /** 155 | * 获取WEB 156 | * @returns 信息 157 | */ 158 | const getWeb = async function () { 159 | let options = { 160 | url: "/api/user/init", 161 | method: "GET", 162 | headers: { 163 | 164 | } 165 | } 166 | let { data: result } = await HttpRequest(options) 167 | return result 168 | } 169 | /** 170 | * 上传变量 171 | */ 172 | const up = async function (variable, value, remark = null, envSplitor = null) { 173 | let options = { 174 | url: "/api/user/update", 175 | method: "POST", 176 | headers: { 177 | "Content-Type": "application/json" 178 | }, 179 | data: JSON.stringify({ variable: variable, value: value, remark: remark, envSplitor: envSplitor }) 180 | } 181 | let { data: result } = await HttpRequest(options) 182 | return result 183 | } -------------------------------------------------------------------------------- /client/src/assets/Utils.js: -------------------------------------------------------------------------------- 1 | export { testPhoneNumber, testEmail, getUUID, getRandomString, getTimeStamp } 2 | /** 3 | * 匹配中国大陆的手机号码 格式是以13-19开头的11位数字 4 | * @param {*} phoneNumber 5 | * @returns 6 | */ 7 | function testPhoneNumber(phoneNumber) { 8 | var regExp = /^1[3-9][0-9]\d{8}$/; 9 | return regExp.test(phoneNumber); 10 | } 11 | /** 12 | * 校验邮箱格式 13 | * @param {*} email 14 | * @returns 15 | */ 16 | function testEmail(email) { 17 | var regExp = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/; 18 | return regExp.test(email); 19 | } 20 | /** 21 | * 获取uuid 格式8-4-4-4-12 22 | * @returns 23 | */ 24 | function getUUID() { 25 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 26 | var r = Math.random() * 16 | 0, 27 | v = c == 'x' ? r : (r & 0x3 | 0x8); 28 | return v.toString(16); 29 | }); 30 | } 31 | /** 32 | * 获取固定长度的随机字母小写+数字 33 | * @param {*} length 34 | * @returns 35 | */ 36 | function getRandomString(length) { 37 | var result = ''; 38 | var characters = '0123456789abcdefghijklmnopqrstuvwxyz'; 39 | for (var i = 0; i < length; i++) { 40 | result += characters.charAt(Math.floor(Math.random() * characters.length)); 41 | } 42 | return result; 43 | } 44 | function getTimeStamp() { 45 | return new Date().getTime() 46 | } -------------------------------------------------------------------------------- /client/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/components/Admin.vue: -------------------------------------------------------------------------------- 1 | 68 | 209 | -------------------------------------------------------------------------------- /client/src/components/AliCaptcha.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /client/src/components/Default.vue: -------------------------------------------------------------------------------- 1 | 414 | 415 | 504 | 505 | -------------------------------------------------------------------------------- /client/src/components/Dialog.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 36 | -------------------------------------------------------------------------------- /client/src/components/Geetest3Captcha.vue: -------------------------------------------------------------------------------- 1 | 5 | 48 | 49 | -------------------------------------------------------------------------------- /client/src/components/Geetest4Captcha.vue: -------------------------------------------------------------------------------- 1 | 2 | 15 | -------------------------------------------------------------------------------- /client/src/components/ImageCaptcha.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /client/src/components/Login.vue: -------------------------------------------------------------------------------- 1 | 16 | 57 | -------------------------------------------------------------------------------- /client/src/components/Message.vue: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/components/Notification.vue: -------------------------------------------------------------------------------- 1 | 4 | 18 | -------------------------------------------------------------------------------- /client/src/components/TencentCaptcha.vue: -------------------------------------------------------------------------------- 1 | 5 | 91 | -------------------------------------------------------------------------------- /client/src/components/YiDunCapacha.vue: -------------------------------------------------------------------------------- 1 | 4 | 40 | -------------------------------------------------------------------------------- /client/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import ElementPlus from 'element-plus' 4 | import 'element-plus/dist/index.css' 5 | import App from './App.vue' 6 | import { createPinia } from 'pinia' 7 | import router from './router/router'; 8 | 9 | const pinia = createPinia() 10 | 11 | const app = createApp(App) 12 | app.use(router) 13 | app.use(pinia) 14 | app.use(ElementPlus) 15 | app.mount('#app') -------------------------------------------------------------------------------- /client/src/router/router.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHashHistory } from 'vue-router'; 2 | 3 | import Default from "../components/Default.vue"; 4 | import Login from '../components/Login.vue'; 5 | import Admin from '../components/Admin.vue'; 6 | 7 | const routes = [ 8 | { path: '/', component: Default }, 9 | { path: '/Login', component: Login }, 10 | { path: '/Admin', component: Admin } 11 | ]; 12 | 13 | const router = createRouter({ 14 | history: createWebHashHistory(), 15 | routes 16 | }); 17 | 18 | export default router; -------------------------------------------------------------------------------- /client/src/stores/counter.js: -------------------------------------------------------------------------------- 1 | // stores/counter.js 2 | import { defineStore } from 'pinia' 3 | 4 | export const useCounterStore = defineStore('counter', { 5 | state: () => { 6 | return { 7 | Notification: { 8 | status: false, 9 | message: "", 10 | title: "", 11 | }, 12 | AliCaptcha: { 13 | success: { 14 | sessionId: "", 15 | sig: "", 16 | token: "" 17 | }, 18 | init: { 19 | appKey: "", 20 | scene: "", 21 | }, 22 | show: null, 23 | status: { 24 | show: false, 25 | success: false 26 | }, 27 | }, 28 | Message: { 29 | status: false, 30 | message: "", 31 | type: "success", 32 | }, 33 | variable: "", 34 | value: "", 35 | loginType: '', 36 | LoginElementId: "", 37 | Geetest3Captcha: { 38 | success: { 39 | variable: "", 40 | seccode: "", 41 | }, 42 | init: { 43 | gt: "", 44 | challenge: "", 45 | }, 46 | show: null, 47 | status: { 48 | show: false, 49 | success: false 50 | }, 51 | }, 52 | Geetest4Captcha: { 53 | success: { 54 | }, 55 | show: null, 56 | init: { 57 | captchaId: "", 58 | }, 59 | status: { 60 | show: false, 61 | success: false 62 | }, 63 | }, 64 | appInfo: {}, 65 | username: "", 66 | password: "", 67 | TencentCaptcha: { 68 | success: { 69 | ticket: "", 70 | randstr: "", 71 | }, 72 | show: null, 73 | init: { 74 | appid: "", 75 | 76 | }, 77 | status: { 78 | show: false, 79 | success: false 80 | }, 81 | }, 82 | YiDunCaptcha: { 83 | show: null, 84 | status: { 85 | show: false, 86 | success: false 87 | }, 88 | init: { 89 | captchaId: "", 90 | }, 91 | }, 92 | AppName: "", 93 | CaptchaConfig: {}, 94 | phone: "", 95 | code: "", 96 | admin: { 97 | username: "", 98 | password: "", 99 | }, 100 | dialog: { 101 | status: false, 102 | message: "", 103 | dialogStatus: null, 104 | } 105 | } 106 | }, 107 | actions: { 108 | set_custom(variable, value) { 109 | this.variable = variable; 110 | this.value = value; 111 | }, 112 | set_Notification(options) { 113 | this.Notification.status = options.status 114 | this.Notification.message = options.message 115 | this.Notification.title = options.title 116 | 117 | }, 118 | setDiaLog(status, message) { 119 | this.dialog.status = status 120 | this.dialog.message = message 121 | }, 122 | set_Message(status, message, type = "success") { 123 | //succeess warning error //message 124 | this.Message.status = status 125 | this.Message.message = message 126 | this.Message.type = type 127 | }, 128 | setDiaLogStatus(status) { 129 | this.dialog.dialogStatus = status 130 | }, 131 | set_Admin(adminUsername, adminPassword) { 132 | this.admin.username = adminUsername 133 | this.admin.password = adminPassword 134 | }, 135 | set_loginType(type) { 136 | this.loginType = type 137 | }, 138 | set_UsernameAndPassword(options) { 139 | this.username = options.username 140 | this.password = options.password 141 | }, 142 | set_MobileAndCode(options) { 143 | this.phone = options.phone 144 | this.code = options.code 145 | }, 146 | set_captcha_show(options) { 147 | this[options.type].show = options.show 148 | }, 149 | set_NoCaptcha() { 150 | this.Geetest3Captcha.show = null 151 | this.TencentCaptcha.show = null 152 | this.YiDunCaptcha.show = null 153 | }, 154 | /** 155 | * 设置验证码 156 | */ 157 | set_Captcha(options) { 158 | this.CaptchaConfig = options 159 | this.LoginElementId = options.type 160 | this[options.type].status.show = true 161 | this[options.type].init = options.config 162 | this[options.type].status.success = false 163 | }, 164 | set_captcha_success(options) { 165 | //设置成功的返回 166 | this[options.type].success = options.success 167 | //表示完成 168 | this[options.type].status.success = true 169 | }, 170 | set_AppName(newValue) { 171 | this.AppName = newValue 172 | }, 173 | set_appInfo(newValue) { 174 | this.appInfo = newValue 175 | } 176 | }, 177 | }) -------------------------------------------------------------------------------- /client/src/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | display: flex; 4 | place-items: center; 5 | min-width: 320px; 6 | min-height: 100vh; 7 | } 8 | 9 | 10 | #app { 11 | max-width: 1280px; 12 | margin: 0 auto; 13 | padding: 2rem; 14 | text-align: center; 15 | } 16 | 17 | @media (prefers-color-scheme: light) { 18 | :root { 19 | color: #213547; 20 | background-color: #ffffff; 21 | 22 | 23 | /* 设背景图的其他属性,比如尺寸、位置等 */ 24 | 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /client/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import path from 'path' 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()], 7 | build: { 8 | rollupOptions: { 9 | output: { 10 | manualChunks: (id) => { 11 | if (id.includes('node_modules')) { 12 | return 'vendor'; 13 | } 14 | } 15 | }, 16 | }, 17 | }, 18 | server: { 19 | proxy: { 20 | // 配置反向代理 21 | '/api/user': { 22 | target: 'http://127.0.0.1:3002', // 目标服务器的地址 23 | changeOrigin: true, // 开启代理服务器,将请求转发到目标服务器上 24 | //rewrite: (path) => path.replace(/^\/api/, '') // 路径重写,去掉开头的 /api 25 | }, 26 | '/api/main': { 27 | target: 'http://127.0.0.1:3000', // 目标服务器的地址 28 | changeOrigin: true, // 开启代理服务器,将请求转发到目标服务器上 29 | //rewrite: (path) => path.replace(/^\/api/, '') // 路径重写,去掉开头的 /api 30 | } 31 | } 32 | } 33 | }) 34 | -------------------------------------------------------------------------------- /server/Funtion/jwt.js: -------------------------------------------------------------------------------- 1 | const JWT = require('jsonwebtoken');//cookie 2 | /** 3 | * 生成token 4 | * @param {Object} payload 需要签名的信息 必须是json格式 5 | * @returns 6 | */ 7 | function setToken(payload, key) { 8 | return JWT.sign(payload, key, { 9 | }); 10 | } 11 | 12 | 13 | /** 14 | * 检查token是否正确 15 | * @param {*} token 16 | * @returns 加密信息 17 | */ 18 | function checkToken(token, key) { 19 | return new Promise((resolve, reject) => { 20 | JWT.verify(token, key, (err, decoded) => { 21 | if (err) { 22 | //reject(false); 23 | resolve(false) 24 | } else { 25 | resolve(decoded); 26 | } 27 | }); 28 | }); 29 | } 30 | 31 | module.exports = { 32 | setToken, 33 | checkToken 34 | } -------------------------------------------------------------------------------- /server/Funtion/key.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs').promises; 2 | async function setKey() { 3 | let KeyStr = creatKey() 4 | try { 5 | await fs.writeFile('jwt.key', KeyStr, 'utf8'); 6 | //console.log('文件写入成功'); 7 | return true 8 | } catch (err) { 9 | //console.error('写入文件时出错:', err); 10 | return false 11 | } 12 | } 13 | function creatKey() { 14 | const a = "qwertyuiop[]\\asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+-=1234567890"; 15 | let b = ""; 16 | for (let i = 0; i < 32; i++) { 17 | const c = Math.floor(Math.random() * a.length); 18 | b += a.charAt(c); 19 | } 20 | function e(input) { 21 | const crypto = require('crypto'); 22 | return crypto.createHash('md5').update(input).digest('hex'); 23 | } 24 | return e(b) + e(new Date().getTime().toString()) 25 | } 26 | async function getKey() { 27 | try { 28 | const data = await fs.readFile('jwt.key', 'utf8'); 29 | return data 30 | } catch (err) { 31 | console.error('读取文件时出错:', err); 32 | return false 33 | } 34 | } 35 | module.exports = { 36 | setKey, 37 | creatKey, 38 | getKey 39 | } -------------------------------------------------------------------------------- /server/Funtion/ql.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | module.exports = { 3 | getToken, 4 | getdata, 5 | setdata, 6 | update, 7 | } 8 | 9 | /** 10 | * 获取青龙临时token 11 | * @returns Authorization 12 | */ 13 | async function getToken(options) { 14 | try { 15 | let { data: result } = await axios.get(`${options.url}/open/auth/token`, { 16 | params: { 17 | client_id: options.id, 18 | client_secret: options.secret 19 | } 20 | }) 21 | if ('code' in result) { 22 | if (result.code == 200) { 23 | return result.data.token_type + ' ' + result.data.token 24 | } 25 | } 26 | } catch (error) { 27 | console.log(`getTOKEN失败`); 28 | 29 | } 30 | } 31 | 32 | /** 33 | * 上传/更新变量 34 | * @param {string} VariableName 变量名 35 | * @param {string} Variable 变量 36 | * @returns 自定义响应体 37 | */ 38 | async function update(url, token, VariableName, Variable, envStrSplitor = "@") { 39 | try { 40 | let originalRes = await getdata(url, token, VariableName) 41 | //console.log(`原数组输出 ` + JSON.stringify(originalRes)); 42 | let originalVariable 43 | if (originalRes.data.length == 0) { 44 | //console.log(`没有变量开始创建`); 45 | let createVariableRes = await setdata(url, token, VariableName, Variable) 46 | if (createVariableRes.code == 200) { 47 | //console.log(`创建变量成功`); 48 | return { status: true, message: "创建变量成功", data: Variable } 49 | } else { 50 | //console.log(`创建变量失败`); 51 | //console.log(createVariableRes); 52 | return { status: false, message: "创建变量失败", data: Variable } 53 | } 54 | } else { 55 | originalVariable = originalRes.data[0].value 56 | console.log(originalVariable); 57 | // 58 | originalVariable += `${envStrSplitor}${Variable}` 59 | // 60 | let originalId = originalRes.data[0].id 61 | let options = { 62 | method: "PUT", 63 | url: `${url}/open/envs`, 64 | headers: { 65 | "Content-Type": "application/json; charset=utf-8", 66 | "Authorization": token 67 | }, 68 | data: { value: originalVariable, name: VariableName, remarks: null, id: originalId } 69 | } 70 | let { data: res } = await axios.request(options) 71 | if ('code' in res) { 72 | if (res.code == 200) { 73 | return { status: true, message: "添加变量成功", data: Variable } 74 | } else { 75 | console.log(res); 76 | return { status: false, message: "添加变量失败", data: Variable } 77 | } 78 | } else { 79 | console.log(res); 80 | return { status: false, message: "添加变量失败", data: Variable } 81 | } 82 | } 83 | } catch (error) { 84 | console.log(error) 85 | console.log(`update失败`); 86 | return { status: false, message: "青龙连通失效", data: Variable } 87 | } 88 | } 89 | /** 90 | * 创建新变量 91 | * @param {string} VariableName 变量名 92 | * @param {string} Variable 变量 93 | * @returns 94 | */ 95 | async function setdata(url, token, VariableName, Variable, remarks = null) { 96 | let options = { 97 | method: "POST", 98 | url: `${url}/open/envs`, 99 | headers: { 100 | "Content-Type": "application/json; charset=utf-8", 101 | "Authorization": token 102 | }, 103 | data: [{ value: Variable, name: VariableName, remarks: remarks }] 104 | } 105 | let { data: result } = await axios.request(options) 106 | return result 107 | } 108 | 109 | /** 110 | * 获取原变量 111 | * @param {string} VariableName 变量名 112 | * @returns 响应体 113 | */ 114 | async function getdata(url, token, VariableName) { 115 | let options = { 116 | method: "GET", 117 | url: `${url}/open/envs?searchValue=${VariableName}`, 118 | headers: { 119 | "Authorization": token 120 | } 121 | } 122 | let { data: res } = await axios.request(options) 123 | if ('code' in res) { 124 | if (res.code == 200) { 125 | return res 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /server/Funtion/utils.js: -------------------------------------------------------------------------------- 1 | function checkParams(...params) { 2 | for (let param of params) { 3 | if (param === undefined || param === null || param === '') { 4 | return false; 5 | } 6 | } 7 | return true; 8 | } 9 | module.exports = { checkParams } -------------------------------------------------------------------------------- /server/Funtion/valueApi.js: -------------------------------------------------------------------------------- 1 | 2 | const fs = require('fs').promises 3 | async function getValue() { 4 | try { 5 | const data = await fs.readFile("value.json", 'utf-8'); 6 | const json = JSON.parse(data); 7 | const applist = json.applist; 8 | return applist; 9 | } catch (error) { 10 | return false 11 | } 12 | } 13 | async function updateValue(json) { 14 | try { 15 | const data = await fs.readFile("value.json", 'utf-8'); 16 | const existingData = JSON.parse(data); 17 | const { applist } = existingData; 18 | // 查找是否有相同 name 的 JSON 对象 19 | const existingIndex = applist.findIndex(obj => obj.name === json.name); 20 | if (existingIndex !== -1) { 21 | // 如果存在相同 name 的 JSON 对象则更新内容 22 | applist[existingIndex] = json; 23 | //console.log('JSON object updated in applist successfully!'); 24 | await fs.writeFile("value.json", JSON.stringify(existingData, null, 2)); 25 | return true 26 | } else { 27 | // 如果不存在则将 JSON 对象添加到 applist 数组中 28 | applist.push(json); 29 | //console.log('JSON object added to applist successfully!'); 30 | await fs.writeFile("value.json", JSON.stringify(existingData, null, 2)); 31 | return true 32 | } 33 | } catch (error) { 34 | return false 35 | } 36 | } 37 | module.exports = { 38 | getValue, 39 | updateValue 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /server/Funtion/webApi.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs').promises; 2 | //const path = require('path'); 3 | // 读取JSON数据 4 | async function readParams() { 5 | try { 6 | const data = await fs.readFile('data.json', 'utf8'); 7 | const jsonData = JSON.parse(data); 8 | return jsonData; 9 | 10 | } catch (err) { 11 | //throw err; 12 | return false 13 | } 14 | } 15 | // 写入JSON数据 16 | async function writeParams(data) { 17 | try { 18 | const jsonData = JSON.stringify(data, null, 2); 19 | await fs.writeFile('data.json', jsonData, 'utf8'); 20 | return true 21 | } catch (err) { 22 | //throw err; 23 | return false 24 | } 25 | } 26 | // 增加或更新数据 27 | async function updateParams(key, value) { 28 | try { 29 | const data = await readParams(); 30 | data[key] = value; 31 | await writeParams(data); 32 | return true 33 | } catch (err) { 34 | return false 35 | } 36 | } 37 | // 删除数据 38 | async function deleteParams(key) { 39 | try { 40 | const data = await readParams(); 41 | delete data[key]; 42 | await writeParams(data); 43 | return true 44 | } catch (err) { 45 | //throw err; 46 | return false 47 | } 48 | } 49 | // 查询数据 50 | async function getParams(key) { 51 | try { 52 | const data = await readParams(); 53 | const value = data[key]; 54 | return value; 55 | } catch (err) { 56 | //throw err; 57 | return false 58 | } 59 | } 60 | 61 | module.exports = { 62 | updateParams, 63 | getParams, 64 | deleteParams 65 | } 66 | -------------------------------------------------------------------------------- /server/WXAuth/gacmotor.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | getUUID, 3 | getSdkTicket, 4 | getAccessToken 5 | } 6 | const { httpRequest } = require('../utils/httpRequest') 7 | const fs = require('fs').promises 8 | async function getUUID() { 9 | let config = await readFile("data_gac.json") 10 | let appid = config.gacmotor.appId 11 | let sdkticket = config.gacmotor.sdkTicket 12 | const { randomString } = require('../utils/utils') 13 | const { Crypto_SHA1 } = require("../utils/crypto") 14 | let noncestr = randomString() 15 | let timestamp = Date.now(); 16 | const signaturePrams = `appid=${appid}&noncestr=${noncestr}&sdk_ticket=${sdkticket}×tamp=${timestamp}`; 17 | const signature = Crypto_SHA1(signaturePrams) 18 | let options = { 19 | url: `https://open.weixin.qq.com/connect/sdk/qrconnect?appid=wx55d651b24ca783fa&noncestr=${noncestr}×tamp=${timestamp}&scope=snsapi_userinfo&signature=${signature}` 20 | } 21 | let { data: uuidResult } = await httpRequest(options) 22 | if (uuidResult.errcode == 0) { 23 | return uuidResult.uuid 24 | } else { 25 | return false 26 | } 27 | } 28 | async function getSdkTicket() { 29 | let config = await readFile("data_gac.json") 30 | let accessToken = config.gacmotor.accessToken 31 | let options = { 32 | url: `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${accessToken}&type=2` 33 | } 34 | let { data: skdTicketresult } = await httpRequest(options) 35 | if (skdTicketresult.errcode == 42001) { 36 | return false 37 | } else if (skdTicketresult.errcode == 0) { 38 | await updateAppId("gacmotor", "sdkTicket", skdTicketresult.ticket) 39 | return skdTicketresult.ticket 40 | } 41 | } 42 | async function getAccessToken() { 43 | let config = await readFile("data_gac.json") 44 | let appid = config.gacmotor.appId 45 | let appsecret = config.gacmotor.appSecert 46 | //accessToken过期 47 | let { data: accessTokenResult } = await httpRequest({ url: `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${appsecret}` }) 48 | let accessToken = accessTokenResult.access_token 49 | await updateAppId("gacmotor", "accessToken", accessToken) 50 | } 51 | 52 | // 读取文件内容 53 | async function readFile(fileName) { 54 | try { 55 | const data = await fs.readFile(fileName, 'utf8'); 56 | return JSON.parse(data); 57 | } catch (err) { 58 | throw err; 59 | } 60 | }; 61 | 62 | // 写入文件内容 63 | async function writeFile(fileName, content) { 64 | try { 65 | await fs.writeFile(fileName, JSON.stringify(content, null, 4), 'utf8'); 66 | } catch (err) { 67 | throw err; 68 | } 69 | }; 70 | 71 | // 异步读取并修改gacmotor中的appId 72 | async function updateAppId(app, name, value) { 73 | try { 74 | const data = await readFile('data_gac.json'); 75 | const appname = data[app]; 76 | // 修改appId 77 | appname[name] = value; 78 | // 写入文件 79 | await writeFile('data_gac.json', data); 80 | //console.log('appId has been updated successfully'); 81 | } catch (err) { 82 | console.error(err); 83 | } 84 | }; -------------------------------------------------------------------------------- /server/apps/apps.js: -------------------------------------------------------------------------------- 1 | const { httpRequest } = require("../utils/httpRequest") 2 | const { checkParams } = require("../utils/checkParams") 3 | module.exports = { 4 | applist, 5 | appinfo 6 | } 7 | async function applist(type) { 8 | if (checkParams(type)) { 9 | if (type == 1) { 10 | return { 11 | status: true, 12 | message: "获取列表成功", 13 | data: [ 14 | { 15 | value: 'BiliBili', 16 | label: '哔哩哔哩', 17 | }, 18 | { 19 | value: 'GeegaPD', 20 | label: '雷达汽车APP账密', 21 | }, 22 | 23 | ] 24 | } 25 | } else if (type == 2) { 26 | return { 27 | status: true, 28 | message: "获取列表成功", 29 | data: [ 30 | { 31 | value: 'Geely', 32 | label: '吉利汽车', 33 | }, 34 | { 35 | value: 'GacmotorApp', 36 | label: '广汽传祺App接口(会顶App但会刷新TOKKEN)', 37 | }, 38 | { 39 | value: 'GacmotorH5', 40 | label: '广汽传祺H5接口(不顶App不会刷新TOKKEN)', 41 | }, 42 | { 43 | value: 'CrazyReader', 44 | label: '疯读小说(时不时收不到码)', 45 | }, 46 | { 47 | value: 'BeiJingEv', 48 | label: '北京汽车APP', 49 | }, 50 | { 51 | value: 'GeegaSMS', 52 | label: '雷达汽车APP短信', 53 | }, 54 | ] 55 | } 56 | } else if (type == 3) { 57 | return { 58 | status: true, 59 | message: "获取列表成功", 60 | data: [{ 61 | value: `GacmotorQr`, 62 | label: `广汽传祺QR接口` 63 | } 64 | ] 65 | } 66 | } 67 | } else { 68 | return { 69 | status: false, 70 | message: "参数错误", 71 | data: null 72 | } 73 | } 74 | } 75 | 76 | async function appinfo(app) { 77 | if (checkParams(app)) { 78 | if (app == "BiliBili") { 79 | let options = { 80 | url: "https://passport.bilibili.com/x/passport-login/captcha?source=main-fe-header&t=0.0775400585207293", 81 | method: "GET", 82 | } 83 | let { data: result } = await httpRequest(options) 84 | if (result.code == 0) { 85 | return { 86 | status: true, message: "获取成功", data: 87 | { type: 1, data: { token: result.data.token }, captcha: { type: "Geetest3Captcha", config: { challenge: result.data.geetest.challenge, gt: result.data.geetest.gt } } } 88 | } 89 | } else { 90 | return { status: false, message: "获取失败", data: null } 91 | 92 | } 93 | } else if (app == "Geely") { 94 | return { 95 | status: true, message: "获取成功", data: { type: 2, data: null, captcha: { type: "TencentCaptcha", config: { appid: "2042700728" } } } 96 | } 97 | } else if (app == "GacmotorApp") { 98 | return { 99 | status: true, message: "获取成功", data: { type: 2, data: null, captcha: null } 100 | } 101 | 102 | } else if (app == "CrazyReader") { 103 | return { 104 | status: true, message: "获取成功", data: { type: 2, data: null, captcha: null } 105 | } 106 | } else if (app == "GacmotorH5") { 107 | return { 108 | status: true, message: "获取成功", data: { type: 2, data: null, captcha: null } 109 | } 110 | } else if (app == "BeiJingEv") { 111 | return { 112 | status: true, message: "获取成功", data: { type: 2, data: null, captcha: { type: "TencentCaptcha", config: { appid: "190206436" } } } 113 | } 114 | } else if (app == "GacmotorQr") { 115 | //const {GetQrCode_Gacmotor} = require("../apps/gacmotor") 116 | //let mainResult = await GetQrCode_Gacmotor() 117 | /*return { 118 | status: true, message: "获取成功", data: { type: `url`, data: `https://open.weixin.qq.com/connect/confirm?uuid=${mainResult}`, value: mainResult, tips: `请使用微信扫码登录` } 119 | }*/ 120 | return { 121 | status: true, message: "获取成功", data: { type: 3, data: null } 122 | } 123 | } else if (app == "GeegaSMS") { 124 | return { 125 | status: true, message: "获取成功", data: { 126 | type: 2, data: null, captcha: { 127 | type: "AliCaptcha", config: { appKey: "FFFF0N0000000000AC64", scene: "nc_other_h5" } 128 | } 129 | } 130 | } 131 | } else if (app == "GeegaPD") { 132 | return { 133 | status: true, message: "获取成功", data: { 134 | type: 1, data: null, captcha: { 135 | type: "AliCaptcha", config: { appKey: "FFFF0N0000000000AC64", scene: "nc_other_h5" } 136 | } 137 | } 138 | } 139 | } 140 | } else { 141 | return { status: false, message: "获取失败", data: null } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /server/apps/beijingev.js: -------------------------------------------------------------------------------- 1 | const { httpRequest } = require("../utils/httpRequest") 2 | const { checkParams } = require("../utils/checkParams") 3 | module.exports = { 4 | SendSMS_BeiJingEv, Login_BeiJingEv 5 | } 6 | async function SendSMS_BeiJingEv(phone, captcha) { 7 | let mobile = phone 8 | let ticket = captcha.ticket 9 | let randstr = captcha.randstr 10 | function get_headers(method, url, body = "") { 11 | url = url.replace("https://beijing-gateway-customer.app-prod.bjev.com.cn", "") 12 | let path = url.split('?')[0] 13 | let params = url.split('?')[1].split('&').sort().join("").toLowerCase() 14 | method = method.toUpperCase(); 15 | let timestamp = new Date().getTime() 16 | const key = `96189e76b405f63f8460367ab2ec74ac` 17 | let str 18 | if (method == "POST") { 19 | str = `${method}${path}ice-auth-appkey:5795393720ice-auth-timestamp:${timestamp}json=${body}${params}${key}` 20 | } else { 21 | str = `${method}${path}ice-auth-appkey:5795393720ice-auth-timestamp:${timestamp}${params}${key}` 22 | } 23 | const { Crypto_SHA256 } = require("../utils/crypto") 24 | const sign = Crypto_SHA256(encodeURIComponent(str)) 25 | return { 26 | "User-Agent": "(Android 10; Xiaomi MI 8 Lite Build/V12.0.1.0.QDTCNXM 3.11.1 135 release bjApp baic-app-android)", 27 | "versionInfo": "(Android 10; Xiaomi MI 8 Lite Build/V12.0.1.0.QDTCNXM 3.11.1 135 release bjApp baic-app-android)", 28 | "Cache-Control": "no-cache", 29 | //"userId": "", 30 | "appKey": 5795393720, 31 | "ice-auth-appkey": 5795393720, 32 | "ice-auth-timestamp": timestamp, 33 | "ice-auth-sign": sign, 34 | "Host": "beijing-gateway-customer.app-prod.bjev.com.cn", 35 | "Connection": "Keep-Alive", 36 | "Accept-Encoding": "gzip" 37 | } 38 | } 39 | const { uuid } = require("../utils/utils") 40 | let uuidd = uuid() 41 | let options = { 42 | url: `https://beijing-gateway-customer.app-prod.bjev.com.cn/beijing-auth-iam-customer/smsCode/sendLoginCode?phone=${mobile}&ticket=${ticket}&rand=${randstr}&uuid_check=${uuidd}`, 43 | method: "GET", 44 | } 45 | options.headers = get_headers(options.method, options.url) 46 | let { data: result } = await httpRequest(options) 47 | //console.log(result); 48 | if (result.code == 0) { 49 | return { status: true, message: "获取验证码成功", data: { type: 2, data: null, captcha: null } } 50 | } else { return { status: false, message: "获取验证码失败", data: null } } 51 | } 52 | 53 | async function Login_BeiJingEv(phone, code) { 54 | 55 | let mobile = phone 56 | function get_headers(method, url, body = "") { 57 | body = body.replaceAll("&", "").toLowerCase()//BODY=无值删除这个键值对 例如下面 58 | body = body.replaceAll("referralcode=", "") 59 | url = url.replace("https://beijing-gateway-customer.app-prod.bjev.com.cn", "") 60 | let path = url.split('?')[0] 61 | let params = url.split('?')[1].split('&').sort().join("").toLowerCase() 62 | method = method.toUpperCase(); 63 | let timestamp = new Date().getTime() 64 | const key = `96189e76b405f63f8460367ab2ec74ac` 65 | let str 66 | if (method == "POST") { 67 | str = `${method}${path}ice-auth-appkey:5795393720ice-auth-timestamp:${timestamp}${body}${params}${key}` 68 | } else { 69 | str = `${method}${path}ice-auth-appkey:5795393720ice-auth-timestamp:${timestamp}${params}${key}` 70 | 71 | } 72 | //console.log(str); 73 | const { Crypto_SHA256 } = require("../utils/crypto") 74 | const sign = Crypto_SHA256(encodeURIComponent(str)) 75 | return { 76 | "Add-Oauth": true, 77 | "User-Agent": "(Android 10; Xiaomi MI 8 Lite Build/V12.0.1.0.QDTCNXM 3.11.1 135 release bjApp baic-app-android)", 78 | "versionInfo": "(Android 10; Xiaomi MI 8 Lite Build/V12.0.1.0.QDTCNXM 3.11.1 135 release bjApp baic-app-android)", 79 | "Cache-Control": "no-cache", 80 | "Authorization": "Basic MjAwMDAxOmFwcEAyMDIy", 81 | "appKey": 5795393720, 82 | "ice-auth-appkey": 5795393720, 83 | "ice-auth-timestamp": timestamp, 84 | "ice-auth-sign": sign, 85 | "Content-Type": "application/x-www-form-urlencoded", 86 | //"Content-Length": 145, 87 | "Host": "beijing-gateway-customer.app-prod.bjev.com.cn", 88 | "Connection": "Keep-Alive", 89 | "Accept-Encoding": "gzip" 90 | } 91 | } 92 | const { uuid } = require("../utils/utils") 93 | let uuidd = uuid() 94 | let options = { 95 | url: `https://beijing-gateway-customer.app-prod.bjev.com.cn/beijing-auth-iam-customer/oauth/token?uuid_check=${uuidd}`, 96 | method: "POST", 97 | data: `buildVersion=135&code=${code}&device_uid=f3baf8eedf65abca6448065ee6e125c1@1700907484087&grant_type=mobile_sms&referralCode=&username=${mobile}` 98 | } 99 | 100 | options.headers = get_headers(options.method, options.url, options.data) 101 | //console.log(options) 102 | let { data: result } = await httpRequest(options) 103 | 104 | //console.log(result); 105 | if (result.code == 0) { 106 | return { status: true, message: "登录成功", data: { "variable": "WoolWeb_BeiJingEv", value: result.data.accessToken } } 107 | } else { return { status: false, message: "登录失败", data: null } } 108 | } -------------------------------------------------------------------------------- /server/apps/bilibili.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Login_BiliBili 3 | } 4 | const { checkParams } = require("../utils/checkParams") 5 | const { httpRequest } = require("../utils/httpRequest") 6 | async function Login_BiliBili(username, password, captcha, data) { 7 | let validate = captcha.validate 8 | let challenge = captcha.challenge 9 | let token = data.token 10 | if (checkParams(username, password, token, validate, challenge)) { 11 | //console.log(`参数校验pass`); 12 | window = {} 13 | const { JSEncrypt } = require("../utils/crypto") 14 | let hash = null 15 | let key = null 16 | let encryptPassword = null 17 | let result = await Get_HashAndKey() 18 | if (result.code == 0) { 19 | hash = result.data.hash 20 | key = result.data.key 21 | if (hash !== null && key !== null) { 22 | encryptPassword = JSEncrypt(key, hash + password) 23 | async function Login(encryptPassword) { 24 | let options = { 25 | url: `https://passport.bilibili.com/x/passport-login/web/login`, 26 | method: "POST", 27 | headers: { 28 | "Host": "passport.bilibili.com", 29 | "Content-Type": "application/x-www-form-urlencoded", 30 | "Cookie": "buvid3=91ADAFA1-6517-8094-1082-842F7121C96789757infoc; b_nut=1697700289; i-wanna-go-back=-1; b_ut=7; _uuid=F5FA5D55-3766-E4AD-1010C5-738EAD7D10DB690370infoc; enable_web_push=DISABLE; buvid4=1B38D8B9-6D36-5A99-204D-8FA54377FFE390263-023101915-gsOoSd6xWjkYGxwGBoe4TQ%3D%3D; buvid_fp=aa2d0d9ab04f9940905ae774ea2f4aa1; CURRENT_FNVAL=4048; header_theme_version=CLOSE; rpdid=|(J|)JJJkuYk0J'uYm~)lkuJR; innersign=0; home_feed_column=4; browser_resolution=442-708; bp_video_offset_85653675=855171475206832181; bili_ticket=eyJhbGciOiJIUzI1NiIsImtpZCI6InMwMyIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTgyMTAyMzIsImlhdCI6MTY5Nzk1MDk3MiwicGx0IjotMX0.ZkoHRimtxhE2kCLWEKI-wouslqGtdg-PhWocdUStbEA; bili_ticket_expires=1698210172; PVID=2; b_lsid=871010FA93_18B56102C4D; sid=7t27x9g3", 31 | "Origin": "https://www.bilibili.com", 32 | "Referer": "https://www.bilibili.com/", 33 | "Sec-Ch-Ua": `"Chromium";v="118", "Microsoft Edge";v="118", "Not=A?Brand";v="99"`, 34 | "Sec-Ch-Ua-Mobile": "?0", 35 | "Sec-Ch-Ua-Platform": `"Windows"`, 36 | "Sec-Fetch-Dest": "empty", 37 | "Sec-Fetch-Mode": "cors", 38 | "Sec-Fetch-Site": "same-site", 39 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.61" 40 | }, 41 | data: `source=main-fe-header&username=${username}&password=${encodeURIComponent(encryptPassword)}&validate=${validate}&token=${token}&seccode=${encodeURIComponent(validate) + `|jordan`}&challenge=${challenge}` 42 | } 43 | //console.log(options); 44 | let { data: result } = await httpRequest(options) 45 | return result 46 | } 47 | let loginResult = await Login(encryptPassword) 48 | if (loginResult.code == 0) { 49 | if (loginResult.data.status == 0) {//2风险 50 | //登录成功 分割url 51 | let url = loginResult.data.url 52 | const dedeUserID = url.match(/DedeUserID=([^&]*)/)[1]; 53 | const dedeUserID__ckMd5 = url.match(/DedeUserID__ckMd5=([^&]*)/)[1]; 54 | const expires = url.match(/Expires=([^&]*)/)[1]; 55 | const sessData = url.match(/SESSDATA=([^&]*)/)[1]; 56 | const bili_jct = url.match(/bili_jct=([^&]*)/)[1]; 57 | return { 58 | status: true, message: "登录成功", data: { "variable": `WoolWeb_BiliBili`, value: `DedeUserID:${dedeUserID};DedeUserID__ckMd5:${dedeUserID__ckMd5};Expires:${expires};SESSDATA:${sessData};bili_jct:${bili_jct}&refresh_token${result.data.refresh_token}` } 59 | } 60 | } else if (loginResult.data.status == 2) { 61 | //自行过验证 62 | return { 63 | status: false, message: "登录风控", data: { url: loginResult.data.url } 64 | } 65 | } else { 66 | console.log(loginResult); 67 | return { 68 | status: false, message: "登录失败", data: null 69 | } 70 | } 71 | } else { 72 | console.log(`登录` + JSON.stringify(loginResult)); 73 | if (result.code == "-629") { 74 | return { 75 | status: false, message: "账号密码错误", data: null 76 | } 77 | } else { 78 | return { 79 | status: false, message: "登录失败", data: result.message 80 | } 81 | } 82 | 83 | } 84 | } else { 85 | return { 86 | status: false, message: "登录失败", data: null 87 | } 88 | } 89 | } else { 90 | console.log("获取KEY" + result); 91 | return { 92 | status: false, message: "登录失败", data: null 93 | } 94 | } 95 | } else { 96 | console.log(username, password, token, validate, challenge) 97 | return { 98 | status: false, message: "登录失败", data: null 99 | } 100 | } 101 | 102 | 103 | 104 | } 105 | async function Get_HashAndKey() { 106 | let options = { 107 | url: `https://passport.bilibili.com/x/passport-login/web/key?_=${new Date().getTime()}`, 108 | method: "GET", 109 | } 110 | let { data: result } = await httpRequest(options) 111 | return result 112 | } 113 | -------------------------------------------------------------------------------- /server/apps/crazyreader.js: -------------------------------------------------------------------------------- 1 | const { checkParams } = require("../utils/checkParams") 2 | const { EncryptAES } = require("../utils/crypto") 3 | const { httpRequest } = require("../utils/httpRequest"); 4 | async function SendSMS_CrazyReader(phone) { 5 | let mobile = phone 6 | //console.log(mobile); 7 | mobile = mobile.toString() 8 | if (checkParams(mobile)) { 9 | const mobileStr = EncryptAES(mobile, 'xoxmx7fqw9m4ejda') 10 | //console.log(mobileStr); 11 | let options = { 12 | url: `https://ws2.fengduxiaoshuo.com/auth/send_verification?_token=366c9c5a-bc78-4ff8-af52-989e1da28925&_ts=1700204697&_v=1&_sign=`, 13 | method: "POST", 14 | headers: { 15 | "Content-Type": "application/json; charset=utf-8" 16 | }, 17 | data: JSON.stringify({ "account_name": mobileStr, "account_type": "com.cootek.auth.phone", "type": "sms", "is_phone_encode": 1 }) 18 | } 19 | try { 20 | let { data: result } = await httpRequest(options) 21 | if (result.result_code == "2000") { 22 | return { status: true, message: "获取验证码成功", data: { type: 2, data: null, captcha: null } } 23 | } else { 24 | return { status: false, message: "获取验证码失败", data: null } 25 | } 26 | } catch (error) { 27 | console.log(`报错`); 28 | console.log(options); 29 | return { status: false, message: "获取验证码失败", data: null } 30 | } 31 | 32 | } else { 33 | return { status: false, message: "获取验证码失败", data: null } 34 | } 35 | } 36 | async function Login_CrazyReader(phone, code) { 37 | let mobile = phone 38 | if (checkParams(mobile, code)) { 39 | const mobileStr = EncryptAES(mobile, 'xoxmx7fqw9m4ejda') 40 | let options = { 41 | url: `https://ws2.fengduxiaoshuo.com/auth/login?_token=366c9c5a-bc78-4ff8-af52-989e1da28925&_ts=1700204697&_v=1&_sign=`, 42 | method: "POST", 43 | headers: { 44 | "Content-Type": "application/json; charset=utf-8" 45 | }, 46 | data: JSON.stringify({ "account_name": mobileStr, "account_group": "com.cootek.crazyreader", "account_type": "com.cootek.auth.phone", "verification": code, "is_phone_encode": 1 }) 47 | } 48 | let result = await httpRequest(options) 49 | if (result.data.result_code == "2000") { 50 | return { 51 | status: true, message: "登录成功", data: { 52 | variable: "WoolWeb_CrazyReader", value: `${result.headers["set-cookie"][0]}` 53 | } 54 | } 55 | } else { 56 | return { status: false, message: "登录失败", data: null } 57 | } 58 | } else { 59 | return { status: false, message: "登录失败", data: null } 60 | } 61 | } 62 | module.exports = { 63 | SendSMS_CrazyReader, Login_CrazyReader 64 | } -------------------------------------------------------------------------------- /server/apps/gacmotor.js: -------------------------------------------------------------------------------- 1 | const { httpRequest } = require("../utils/httpRequest") 2 | const {checkParams} = require("../utils/checkParams") 3 | 4 | const appVersion = "5.1.22" 5 | async function Login_GacmotorApp(phone, code) { 6 | let mobile = phone 7 | if (checkParams(mobile, code)) { 8 | let { Crypto_MD5 } = require("../utils/crypto") 9 | let { randomString } = require("../utils/utils") 10 | let timestamp1 = new Date().getTime(); 11 | let timestamp2 = new Date().getTime(); 12 | let nonce = Math.floor(100000 + Math.random() * 900000); 13 | let appid = `8c4131ff-e326-43ea-b333-decb23936673` 14 | let key = `46856407-b211-4a10-9cb2-5a9b94361614` 15 | let sig = Crypto_MD5(`${timestamp1}${nonce}${appid}${key}`) 16 | let apiSignKey = `a361588rt20dpol` 17 | let apiSign = (Crypto_MD5(`${timestamp2}${apiSignKey}`)).toUpperCase() 18 | let deviceCode = '9e4bb0e5bc326fb1' 19 | let registrationID = '170976fa8b8cd134f94' 20 | let options = { 21 | url: `https://next.gacmotor.com/app/app-api/login/loginBySms`, 22 | method: `POST`, 23 | headers: { 24 | "Accept": "application/json", 25 | "deviceCode": deviceCode, 26 | "current-time": timestamp2, 27 | "deviceId": registrationID, 28 | "version": appVersion, 29 | "nonce": nonce, 30 | "sig": sig, 31 | "platformNo": "Android", 32 | "osVersion": 10, 33 | "operateSystem": "android", 34 | "appId": appid, 35 | "registrationID": registrationID, 36 | "api-sign": apiSign, 37 | "deviceModel": "MI 8 Lite", 38 | "timestamp": timestamp1, 39 | "Content-Type": "application/json; charset=UTF-8", 40 | "Host": "next.gacmotor.com", 41 | "Connection": "Keep-Alive", 42 | "Accept-Encoding": "gzip", 43 | "User-Agent": "okhttp/4.8.1" 44 | }, 45 | data: JSON.stringify({ "mobilePhone": `${mobile}`, "registrationId": registrationID, "smsCode": `${code}`,"blackBox": "rGPHQ1733625985yNQbzUFhLCa" }) 46 | } 47 | //console.log(options); 48 | let { data: result } = await httpRequest(options) 49 | //console.log(result); 50 | if (result.resultCode == "0") { 51 | return { status: true, message: "登录成功", data: { "variable": "WoolWeb_GacmotorApp", "value": `accessToken=${result.data.accessToken}&refreshToken=${result.data.refreshToken}` } } 52 | } else { 53 | return { status: false, message: "登录失败", data: null } 54 | } 55 | } else { 56 | return { status: false, message: "登录失败", data: null } 57 | } 58 | } 59 | async function SendSMS_GacmotorApp(phone) { 60 | let mobile = phone 61 | if (checkParams(mobile)) { 62 | let { Crypto_MD5 } = require("../utils/crypto") 63 | let timestamp1 = new Date().getTime(); 64 | let timestamp2 = new Date().getTime(); 65 | let nonce = Math.floor(100000 + Math.random() * 900000); 66 | let appid = `8c4131ff-e326-43ea-b333-decb23936673` 67 | let key = `46856407-b211-4a10-9cb2-5a9b94361614` 68 | let sig = Crypto_MD5(`${timestamp1}${nonce}${appid}${key}`) 69 | let apiSignKey = `a361588rt20dpol` 70 | let apiSign = (Crypto_MD5(`${timestamp2}${apiSignKey}`)).toUpperCase() 71 | let options = { 72 | url: `https://next.gacmotor.com/app/app-api/sms/sendSmsCodeV2`, 73 | method: `POST`, 74 | headers: { 75 | "Accept": "application/json", 76 | "deviceCode": "9e4bb0e5bc326fb1", 77 | "current-time": timestamp2, 78 | "deviceId": "1a0018970ba16cd9f17", 79 | "version": appVersion, 80 | "nonce": nonce, 81 | "sig": sig, 82 | "platformNo": "Android", 83 | "osVersion": 10, 84 | "operateSystem": "android", 85 | "appId": appid, 86 | "registrationID": "170976fa8b8cd134f94", 87 | "api-sign": apiSign, 88 | "deviceModel": "MI 8 Lite", 89 | "timestamp": timestamp1, 90 | "Content-Type": "application/json; charset=UTF-8", 91 | "Host": "next.gacmotor.com", 92 | "Connection": "Keep-Alive", 93 | "Accept-Encoding": "gzip", 94 | "User-Agent": "okhttp/4.8.1" 95 | }, 96 | data: JSON.stringify({ "mobile": `${mobile}` }) 97 | } 98 | let { data: result } = await httpRequest(options) 99 | //console.log(result); 100 | if (result.resultCode == "0") { 101 | return { status: true, message: "获取验证码成功", data: { type: 2, data: null, captcha: null } } 102 | } else { 103 | return { status: false, message: "获取验证码失败", data: null } 104 | } 105 | } else { 106 | return { status: false, message: "获取验证码失败", data: null } 107 | } 108 | } 109 | 110 | async function SendSMS_GacmotorH5(phone) { 111 | const mobile = phone 112 | if (checkParams(mobile)) { 113 | let options = { 114 | url: `https://mall.gacmotor.com/customer-app/customer/oneid/sendMsg/${mobile}`, 115 | method: "GET", 116 | headers: { 117 | "Host": "mall.gacmotor.com", 118 | "Referer": "https://mall.gacmotor.com/act/answer-activity?id=464", 119 | "Sec-Fetch-Dest": "empty", 120 | "Sec-Fetch-Mode": "cors", 121 | "Sec-Fetch-Site": "same-origin", 122 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0", 123 | "sec-ch-ua": `"Microsoft Edge";v="119", "Chromium";v="119", "Not?A_Brand";v="24"`, 124 | "sec-ch-ua-mobile": "?0", 125 | "sec-ch-ua-platform": `"Windows"`, 126 | "Accept": "application/json, text/plain, */*", 127 | "Accept-Encoding": "gzip, deflate, br", 128 | "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", 129 | "Connection": "keep-alive", 130 | "Content-Type": "application/json;charset=utf-8" 131 | } 132 | } 133 | let { data: result } = await httpRequest(options) 134 | console.log(result); 135 | if (result.code == "0000") { 136 | return { status: true, message: "获取验证码成功", data: { type: 2, data: null, captcha: null } } 137 | } else { 138 | return { status: false, message: "获取验证码失败", data: null } 139 | } 140 | } else { 141 | return { status: false, message: "获取验证码失败", data: null } 142 | } 143 | } 144 | 145 | async function Login_GacmotorH5(phone, code) { 146 | let mobile = phone 147 | if (checkParams(mobile, code)) { 148 | let { Crypto_MD5, JSEncrypt } = require("../utils/crypto") 149 | let publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjGTyMPIG3P+ebXJeZi1fLkqW67JH93gGKZsO5lvv6BVkr/MReBtCDy3VnovY4JUxJJbEj6sfcMoHK0yC3pfDGhuEP3blOQWkwg4IcDSHUhAiZqtQQ34UkZYCTxP1g2fLhR7W/JUf6eA5rNM9l1MJuErS0ijEBtB9IiK6QUlw4lRt+9qe1SuK7oGoai6eyfW7yvPvS9EPIoFxZFzl7GsUFNcPjctMs7Gw4AveS+uM42P2yMGTsSrh9oEUmin+8lOYgxfJYLtHND6Nba/Hzfjxx/yVqcfiCVs9QIoqJXfisy2XDnbiC9vFlM1B45EyhbL8b4DDdnc20VZKnQJD/wM0vwIDAQAB" 150 | const mobilestr = JSEncrypt(publicKey, `${mobile}`) 151 | let md5Data = JSON.stringify({ 'mobile': mobilestr, 'mobileCaptcha': `${code}`, 'channel': 'm_channel', 'source': '' }) 152 | let md5Hash = Crypto_MD5(md5Data + `ds890%$`) 153 | //let deviceCode = generateRandomString(16) 154 | //let registrationID = generateRandomString(19) 155 | let options = { 156 | method: 'POST', 157 | url: 'https://mall.gacmotor.com/customer-app/customer/oneid/sms/login', 158 | headers: { 159 | Accept: 'application/json, text/plain, */*', 160 | 'Accept-Encoding': 'gzip, deflate, br', 161 | 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', 162 | Connection: 'keep-alive', 163 | //'Content-Length': '472', 164 | 'Content-Type': 'application/json;charset=UTF-8', 165 | //Cookie: 'Hm_lvt_998a970b58c68b11573410ac4bb31c9f=1700452109,1700815736; Hm_lvt_6a0d1dcaf9ddec933029987d0f007ecf=1700452109,1700815736; sensorsdata2015jssdkcross=dfm-enc-{"Va28a6y8_aV":"EturiVtAuAnEru-AIEsrStGgAsAGni-SynHRuHt-EIsREAS-EturiVtAuARESVr","gae28_aV":"","OemO2":{"$ki8r28_8eiggay_2mbeyr_8cOr":"直接流量","$ki8r28_2rieyz_lrcMmeV":"未取到值_直接打开","$ki8r28_ergreere":""},"aVr68a8ar2":"rc3liZ7ku67OV5kgPsGCiskkDskl3qmawFzaWZTlpXLawXPJWZ38wXwJwoKApXkowX3MpFWzBF7qQqKIPqKSBF1hwqyJwXN8wFzaWZTlpXLawXyJQ97k36A=","za28mec_kmfa6_aV":{"6ior":"","Cikbr":""},"$VrCayr_aV":"EturiVtAuAnEru-AIEsrStGgAsAGni-SynHRuHt-EIsREAS-EturiVtAuARESVr"}; xn_dvid_kf_20081=34F98D-91E67A48-7665-AF48-F723-00CA77FE63C6; xn_sid_kf_20081=1700820318411256; HWWAFSESID=0c75a79a4c28eaf693; HWWAFSESTIME=1700822527447', 166 | Host: 'mall.gacmotor.com', 167 | Origin: 'https://mall.gacmotor.com', 168 | Referer: 'https://mall.gacmotor.com/act/answer-activity?id=464', 169 | 'Sec-Fetch-Dest': 'empty', 170 | 'Sec-Fetch-Mode': 'cors', 171 | 'Sec-Fetch-Site': 'same-origin', 172 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0', 173 | 'sec-ch-ua': '"Microsoft Edge";v="119", "Chromium";v="119", "Not?A_Brand";v="24"', 174 | 'sec-ch-ua-mobile': '?0', 175 | 'sec-ch-ua-platform': '"Windows"', 176 | 'content-type': 'application/json' 177 | }, 178 | data: { 179 | md5Data: md5Data, 180 | md5Hash: md5Hash 181 | } 182 | } 183 | //console.log(options); 184 | let { data: result } = await httpRequest(options) 185 | //console.log(JSON.stringify(result)); 186 | if (result.code == "0000") { 187 | return { status: true, message: "登录成功", data: { "variable": "WoolWeb_GacmotorH5", "value": `accessToken=${result.data.userInfo.oneIdLoginResVo.token.accessToken}` } } 188 | 189 | } else { 190 | return { status: false, message: "登录失败", data: null } 191 | } 192 | } else { 193 | return { status: false, message: "登录失败", data: null } 194 | } 195 | } 196 | async function GetQrCode_Gacmotor() { 197 | const { getUUID, 198 | getSdkTicket, 199 | getAccessToken } = require("../WXAuth/gacmotor") 200 | async function main() { 201 | let uuid = await getUUID() 202 | console.log(uuid); 203 | if (uuid !== false) { 204 | return uuid 205 | } else { 206 | let sdkTicket = await getSdkTicket() 207 | console.log(sdkTicket) 208 | if (sdkTicket !== false) { 209 | let uuid = await getUUID() 210 | if (uuid !== false) { 211 | return uuid 212 | } 213 | } else { 214 | await getAccessToken() 215 | let sdkTicket = await getSdkTicket() 216 | if (sdkTicket !== false) { 217 | let uuid = await getUUID() 218 | return uuid 219 | } 220 | 221 | } 222 | } 223 | } 224 | let mainResult = await main() 225 | return { 226 | status: true, message: "获取成功", data: { type: `url`, data: `https://open.weixin.qq.com/connect/confirm?uuid=${mainResult}`, value: mainResult, tips: `请使用微信扫码登录` } 227 | } 228 | } 229 | 230 | async function LoginQrCode_Gacmotor(value) { 231 | //console.log(value); 232 | console.log(`https://lp.open.weixin.qq.com/connect/l/qrconnect?f=json&uuid=${value}&_=${Date.now()}`); 233 | let { data: result } = await httpRequest({ url: `https://lp.open.weixin.qq.com/connect/l/qrconnect?f=json&uuid=${value}&_=${Date.now()}` }) 234 | //console.log(result); 235 | if (result.wx_errcode == "405") { 236 | let { Crypto_MD5 } = require("../utils/crypto") 237 | let timestamp1 = new Date().getTime(); 238 | let timestamp2 = new Date().getTime(); 239 | let nonce = Math.floor(100000 + Math.random() * 900000); 240 | let appid = `8c4131ff-e326-43ea-b333-decb23936673` 241 | let key = `46856407-b211-4a10-9cb2-5a9b94361614` 242 | let sig = Crypto_MD5(`${timestamp1}${nonce}${appid}${key}`) 243 | let apiSignKey = `a361588rt20dpol` 244 | let apiSign = (Crypto_MD5(`${timestamp2}${apiSignKey}`)).toUpperCase() 245 | let options = { 246 | url: `https://next.gacmotor.com/app/app-api/login/loginWithThird`, 247 | method: `POST`, 248 | headers: { 249 | "Accept": "application/json", 250 | "deviceCode": "3cf4cc2a5fcf407a", 251 | "current-time": timestamp2, 252 | "deviceId": "1a0018970ba16cd9f17", 253 | "version": "5.1.0", 254 | "nonce": nonce, 255 | "sig": sig, 256 | "platformNo": "Android", 257 | "osVersion": 10, 258 | "operateSystem": "android", 259 | "appId": appid, 260 | "registrationID": "1a0018970ba16cd9f17", 261 | "api-sign": apiSign, 262 | "deviceModel": "MI 8 Lite", 263 | "timestamp": timestamp1, 264 | "Content-Type": "application/json; charset=UTF-8", 265 | "Host": "next.gacmotor.com", 266 | "Connection": "Keep-Alive", 267 | "Accept-Encoding": "gzip", 268 | "User-Agent": "okhttp/4.8.1" 269 | }, 270 | data: JSON.stringify({ "code": `${result.wx_code}`, "registrationID": ``, "thirdPartType": "wechat" }) 271 | } 272 | let { data: loginResult } = await httpRequest(options) 273 | if (loginResult.resultCode == "0") { 274 | return { status: true, message: "登录成功", data: { variable: "WoolWeb_GacmotorQr", value: `access_token=${loginResult.data.accessToken}&refresh_token=${loginResult.data.refreshToken}` } } 275 | } else { 276 | console.log(loginResult); 277 | return { status: false, message: "登录失败", data: null, } 278 | 279 | } 280 | } 281 | 282 | } 283 | module.exports = { 284 | Login_GacmotorApp, SendSMS_GacmotorApp, SendSMS_GacmotorH5, Login_GacmotorH5, 285 | GetQrCode_Gacmotor, LoginQrCode_Gacmotor 286 | } 287 | -------------------------------------------------------------------------------- /server/apps/geega.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 雷达汽车APP 3 | */ 4 | 5 | const { checkParams } = require("../utils/checkParams") 6 | const { EncryptAES } = require("../utils/crypto") 7 | const { httpRequest } = require("../utils/httpRequest"); 8 | module.exports = { 9 | SendSMS_Geega, 10 | Login_Geega, 11 | UserPassLogin_Geega 12 | } 13 | async function SendSMS_Geega(phone, captcha) { 14 | let sig = captcha.sig 15 | let token = captcha.token 16 | let sessionId = captcha.sessionId 17 | let options = { 18 | url: `https://app-api.radar-ev.com/appapi/common/common/sendSmsCode?mobile=${phone}&needCheckSlither=1&sig=${sig}&token=${encodeURIComponent(token)}&sessionId=${sessionId}`, 19 | method: "GET", 20 | /* headers: { 21 | Host: `app-api.radar-ev.com` 22 | }*/ 23 | } 24 | let { data: result } = await httpRequest(options) 25 | //console.log(options); 26 | //console.log(result); 27 | if (result.code == 0) { 28 | return { status: true, message: `获取验证码成功`, data: { type: 2, data: null, captcha: null } } 29 | } else if (result.code == 1) { 30 | return { status: false, message: `获取验证码频繁`, data: null } 31 | } else { 32 | return { status: false, message: `获取验证码频繁`, data: null } 33 | } 34 | 35 | } 36 | async function Login_Geega(phone, code) { 37 | let options = { 38 | url: `https://app-api.radar-ev.com/appapi/auth/oauth/sms`, 39 | method: "POST", 40 | headers: { 41 | "system": "ios", 42 | "Content-Type": `application/json;charset=utf-8` 43 | }, 44 | data: JSON.stringify({ "mobile": phone.toString(), "code": code.toString() }) 45 | } 46 | let { data: result } = await httpRequest(options) 47 | //console.log(options); 48 | //console.log(result); 49 | if (result.code == 0) { 50 | return { status: true, message: `登录成功`, data: { "variable": "WoolWeb_Geega", "value": `rid=${result.data.rId}#aId=${result.data.aId}` } } 51 | } else { 52 | return { status: false, message: `登录失败`, data: null } 53 | } 54 | 55 | } 56 | 57 | 58 | async function UserPassLogin_Geega(phone, password, captcha) { 59 | let sig = captcha.sig 60 | let token = captcha.token 61 | let sessionId = captcha.sessionId 62 | let options = { 63 | url: `https://app-api.radar-ev.com/appapi/auth/oauth/sign/pd`, 64 | method: "POST", 65 | headers: { 66 | "system": "ios", 67 | "Content-Type": `application/json;charset=utf-8` 68 | }, 69 | data: JSON.stringify({ "password": password, "sig": sig, "mobile": phone.toString(), "sessionId": sessionId, "token": token }) 70 | } 71 | let { data: result } = await httpRequest(options) 72 | //console.log(options); 73 | console.log(result); 74 | if (result.code == 0) { 75 | return { status: true, message: `登录成功`, data: { "variable": "WoolWeb_Geega", "value": `rid=${result.data.rId}#aId=${result.data.aId}` } } 76 | } else { 77 | return { status: false, message: `登录失败`, data: null } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /server/apps/geely.js: -------------------------------------------------------------------------------- 1 | 2 | const { httpRequest } = require('../utils/httpRequest') 3 | const { checkParams } = require("../utils/checkParams") 4 | module.exports = { 5 | SendSMS_GeelyApp, 6 | Login_Geely 7 | } 8 | async function SendSMS_GeelyApp(phone, captcha) { 9 | let mobile = phone 10 | let ticket = captcha.ticket 11 | let randstr = captcha.randstr 12 | let options = { 13 | url: "https://app.geely.com/api/v1/message/sendSmsCode", 14 | method: "POST", 15 | headers: { 16 | "Host": "app.geely.com", 17 | "x-refresh-token": true, 18 | "devicesn": 356697505697247, 19 | "txcookie": "", 20 | "token": "", 21 | "appversion": "3.11.1", 22 | "platform": "Android", 23 | "cache-control": "no-cache", 24 | "content-type": "application/json; charset=utf-8", 25 | "accept-encoding": "gzip", 26 | "user-agent": "okhttp/4.9.3" 27 | }, 28 | data: JSON.stringify({ "mobile": mobile, "ticket": ticket, "randStr": randstr, "scene": "login" }) 29 | } 30 | let { data: result } = await httpRequest(options) 31 | //console.log(result); 32 | if (result.code == "success") { 33 | if (result.data.msg == "success") { 34 | return { status: true, message: "获取验证码成功", data: { type: 2, data: { txCookie: result.data.txCookie }, captcha: null } } 35 | } else { 36 | return { status: false, message: "获取验证码失败", data: null } 37 | } 38 | } else { return { status: false, message: "获取验证码失败", data: null } } 39 | } 40 | async function Login_Geely(phone, code, data) { 41 | let mobile = phone 42 | let txCookie = data.txCookie 43 | if (checkParams(mobile, code, txCookie)) { 44 | let options = { 45 | url: "https://app.geely.com/api/v1/userCenter/login/useCode", 46 | method: "POST", 47 | headers: { 48 | "Host": "app.geely.com", 49 | "x-refresh-token": true, 50 | "devicesn": 356697505697247, 51 | "txcookie": txCookie, 52 | "token": "", 53 | "appversion": "3.11.1", 54 | "platform": "Android", 55 | "cache-control": "no-cache", 56 | "content-type": "application/json; charset=utf-8", 57 | "accept-encoding": "gzip", 58 | "user-agent": "okhttp/4.9.3" 59 | }, 60 | data: JSON.stringify( 61 | { "phone": mobile, "identifyCode": code }) 62 | } 63 | let { data: result } = await httpRequest(options) 64 | //console.log(result); 65 | if (result.code == "success") { 66 | return { 67 | status: true, message: "登录成功", data: 68 | { "variable": "WoolWeb_Geely", value: `token=${result.data.token}&txCookie=${result.data.txCookie}&refreshToken=${result.data.refreshToken}` } 69 | } 70 | } else { 71 | return { status: false, message: result.message, data: null } 72 | } 73 | } else { 74 | return { status: false, message: "缺少参数", data: null } 75 | } 76 | } -------------------------------------------------------------------------------- /server/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "web": { 3 | "name": "A", 4 | "notice": "A" 5 | }, 6 | "qinglong": { 7 | "url": "", 8 | "id": "", 9 | "secret": "", 10 | "version": "new" 11 | }, 12 | "admin": { 13 | "username": "", 14 | "password": "" 15 | } 16 | } -------------------------------------------------------------------------------- /server/data_gac.json: -------------------------------------------------------------------------------- 1 | { 2 | "gacmotor": { 3 | "appId": "wx55d651b24ca783fa", 4 | "appSecert": "f7b821627134578c3078d2ed160f31b1", 5 | "accessToken": "75_pX7TVtUOHZOP4T2OYjyaBze9StYYSvE4kIjpzAFDCbuc2Y2LMsaH9Z4OypXU5TfVU4EmhJoa3Xbi4tJj2sX1e95V1v1QCTKkHd5vFB30PnXCO-XF0SiICriiXSIAULfAEAJDU", 6 | "sdkTicket": "ApLNZQ7OekfcASNpXguqxpsFKr7WU5zcGuLItj8V08kAiX-ikkPPgg1i0eFqoHiRLm5SVvgHs2Ht51PCKHeRGw" 7 | } 8 | } -------------------------------------------------------------------------------- /server/dist/.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallfawn/WoolWeb/ecd02cb29b7befde0a1cd49cabfb26ddb37af4d9/server/dist/.md -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const app = express() 3 | const path = require('path'); 4 | app.use(express.json()); 5 | const { getKey, setKey, creatKey } = require("./Funtion/key") 6 | const { getParams, updateParams, deleteParams } = require("./Funtion/webApi") 7 | const { getValue, updateValue } = require("./Funtion/valueApi") 8 | const { checkParams } = require("./Funtion/utils") 9 | const { setToken, checkToken } = require("./Funtion/jwt") 10 | const axios = require('axios'); 11 | /**登录API */ 12 | app.post('/api/user/login', async (req, res) => { 13 | const { username, password } = req.body 14 | if (checkParams(username, password)) { 15 | let admin = await getParams("admin") 16 | if (username == admin.username && password == admin.password) { 17 | let key = await getKey() 18 | let token = setToken({ username: username }, key) 19 | res.send({ 20 | status: true, message: "登录成功", data: { token: token } 21 | }) 22 | } else { 23 | res.send({ status: false, message: "登录失败", data: null }) 24 | } 25 | } else { 26 | res.send({ status: false, message: "登录失败", data: null }) 27 | } 28 | }) 29 | /**注册API */ 30 | app.post('/api/user/register', async (req, res) => { 31 | let key = await getKey(); 32 | if (key == "" || key == null || key == undefined) { 33 | await setKey() 34 | } 35 | const { username, password } = req.body 36 | let admin = await getParams("admin") 37 | if (admin.username == "" && admin.password == "") { 38 | await updateParams('admin', { 39 | username: username, 40 | password: password 41 | }) 42 | res.send({ status: true, message: "注册成功", data: null }) 43 | } else { 44 | res.send({ status: false, message: "已注册", data: null }) 45 | } 46 | }) 47 | /**上传青龙API */ 48 | app.post('/api/user/update', async (req, res) => { 49 | const { variable, value, remark, envSplitor } = req.body; 50 | const { getParams } = require("./Funtion/webApi") 51 | const { getToken, update, setdata } = require("./Funtion/ql") 52 | let ql = await getParams("qinglong") 53 | let token = await getToken(ql) 54 | if (envSplitor !== null) { 55 | //非一对一 56 | if (checkParams(variable, value)) { 57 | let updateResult = await update(ql.url, token, variable, value, envSplitor) 58 | res.send(updateResult) 59 | } 60 | } else if (envSplitor == null) { 61 | if (checkParams(variable, value)) { 62 | //OTO模式 one to one 一对一 63 | let updateResult = await setdata(ql.url, token, variable, value, remark) 64 | if (updateResult.code == 200) { 65 | res.send({ status: true, message: "创建变量成功", data: variable }) 66 | } 67 | } 68 | } 69 | }) 70 | /**获取网站设置API */ 71 | app.post('/api/user/get', async (req, res) => { 72 | const { variable } = req.body; 73 | if (variable == "value") { 74 | res.send({ status: true, message: "获取成功", data: await getValue() }) 75 | } else { 76 | const { token } = req.headers 77 | if (checkParams(token)) { 78 | let key = await getKey() 79 | if (await checkToken(token, key)) { 80 | if (variable == "qinglong") { 81 | res.send({ status: true, message: "获取成功", data: await getParams("qinglong") }) 82 | } else if (variable == "web") { 83 | res.send({ status: true, message: "获取成功", data: await getParams("web") }) 84 | } else { 85 | res.send({ status: false, message: "获取失败", data: null }) 86 | } 87 | } 88 | } else { 89 | res.send({ status: false, message: "获取失败", data: null }) 90 | } 91 | } 92 | 93 | }) 94 | /**设置网站设置API */ 95 | app.post('/api/user/set', async (req, res) => { 96 | const { variable, value } = req.body; 97 | const { token } = req.headers 98 | if (checkParams(token)) { 99 | let key = await getKey() 100 | if (await checkToken(token, key)) { 101 | if (variable == "qinglong") { 102 | updateParams("qinglong", { 103 | url: value.url, 104 | id: value.id, 105 | secret: value.secret, 106 | version: value.version 107 | }) 108 | res.send({ 109 | status: true, message: "设置成功", data: null 110 | }) 111 | } else if (variable == "web") { 112 | updateParams("web", { 113 | name: value.name, 114 | notice: value.notice 115 | }) 116 | res.send({ 117 | status: true, message: "设置成功", data: null 118 | }) 119 | } else { 120 | res.send({ status: false, message: "设置失败", data: null }) 121 | } 122 | } else { 123 | res.send({ status: false, message: "设置失败", data: null }) 124 | } 125 | } else { 126 | res.send({ status: false, message: "设置失败", data: null }) 127 | } 128 | }) 129 | /**测试青龙API */ 130 | app.post('/api/user/test', async (req, res) => { 131 | const { url, id, secret } = req.body; 132 | if (checkParams(url, id, secret)) { 133 | let testUrl = `${url}/open/auth/token?client_id=${id}&client_secret=${secret}` 134 | try { 135 | let { data: result } = await axios.request({ url: testUrl }) 136 | if (result.code === 200) { 137 | res.send({ status: true, message: "青龙连通测试成功", data: null }) 138 | } else { 139 | res.send({ status: false, message: "青龙连通测试失败", data: null }) 140 | } 141 | } catch (error) { 142 | res.send({ status: false, message: "青龙连通测试失败", data: null }) 143 | } 144 | } 145 | }) 146 | /**INIT API */ 147 | app.get('/api/user/init', async (req, res) => { 148 | let result = await getParams("web") 149 | res.send({ status: true, message: "获取成功", data: result }) 150 | }) 151 | 152 | /**变量信息更新API */ 153 | app.post('/api/user/value/update', async (req, res) => { 154 | const { name, variable, test, regular, envSplitor } = req.body 155 | let result = await updateValue({ name: name, variable: variable, test: test, regular: regular, envSplitor: envSplitor }) 156 | if (result == true) { 157 | res.send({ status: true, message: "保存成功", data: { name: name, variable: variable, test: test, regular: regular, envSplitor: envSplitor } }) 158 | } else { 159 | res.send({ status: true, message: "保存失败", data: null }) 160 | } 161 | })// 设置静态资源目录(dist 文件夹) 162 | app.use(express.static(path.join(__dirname, 'dist'))); 163 | 164 | // 处理根路径请求,返回 index.html 165 | app.get('/', function (req, res, next) { 166 | res.sendFile(path.join(__dirname, 'dist/index.html')); 167 | }); 168 | //读取DIST目录的index.html文件 169 | app.get('/', function (req, res, next) { 170 | res.sendFile(path.join(__dirname, 'dist/index.html')); 171 | }); 172 | app.get('/ping', function (req, res, next) { 173 | res.send("pong") 174 | }) 175 | app.get('/api/main/apps', async function (req, res, next) { 176 | const { type, data } = req.query 177 | const { appinfo, applist } = require("./apps/apps") 178 | if (type == "list") { 179 | let result = await applist(data) 180 | res.send(result) 181 | } else if (type == "info") { 182 | let result = await appinfo(data) 183 | res.send(result) 184 | } 185 | }) 186 | app.post('/api/main/login', async function (req, res, next) { 187 | const { app, username, password, phone, code, captcha, data } = req.body 188 | if (app == "BiliBili") { 189 | const { Login_BiliBili } = require("./apps/bilibili") 190 | let result = await Login_BiliBili(username, password, captcha, data) 191 | res.send(result) 192 | } else if (app == "GacmotorApp") { 193 | const { Login_GacmotorApp } = require("./apps/gacmotor") 194 | let result = await Login_GacmotorApp(phone, code) 195 | res.send(result) 196 | } else if (app == "GacmotorH5") { 197 | const { Login_GacmotorH5 } = require("./apps/gacmotor") 198 | let result = await Login_GacmotorH5(phone, code) 199 | res.send(result) 200 | } else if (app == "Geely") { 201 | const { Login_Geely } = require("./apps/geely") 202 | let result = await Login_Geely(phone, code, data) 203 | res.send(result) 204 | } else if (app == "BeiJingEv") { 205 | const { Login_BeiJingEv } = require("./apps/beijingev") 206 | let result = await Login_BeiJingEv(phone, code) 207 | res.send(result) 208 | } else if (app == "CrazyReader") { 209 | const { Login_CrazyReader } = require("./apps/crazyreader") 210 | let result = await Login_CrazyReader(phone, code) 211 | res.send(result) 212 | } else if (app == "GeegaSMS") { 213 | const { Login_Geega } = require("./apps/geega") 214 | let result = await Login_Geega(phone, code) 215 | res.send(result) 216 | } else if (app == "GeegaPD") { 217 | const { UserPassLogin_Geega } = require("./apps/geega") 218 | let result = await UserPassLogin_Geega(username, password, captcha) 219 | res.send(result) 220 | } 221 | }) 222 | app.post('/api/main/sms', async function (req, res, next) { 223 | const { app, phone, captcha, data } = req.body 224 | if (app == "GacmotorApp") { 225 | const { SendSMS_GacmotorApp } = require("./apps/gacmotor") 226 | let result = await SendSMS_GacmotorApp(phone) 227 | res.send(result) 228 | } else if (app == "GacmotorH5") { 229 | const { SendSMS_GacmotorH5 } = require("./apps/gacmotor") 230 | let result = await SendSMS_GacmotorH5(phone) 231 | res.send(result) 232 | } else if (app == "Geely") { 233 | const { SendSMS_GeelyApp } = require("./apps/geely") 234 | let result = await SendSMS_GeelyApp(phone, captcha) 235 | res.send(result) 236 | } else if (app == "BeiJingEv") { 237 | const { SendSMS_BeiJingEv } = require("./apps/beijingev") 238 | let result = await SendSMS_BeiJingEv(phone, captcha) 239 | res.send(result) 240 | } else if (app == "CrazyReader") { 241 | const { SendSMS_CrazyReader } = require("./apps/crazyreader") 242 | let result = await SendSMS_CrazyReader(phone) 243 | res.send(result) 244 | } else if (app == "Geega") { 245 | const { SendSMS_Geega } = require("./apps/geega") 246 | let result = await SendSMS_Geega(phone, captcha) 247 | res.send(result) 248 | } 249 | 250 | }) 251 | app.get('/api/main/qrcode/get', async function (req, res, next) { 252 | const { app } = req.query 253 | if (app == "GacmotorQr") { 254 | const { GetQrCode_Gacmotor } = require("./apps/gacmotor") 255 | let result = await GetQrCode_Gacmotor() 256 | res.send(result) 257 | } 258 | 259 | }) 260 | app.post('/api/main/qrcode/login', async function (req, res, next) { 261 | const { app, value } = req.body 262 | if (app == "GacmotorQr") { 263 | const { LoginQrCode_Gacmotor } = require("./apps/gacmotor") 264 | let result = await LoginQrCode_Gacmotor(value) 265 | res.send(result) 266 | } 267 | 268 | }) 269 | 270 | app.listen(1433, () => { 271 | console.log('Server is running on port 1433'); 272 | }); -------------------------------------------------------------------------------- /server/jwt.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallfawn/WoolWeb/ecd02cb29b7befde0a1cd49cabfb26ddb37af4d9/server/jwt.key -------------------------------------------------------------------------------- /server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "private", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "private", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^1.6.3", 13 | "express": "^4.18.2", 14 | "jsonwebtoken": "^9.0.2" 15 | } 16 | }, 17 | "node_modules/accepts": { 18 | "version": "1.3.8", 19 | "resolved": "https://mirrors.cloud.tencent.com/npm/accepts/-/accepts-1.3.8.tgz", 20 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 21 | "dependencies": { 22 | "mime-types": "~2.1.34", 23 | "negotiator": "0.6.3" 24 | }, 25 | "engines": { 26 | "node": ">= 0.6" 27 | } 28 | }, 29 | "node_modules/array-flatten": { 30 | "version": "1.1.1", 31 | "resolved": "https://mirrors.cloud.tencent.com/npm/array-flatten/-/array-flatten-1.1.1.tgz", 32 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 33 | }, 34 | "node_modules/asynckit": { 35 | "version": "0.4.0", 36 | "resolved": "https://mirrors.cloud.tencent.com/npm/asynckit/-/asynckit-0.4.0.tgz", 37 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 38 | }, 39 | "node_modules/axios": { 40 | "version": "1.6.3", 41 | "resolved": "https://mirrors.cloud.tencent.com/npm/axios/-/axios-1.6.3.tgz", 42 | "integrity": "sha512-fWyNdeawGam70jXSVlKl+SUNVcL6j6W79CuSIPfi6HnDUmSCH6gyUys/HrqHeA/wU0Az41rRgean494d0Jb+ww==", 43 | "dependencies": { 44 | "follow-redirects": "^1.15.0", 45 | "form-data": "^4.0.0", 46 | "proxy-from-env": "^1.1.0" 47 | } 48 | }, 49 | "node_modules/body-parser": { 50 | "version": "1.20.1", 51 | "resolved": "https://mirrors.cloud.tencent.com/npm/body-parser/-/body-parser-1.20.1.tgz", 52 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 53 | "dependencies": { 54 | "bytes": "3.1.2", 55 | "content-type": "~1.0.4", 56 | "debug": "2.6.9", 57 | "depd": "2.0.0", 58 | "destroy": "1.2.0", 59 | "http-errors": "2.0.0", 60 | "iconv-lite": "0.4.24", 61 | "on-finished": "2.4.1", 62 | "qs": "6.11.0", 63 | "raw-body": "2.5.1", 64 | "type-is": "~1.6.18", 65 | "unpipe": "1.0.0" 66 | }, 67 | "engines": { 68 | "node": ">= 0.8", 69 | "npm": "1.2.8000 || >= 1.4.16" 70 | } 71 | }, 72 | "node_modules/buffer-equal-constant-time": { 73 | "version": "1.0.1", 74 | "resolved": "https://mirrors.cloud.tencent.com/npm/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 75 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 76 | }, 77 | "node_modules/bytes": { 78 | "version": "3.1.2", 79 | "resolved": "https://mirrors.cloud.tencent.com/npm/bytes/-/bytes-3.1.2.tgz", 80 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 81 | "engines": { 82 | "node": ">= 0.8" 83 | } 84 | }, 85 | "node_modules/call-bind": { 86 | "version": "1.0.5", 87 | "resolved": "https://mirrors.cloud.tencent.com/npm/call-bind/-/call-bind-1.0.5.tgz", 88 | "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", 89 | "dependencies": { 90 | "function-bind": "^1.1.2", 91 | "get-intrinsic": "^1.2.1", 92 | "set-function-length": "^1.1.1" 93 | }, 94 | "funding": { 95 | "url": "https://github.com/sponsors/ljharb" 96 | } 97 | }, 98 | "node_modules/combined-stream": { 99 | "version": "1.0.8", 100 | "resolved": "https://mirrors.cloud.tencent.com/npm/combined-stream/-/combined-stream-1.0.8.tgz", 101 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 102 | "dependencies": { 103 | "delayed-stream": "~1.0.0" 104 | }, 105 | "engines": { 106 | "node": ">= 0.8" 107 | } 108 | }, 109 | "node_modules/content-disposition": { 110 | "version": "0.5.4", 111 | "resolved": "https://mirrors.cloud.tencent.com/npm/content-disposition/-/content-disposition-0.5.4.tgz", 112 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 113 | "dependencies": { 114 | "safe-buffer": "5.2.1" 115 | }, 116 | "engines": { 117 | "node": ">= 0.6" 118 | } 119 | }, 120 | "node_modules/content-type": { 121 | "version": "1.0.5", 122 | "resolved": "https://mirrors.cloud.tencent.com/npm/content-type/-/content-type-1.0.5.tgz", 123 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 124 | "engines": { 125 | "node": ">= 0.6" 126 | } 127 | }, 128 | "node_modules/cookie": { 129 | "version": "0.5.0", 130 | "resolved": "https://mirrors.cloud.tencent.com/npm/cookie/-/cookie-0.5.0.tgz", 131 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 132 | "engines": { 133 | "node": ">= 0.6" 134 | } 135 | }, 136 | "node_modules/cookie-signature": { 137 | "version": "1.0.6", 138 | "resolved": "https://mirrors.cloud.tencent.com/npm/cookie-signature/-/cookie-signature-1.0.6.tgz", 139 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 140 | }, 141 | "node_modules/debug": { 142 | "version": "2.6.9", 143 | "resolved": "https://mirrors.cloud.tencent.com/npm/debug/-/debug-2.6.9.tgz", 144 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 145 | "dependencies": { 146 | "ms": "2.0.0" 147 | } 148 | }, 149 | "node_modules/define-data-property": { 150 | "version": "1.1.1", 151 | "resolved": "https://mirrors.cloud.tencent.com/npm/define-data-property/-/define-data-property-1.1.1.tgz", 152 | "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", 153 | "dependencies": { 154 | "get-intrinsic": "^1.2.1", 155 | "gopd": "^1.0.1", 156 | "has-property-descriptors": "^1.0.0" 157 | }, 158 | "engines": { 159 | "node": ">= 0.4" 160 | } 161 | }, 162 | "node_modules/delayed-stream": { 163 | "version": "1.0.0", 164 | "resolved": "https://mirrors.cloud.tencent.com/npm/delayed-stream/-/delayed-stream-1.0.0.tgz", 165 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 166 | "engines": { 167 | "node": ">=0.4.0" 168 | } 169 | }, 170 | "node_modules/depd": { 171 | "version": "2.0.0", 172 | "resolved": "https://mirrors.cloud.tencent.com/npm/depd/-/depd-2.0.0.tgz", 173 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 174 | "engines": { 175 | "node": ">= 0.8" 176 | } 177 | }, 178 | "node_modules/destroy": { 179 | "version": "1.2.0", 180 | "resolved": "https://mirrors.cloud.tencent.com/npm/destroy/-/destroy-1.2.0.tgz", 181 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 182 | "engines": { 183 | "node": ">= 0.8", 184 | "npm": "1.2.8000 || >= 1.4.16" 185 | } 186 | }, 187 | "node_modules/ecdsa-sig-formatter": { 188 | "version": "1.0.11", 189 | "resolved": "https://mirrors.cloud.tencent.com/npm/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 190 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 191 | "dependencies": { 192 | "safe-buffer": "^5.0.1" 193 | } 194 | }, 195 | "node_modules/ee-first": { 196 | "version": "1.1.1", 197 | "resolved": "https://mirrors.cloud.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", 198 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 199 | }, 200 | "node_modules/encodeurl": { 201 | "version": "1.0.2", 202 | "resolved": "https://mirrors.cloud.tencent.com/npm/encodeurl/-/encodeurl-1.0.2.tgz", 203 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", 204 | "engines": { 205 | "node": ">= 0.8" 206 | } 207 | }, 208 | "node_modules/escape-html": { 209 | "version": "1.0.3", 210 | "resolved": "https://mirrors.cloud.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", 211 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 212 | }, 213 | "node_modules/etag": { 214 | "version": "1.8.1", 215 | "resolved": "https://mirrors.cloud.tencent.com/npm/etag/-/etag-1.8.1.tgz", 216 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", 217 | "engines": { 218 | "node": ">= 0.6" 219 | } 220 | }, 221 | "node_modules/express": { 222 | "version": "4.18.2", 223 | "resolved": "https://mirrors.cloud.tencent.com/npm/express/-/express-4.18.2.tgz", 224 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 225 | "dependencies": { 226 | "accepts": "~1.3.8", 227 | "array-flatten": "1.1.1", 228 | "body-parser": "1.20.1", 229 | "content-disposition": "0.5.4", 230 | "content-type": "~1.0.4", 231 | "cookie": "0.5.0", 232 | "cookie-signature": "1.0.6", 233 | "debug": "2.6.9", 234 | "depd": "2.0.0", 235 | "encodeurl": "~1.0.2", 236 | "escape-html": "~1.0.3", 237 | "etag": "~1.8.1", 238 | "finalhandler": "1.2.0", 239 | "fresh": "0.5.2", 240 | "http-errors": "2.0.0", 241 | "merge-descriptors": "1.0.1", 242 | "methods": "~1.1.2", 243 | "on-finished": "2.4.1", 244 | "parseurl": "~1.3.3", 245 | "path-to-regexp": "0.1.7", 246 | "proxy-addr": "~2.0.7", 247 | "qs": "6.11.0", 248 | "range-parser": "~1.2.1", 249 | "safe-buffer": "5.2.1", 250 | "send": "0.18.0", 251 | "serve-static": "1.15.0", 252 | "setprototypeof": "1.2.0", 253 | "statuses": "2.0.1", 254 | "type-is": "~1.6.18", 255 | "utils-merge": "1.0.1", 256 | "vary": "~1.1.2" 257 | }, 258 | "engines": { 259 | "node": ">= 0.10.0" 260 | } 261 | }, 262 | "node_modules/finalhandler": { 263 | "version": "1.2.0", 264 | "resolved": "https://mirrors.cloud.tencent.com/npm/finalhandler/-/finalhandler-1.2.0.tgz", 265 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 266 | "dependencies": { 267 | "debug": "2.6.9", 268 | "encodeurl": "~1.0.2", 269 | "escape-html": "~1.0.3", 270 | "on-finished": "2.4.1", 271 | "parseurl": "~1.3.3", 272 | "statuses": "2.0.1", 273 | "unpipe": "~1.0.0" 274 | }, 275 | "engines": { 276 | "node": ">= 0.8" 277 | } 278 | }, 279 | "node_modules/follow-redirects": { 280 | "version": "1.15.3", 281 | "resolved": "https://mirrors.cloud.tencent.com/npm/follow-redirects/-/follow-redirects-1.15.3.tgz", 282 | "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", 283 | "funding": [ 284 | { 285 | "type": "individual", 286 | "url": "https://github.com/sponsors/RubenVerborgh" 287 | } 288 | ], 289 | "engines": { 290 | "node": ">=4.0" 291 | }, 292 | "peerDependenciesMeta": { 293 | "debug": { 294 | "optional": true 295 | } 296 | } 297 | }, 298 | "node_modules/form-data": { 299 | "version": "4.0.0", 300 | "resolved": "https://mirrors.cloud.tencent.com/npm/form-data/-/form-data-4.0.0.tgz", 301 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 302 | "dependencies": { 303 | "asynckit": "^0.4.0", 304 | "combined-stream": "^1.0.8", 305 | "mime-types": "^2.1.12" 306 | }, 307 | "engines": { 308 | "node": ">= 6" 309 | } 310 | }, 311 | "node_modules/forwarded": { 312 | "version": "0.2.0", 313 | "resolved": "https://mirrors.cloud.tencent.com/npm/forwarded/-/forwarded-0.2.0.tgz", 314 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 315 | "engines": { 316 | "node": ">= 0.6" 317 | } 318 | }, 319 | "node_modules/fresh": { 320 | "version": "0.5.2", 321 | "resolved": "https://mirrors.cloud.tencent.com/npm/fresh/-/fresh-0.5.2.tgz", 322 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", 323 | "engines": { 324 | "node": ">= 0.6" 325 | } 326 | }, 327 | "node_modules/function-bind": { 328 | "version": "1.1.2", 329 | "resolved": "https://mirrors.cloud.tencent.com/npm/function-bind/-/function-bind-1.1.2.tgz", 330 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 331 | "funding": { 332 | "url": "https://github.com/sponsors/ljharb" 333 | } 334 | }, 335 | "node_modules/get-intrinsic": { 336 | "version": "1.2.2", 337 | "resolved": "https://mirrors.cloud.tencent.com/npm/get-intrinsic/-/get-intrinsic-1.2.2.tgz", 338 | "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", 339 | "dependencies": { 340 | "function-bind": "^1.1.2", 341 | "has-proto": "^1.0.1", 342 | "has-symbols": "^1.0.3", 343 | "hasown": "^2.0.0" 344 | }, 345 | "funding": { 346 | "url": "https://github.com/sponsors/ljharb" 347 | } 348 | }, 349 | "node_modules/gopd": { 350 | "version": "1.0.1", 351 | "resolved": "https://mirrors.cloud.tencent.com/npm/gopd/-/gopd-1.0.1.tgz", 352 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 353 | "dependencies": { 354 | "get-intrinsic": "^1.1.3" 355 | }, 356 | "funding": { 357 | "url": "https://github.com/sponsors/ljharb" 358 | } 359 | }, 360 | "node_modules/has-property-descriptors": { 361 | "version": "1.0.1", 362 | "resolved": "https://mirrors.cloud.tencent.com/npm/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", 363 | "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", 364 | "dependencies": { 365 | "get-intrinsic": "^1.2.2" 366 | }, 367 | "funding": { 368 | "url": "https://github.com/sponsors/ljharb" 369 | } 370 | }, 371 | "node_modules/has-proto": { 372 | "version": "1.0.1", 373 | "resolved": "https://mirrors.cloud.tencent.com/npm/has-proto/-/has-proto-1.0.1.tgz", 374 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", 375 | "engines": { 376 | "node": ">= 0.4" 377 | }, 378 | "funding": { 379 | "url": "https://github.com/sponsors/ljharb" 380 | } 381 | }, 382 | "node_modules/has-symbols": { 383 | "version": "1.0.3", 384 | "resolved": "https://mirrors.cloud.tencent.com/npm/has-symbols/-/has-symbols-1.0.3.tgz", 385 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 386 | "engines": { 387 | "node": ">= 0.4" 388 | }, 389 | "funding": { 390 | "url": "https://github.com/sponsors/ljharb" 391 | } 392 | }, 393 | "node_modules/hasown": { 394 | "version": "2.0.0", 395 | "resolved": "https://mirrors.cloud.tencent.com/npm/hasown/-/hasown-2.0.0.tgz", 396 | "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", 397 | "dependencies": { 398 | "function-bind": "^1.1.2" 399 | }, 400 | "engines": { 401 | "node": ">= 0.4" 402 | } 403 | }, 404 | "node_modules/http-errors": { 405 | "version": "2.0.0", 406 | "resolved": "https://mirrors.cloud.tencent.com/npm/http-errors/-/http-errors-2.0.0.tgz", 407 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 408 | "dependencies": { 409 | "depd": "2.0.0", 410 | "inherits": "2.0.4", 411 | "setprototypeof": "1.2.0", 412 | "statuses": "2.0.1", 413 | "toidentifier": "1.0.1" 414 | }, 415 | "engines": { 416 | "node": ">= 0.8" 417 | } 418 | }, 419 | "node_modules/iconv-lite": { 420 | "version": "0.4.24", 421 | "resolved": "https://mirrors.cloud.tencent.com/npm/iconv-lite/-/iconv-lite-0.4.24.tgz", 422 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 423 | "dependencies": { 424 | "safer-buffer": ">= 2.1.2 < 3" 425 | }, 426 | "engines": { 427 | "node": ">=0.10.0" 428 | } 429 | }, 430 | "node_modules/inherits": { 431 | "version": "2.0.4", 432 | "resolved": "https://mirrors.cloud.tencent.com/npm/inherits/-/inherits-2.0.4.tgz", 433 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 434 | }, 435 | "node_modules/ipaddr.js": { 436 | "version": "1.9.1", 437 | "resolved": "https://mirrors.cloud.tencent.com/npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 438 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 439 | "engines": { 440 | "node": ">= 0.10" 441 | } 442 | }, 443 | "node_modules/jsonwebtoken": { 444 | "version": "9.0.2", 445 | "resolved": "https://mirrors.cloud.tencent.com/npm/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", 446 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", 447 | "dependencies": { 448 | "jws": "^3.2.2", 449 | "lodash.includes": "^4.3.0", 450 | "lodash.isboolean": "^3.0.3", 451 | "lodash.isinteger": "^4.0.4", 452 | "lodash.isnumber": "^3.0.3", 453 | "lodash.isplainobject": "^4.0.6", 454 | "lodash.isstring": "^4.0.1", 455 | "lodash.once": "^4.0.0", 456 | "ms": "^2.1.1", 457 | "semver": "^7.5.4" 458 | }, 459 | "engines": { 460 | "node": ">=12", 461 | "npm": ">=6" 462 | } 463 | }, 464 | "node_modules/jsonwebtoken/node_modules/ms": { 465 | "version": "2.1.3", 466 | "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.3.tgz", 467 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 468 | }, 469 | "node_modules/jwa": { 470 | "version": "1.4.1", 471 | "resolved": "https://mirrors.cloud.tencent.com/npm/jwa/-/jwa-1.4.1.tgz", 472 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 473 | "dependencies": { 474 | "buffer-equal-constant-time": "1.0.1", 475 | "ecdsa-sig-formatter": "1.0.11", 476 | "safe-buffer": "^5.0.1" 477 | } 478 | }, 479 | "node_modules/jws": { 480 | "version": "3.2.2", 481 | "resolved": "https://mirrors.cloud.tencent.com/npm/jws/-/jws-3.2.2.tgz", 482 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 483 | "dependencies": { 484 | "jwa": "^1.4.1", 485 | "safe-buffer": "^5.0.1" 486 | } 487 | }, 488 | "node_modules/lodash.includes": { 489 | "version": "4.3.0", 490 | "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.includes/-/lodash.includes-4.3.0.tgz", 491 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 492 | }, 493 | "node_modules/lodash.isboolean": { 494 | "version": "3.0.3", 495 | "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 496 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 497 | }, 498 | "node_modules/lodash.isinteger": { 499 | "version": "4.0.4", 500 | "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 501 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 502 | }, 503 | "node_modules/lodash.isnumber": { 504 | "version": "3.0.3", 505 | "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 506 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 507 | }, 508 | "node_modules/lodash.isplainobject": { 509 | "version": "4.0.6", 510 | "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 511 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 512 | }, 513 | "node_modules/lodash.isstring": { 514 | "version": "4.0.1", 515 | "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 516 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 517 | }, 518 | "node_modules/lodash.once": { 519 | "version": "4.1.1", 520 | "resolved": "https://mirrors.cloud.tencent.com/npm/lodash.once/-/lodash.once-4.1.1.tgz", 521 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 522 | }, 523 | "node_modules/lru-cache": { 524 | "version": "6.0.0", 525 | "resolved": "https://mirrors.cloud.tencent.com/npm/lru-cache/-/lru-cache-6.0.0.tgz", 526 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 527 | "dependencies": { 528 | "yallist": "^4.0.0" 529 | }, 530 | "engines": { 531 | "node": ">=10" 532 | } 533 | }, 534 | "node_modules/media-typer": { 535 | "version": "0.3.0", 536 | "resolved": "https://mirrors.cloud.tencent.com/npm/media-typer/-/media-typer-0.3.0.tgz", 537 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", 538 | "engines": { 539 | "node": ">= 0.6" 540 | } 541 | }, 542 | "node_modules/merge-descriptors": { 543 | "version": "1.0.1", 544 | "resolved": "https://mirrors.cloud.tencent.com/npm/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 545 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 546 | }, 547 | "node_modules/methods": { 548 | "version": "1.1.2", 549 | "resolved": "https://mirrors.cloud.tencent.com/npm/methods/-/methods-1.1.2.tgz", 550 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 551 | "engines": { 552 | "node": ">= 0.6" 553 | } 554 | }, 555 | "node_modules/mime": { 556 | "version": "1.6.0", 557 | "resolved": "https://mirrors.cloud.tencent.com/npm/mime/-/mime-1.6.0.tgz", 558 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 559 | "bin": { 560 | "mime": "cli.js" 561 | }, 562 | "engines": { 563 | "node": ">=4" 564 | } 565 | }, 566 | "node_modules/mime-db": { 567 | "version": "1.52.0", 568 | "resolved": "https://mirrors.cloud.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz", 569 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 570 | "engines": { 571 | "node": ">= 0.6" 572 | } 573 | }, 574 | "node_modules/mime-types": { 575 | "version": "2.1.35", 576 | "resolved": "https://mirrors.cloud.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz", 577 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 578 | "dependencies": { 579 | "mime-db": "1.52.0" 580 | }, 581 | "engines": { 582 | "node": ">= 0.6" 583 | } 584 | }, 585 | "node_modules/ms": { 586 | "version": "2.0.0", 587 | "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", 588 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 589 | }, 590 | "node_modules/negotiator": { 591 | "version": "0.6.3", 592 | "resolved": "https://mirrors.cloud.tencent.com/npm/negotiator/-/negotiator-0.6.3.tgz", 593 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 594 | "engines": { 595 | "node": ">= 0.6" 596 | } 597 | }, 598 | "node_modules/object-inspect": { 599 | "version": "1.13.1", 600 | "resolved": "https://mirrors.cloud.tencent.com/npm/object-inspect/-/object-inspect-1.13.1.tgz", 601 | "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", 602 | "funding": { 603 | "url": "https://github.com/sponsors/ljharb" 604 | } 605 | }, 606 | "node_modules/on-finished": { 607 | "version": "2.4.1", 608 | "resolved": "https://mirrors.cloud.tencent.com/npm/on-finished/-/on-finished-2.4.1.tgz", 609 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 610 | "dependencies": { 611 | "ee-first": "1.1.1" 612 | }, 613 | "engines": { 614 | "node": ">= 0.8" 615 | } 616 | }, 617 | "node_modules/parseurl": { 618 | "version": "1.3.3", 619 | "resolved": "https://mirrors.cloud.tencent.com/npm/parseurl/-/parseurl-1.3.3.tgz", 620 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 621 | "engines": { 622 | "node": ">= 0.8" 623 | } 624 | }, 625 | "node_modules/path-to-regexp": { 626 | "version": "0.1.7", 627 | "resolved": "https://mirrors.cloud.tencent.com/npm/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 628 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 629 | }, 630 | "node_modules/proxy-addr": { 631 | "version": "2.0.7", 632 | "resolved": "https://mirrors.cloud.tencent.com/npm/proxy-addr/-/proxy-addr-2.0.7.tgz", 633 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 634 | "dependencies": { 635 | "forwarded": "0.2.0", 636 | "ipaddr.js": "1.9.1" 637 | }, 638 | "engines": { 639 | "node": ">= 0.10" 640 | } 641 | }, 642 | "node_modules/proxy-from-env": { 643 | "version": "1.1.0", 644 | "resolved": "https://mirrors.cloud.tencent.com/npm/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 645 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 646 | }, 647 | "node_modules/qs": { 648 | "version": "6.11.0", 649 | "resolved": "https://mirrors.cloud.tencent.com/npm/qs/-/qs-6.11.0.tgz", 650 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 651 | "dependencies": { 652 | "side-channel": "^1.0.4" 653 | }, 654 | "engines": { 655 | "node": ">=0.6" 656 | }, 657 | "funding": { 658 | "url": "https://github.com/sponsors/ljharb" 659 | } 660 | }, 661 | "node_modules/range-parser": { 662 | "version": "1.2.1", 663 | "resolved": "https://mirrors.cloud.tencent.com/npm/range-parser/-/range-parser-1.2.1.tgz", 664 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 665 | "engines": { 666 | "node": ">= 0.6" 667 | } 668 | }, 669 | "node_modules/raw-body": { 670 | "version": "2.5.1", 671 | "resolved": "https://mirrors.cloud.tencent.com/npm/raw-body/-/raw-body-2.5.1.tgz", 672 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 673 | "dependencies": { 674 | "bytes": "3.1.2", 675 | "http-errors": "2.0.0", 676 | "iconv-lite": "0.4.24", 677 | "unpipe": "1.0.0" 678 | }, 679 | "engines": { 680 | "node": ">= 0.8" 681 | } 682 | }, 683 | "node_modules/safe-buffer": { 684 | "version": "5.2.1", 685 | "resolved": "https://mirrors.cloud.tencent.com/npm/safe-buffer/-/safe-buffer-5.2.1.tgz", 686 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 687 | "funding": [ 688 | { 689 | "type": "github", 690 | "url": "https://github.com/sponsors/feross" 691 | }, 692 | { 693 | "type": "patreon", 694 | "url": "https://www.patreon.com/feross" 695 | }, 696 | { 697 | "type": "consulting", 698 | "url": "https://feross.org/support" 699 | } 700 | ] 701 | }, 702 | "node_modules/safer-buffer": { 703 | "version": "2.1.2", 704 | "resolved": "https://mirrors.cloud.tencent.com/npm/safer-buffer/-/safer-buffer-2.1.2.tgz", 705 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 706 | }, 707 | "node_modules/semver": { 708 | "version": "7.5.4", 709 | "resolved": "https://mirrors.cloud.tencent.com/npm/semver/-/semver-7.5.4.tgz", 710 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 711 | "dependencies": { 712 | "lru-cache": "^6.0.0" 713 | }, 714 | "bin": { 715 | "semver": "bin/semver.js" 716 | }, 717 | "engines": { 718 | "node": ">=10" 719 | } 720 | }, 721 | "node_modules/send": { 722 | "version": "0.18.0", 723 | "resolved": "https://mirrors.cloud.tencent.com/npm/send/-/send-0.18.0.tgz", 724 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 725 | "dependencies": { 726 | "debug": "2.6.9", 727 | "depd": "2.0.0", 728 | "destroy": "1.2.0", 729 | "encodeurl": "~1.0.2", 730 | "escape-html": "~1.0.3", 731 | "etag": "~1.8.1", 732 | "fresh": "0.5.2", 733 | "http-errors": "2.0.0", 734 | "mime": "1.6.0", 735 | "ms": "2.1.3", 736 | "on-finished": "2.4.1", 737 | "range-parser": "~1.2.1", 738 | "statuses": "2.0.1" 739 | }, 740 | "engines": { 741 | "node": ">= 0.8.0" 742 | } 743 | }, 744 | "node_modules/send/node_modules/ms": { 745 | "version": "2.1.3", 746 | "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.3.tgz", 747 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 748 | }, 749 | "node_modules/serve-static": { 750 | "version": "1.15.0", 751 | "resolved": "https://mirrors.cloud.tencent.com/npm/serve-static/-/serve-static-1.15.0.tgz", 752 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 753 | "dependencies": { 754 | "encodeurl": "~1.0.2", 755 | "escape-html": "~1.0.3", 756 | "parseurl": "~1.3.3", 757 | "send": "0.18.0" 758 | }, 759 | "engines": { 760 | "node": ">= 0.8.0" 761 | } 762 | }, 763 | "node_modules/set-function-length": { 764 | "version": "1.1.1", 765 | "resolved": "https://mirrors.cloud.tencent.com/npm/set-function-length/-/set-function-length-1.1.1.tgz", 766 | "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", 767 | "dependencies": { 768 | "define-data-property": "^1.1.1", 769 | "get-intrinsic": "^1.2.1", 770 | "gopd": "^1.0.1", 771 | "has-property-descriptors": "^1.0.0" 772 | }, 773 | "engines": { 774 | "node": ">= 0.4" 775 | } 776 | }, 777 | "node_modules/setprototypeof": { 778 | "version": "1.2.0", 779 | "resolved": "https://mirrors.cloud.tencent.com/npm/setprototypeof/-/setprototypeof-1.2.0.tgz", 780 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 781 | }, 782 | "node_modules/side-channel": { 783 | "version": "1.0.4", 784 | "resolved": "https://mirrors.cloud.tencent.com/npm/side-channel/-/side-channel-1.0.4.tgz", 785 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 786 | "dependencies": { 787 | "call-bind": "^1.0.0", 788 | "get-intrinsic": "^1.0.2", 789 | "object-inspect": "^1.9.0" 790 | }, 791 | "funding": { 792 | "url": "https://github.com/sponsors/ljharb" 793 | } 794 | }, 795 | "node_modules/statuses": { 796 | "version": "2.0.1", 797 | "resolved": "https://mirrors.cloud.tencent.com/npm/statuses/-/statuses-2.0.1.tgz", 798 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 799 | "engines": { 800 | "node": ">= 0.8" 801 | } 802 | }, 803 | "node_modules/toidentifier": { 804 | "version": "1.0.1", 805 | "resolved": "https://mirrors.cloud.tencent.com/npm/toidentifier/-/toidentifier-1.0.1.tgz", 806 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 807 | "engines": { 808 | "node": ">=0.6" 809 | } 810 | }, 811 | "node_modules/type-is": { 812 | "version": "1.6.18", 813 | "resolved": "https://mirrors.cloud.tencent.com/npm/type-is/-/type-is-1.6.18.tgz", 814 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 815 | "dependencies": { 816 | "media-typer": "0.3.0", 817 | "mime-types": "~2.1.24" 818 | }, 819 | "engines": { 820 | "node": ">= 0.6" 821 | } 822 | }, 823 | "node_modules/unpipe": { 824 | "version": "1.0.0", 825 | "resolved": "https://mirrors.cloud.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz", 826 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", 827 | "engines": { 828 | "node": ">= 0.8" 829 | } 830 | }, 831 | "node_modules/utils-merge": { 832 | "version": "1.0.1", 833 | "resolved": "https://mirrors.cloud.tencent.com/npm/utils-merge/-/utils-merge-1.0.1.tgz", 834 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 835 | "engines": { 836 | "node": ">= 0.4.0" 837 | } 838 | }, 839 | "node_modules/vary": { 840 | "version": "1.1.2", 841 | "resolved": "https://mirrors.cloud.tencent.com/npm/vary/-/vary-1.1.2.tgz", 842 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", 843 | "engines": { 844 | "node": ">= 0.8" 845 | } 846 | }, 847 | "node_modules/yallist": { 848 | "version": "4.0.0", 849 | "resolved": "https://mirrors.cloud.tencent.com/npm/yallist/-/yallist-4.0.0.tgz", 850 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 851 | } 852 | } 853 | } 854 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "private", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "axios": "^1.6.3", 13 | "express": "^4.18.2", 14 | "jsonwebtoken": "^9.0.2", 15 | "crypto-js": "^4.2.0", 16 | "jsencrypt": "^3.3.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /server/utils/checkParams.js: -------------------------------------------------------------------------------- 1 | function checkParams(...params) { 2 | for (let param of params) { 3 | if (param === undefined || param === null || param === '') { 4 | return false; 5 | } 6 | } 7 | return true; 8 | } 9 | module.exports = { checkParams } -------------------------------------------------------------------------------- /server/utils/crypto.js: -------------------------------------------------------------------------------- 1 | const Crypto = require('crypto');//加解密 2 | const CryptoJS = require('crypto-js'); 3 | 4 | module.exports = { 5 | EncryptAES, 6 | Crypto_MD5, 7 | Crypto_BASE64_en, 8 | Crypto_BASE64_de, 9 | Crypto_HMACSHA256, 10 | Crypto_SHA256, 11 | Crypto_SHA1, 12 | JSEncrypt 13 | } 14 | function Crypto_MD5(text) { 15 | const hash = Crypto.createHash('md5'); 16 | hash.update(text); 17 | return hash.digest('hex'); 18 | } 19 | 20 | function Crypto_BASE64_en(text) { 21 | const buffer = Buffer.from(text, 'utf8'); 22 | return buffer.toString('base64'); 23 | } 24 | 25 | function Crypto_BASE64_de(text) { 26 | const buffer = Buffer.from(text, 'base64'); 27 | buffer.toString('utf8'); 28 | } 29 | function Crypto_SHA256(str) { 30 | const crypto = require("crypto"); 31 | return crypto.createHash("sha256").update(str).digest("hex"); 32 | 33 | } 34 | function Crypto_HMACSHA256(key, data) { 35 | const hmac = Crypto.createHmac('sha256', key); 36 | hmac.update(data); 37 | return hmac.digest('hex'); 38 | } 39 | function EncryptAES(data, key) { 40 | const dataWordArray = CryptoJS.enc.Utf8.parse(data); 41 | const keyWordArray = CryptoJS.enc.Utf8.parse(key); 42 | const encrypted = CryptoJS.AES.encrypt(dataWordArray, keyWordArray, { 43 | mode: CryptoJS.mode.ECB, 44 | padding: CryptoJS.pad.Pkcs7 45 | }); 46 | return encrypted.toString(); 47 | 48 | } 49 | 50 | function Crypto_SHA1(str) { 51 | const crypto = require('crypto'); 52 | return crypto.createHash("sha1").update(str).digest('hex') 53 | } 54 | function JSEncrypt(publicKey, plainText) { 55 | window = {} 56 | const JSEncrypt = require("jsencrypt") 57 | const crypt = new JSEncrypt() 58 | crypt.setPublicKey(publicKey) 59 | return crypt.encrypt(plainText) 60 | } -------------------------------------------------------------------------------- /server/utils/httpRequest.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | 3 | function httpRequest(options) { 4 | return new Promise((resolve, reject) => { 5 | axios(options).then(res => { 6 | resolve(res) 7 | }).catch(err => { 8 | reject(err) 9 | }) 10 | }) 11 | } 12 | module.exports = { httpRequest } -------------------------------------------------------------------------------- /server/utils/sign.js: -------------------------------------------------------------------------------- 1 | function checkSign(req) { 2 | const { url, method, body } = req; 3 | let key = "a1752adfba6ebf0f0423654973ecee84" 4 | let sign = req.headers.s 5 | let timestamp = req.headers.t 6 | let nonce = req.headers.n 7 | let urlStr = url 8 | let methodStr = method 9 | let bodyStr = JSON.stringify(body) 10 | let checkString = methodStr + urlStr + bodyStr + timestamp + nonce + key 11 | console.log(checkString); 12 | if (hs(checkString) == sign) { 13 | return true 14 | } else { 15 | return false 16 | } 17 | } 18 | //POST/api/main/qrcode/login"{\"app\":\"GacmotorQr\",\"value\":\"0412jgdn1WF5Ha1r\"}"17034909832296b5k33ookna1752adfba6ebf0f0423654973ecee84 19 | //POST/api/main/qrcode/login{"app":"GacmotorQr","value":"0412jgdn1WF5Ha1r"}17034909832296b5k33ookna1752adfba6ebf0f0423654973ecee84 20 | module.exports = { 21 | checkSign 22 | } 23 | function hs(a) { 24 | a = a.toString() 25 | function b(a, b) { 26 | return (a << b) | (a >>> (32 - b)); 27 | } 28 | function c(a, b) { 29 | var c, d, e, f, g; 30 | return ( 31 | (e = 2147483648 & a), 32 | (f = 2147483648 & b), 33 | (c = 1073741824 & a), 34 | (d = 1073741824 & b), 35 | (g = (1073741823 & a) + (1073741823 & b)), 36 | c & d 37 | ? 2147483648 ^ g ^ e ^ f 38 | : c | d 39 | ? 1073741824 & g 40 | ? 3221225472 ^ g ^ e ^ f 41 | : 1073741824 ^ g ^ e ^ f 42 | : g ^ e ^ f 43 | ); 44 | } 45 | function d(a, b, c) { 46 | return (a & b) | (~a & c); 47 | } 48 | function e(a, b, c) { 49 | return (a & c) | (b & ~c); 50 | } 51 | function f(a, b, c) { 52 | return a ^ b ^ c; 53 | } 54 | function g(a, b, c) { 55 | return b ^ (a | ~c); 56 | } 57 | function h(a, e, f, g, h, i, j) { 58 | return (a = c(a, c(c(d(e, f, g), h), j))), c(b(a, i), e); 59 | } 60 | function i(a, d, f, g, h, i, j) { 61 | return (a = c(a, c(c(e(d, f, g), h), j))), c(b(a, i), d); 62 | } 63 | function j(a, d, e, g, h, i, j) { 64 | return (a = c(a, c(c(f(d, e, g), h), j))), c(b(a, i), d); 65 | } 66 | function k(a, d, e, f, h, i, j) { 67 | return (a = c(a, c(c(g(d, e, f), h), j))), c(b(a, i), d); 68 | } 69 | function l(a) { 70 | for ( 71 | var b, 72 | c = a.length, 73 | d = c + 8, 74 | e = (d - (d % 64)) / 64, 75 | f = 16 * (e + 1), 76 | g = new Array(f - 1), 77 | h = 0, 78 | i = 0; 79 | c > i; 80 | 81 | ) 82 | (b = (i - (i % 4)) / 4), 83 | (h = (i % 4) * 8), 84 | (g[b] = g[b] | (a.charCodeAt(i) << h)), 85 | i++; 86 | return ( 87 | (b = (i - (i % 4)) / 4), 88 | (h = (i % 4) * 8), 89 | (g[b] = g[b] | (128 << h)), 90 | (g[f - 2] = c << 3), 91 | (g[f - 1] = c >>> 29), 92 | g 93 | ); 94 | } 95 | function m(a) { 96 | var b, 97 | c, 98 | d = "", 99 | e = ""; 100 | for (c = 0; 3 >= c; c++) 101 | (b = (a >>> (8 * c)) & 255), 102 | (e = "0" + b.toString(16)), 103 | (d += e.substr(e.length - 2, 2)); 104 | return d; 105 | } 106 | function n(a) { 107 | a = a.replace(/\r\n/g, "\n"); 108 | for (var b = "", c = 0; c < a.length; c++) { 109 | var d = a.charCodeAt(c); 110 | 128 > d 111 | ? (b += String.fromCharCode(d)) 112 | : d > 127 && 2048 > d 113 | ? ((b += String.fromCharCode((d >> 6) | 192)), 114 | (b += String.fromCharCode((63 & d) | 128))) 115 | : ((b += String.fromCharCode((d >> 12) | 224)), 116 | (b += String.fromCharCode(((d >> 6) & 63) | 128)), 117 | (b += String.fromCharCode((63 & d) | 128))); 118 | } 119 | return b; 120 | } 121 | var o, 122 | p, 123 | q, 124 | r, 125 | s, 126 | t, 127 | u, 128 | v, 129 | w, 130 | x = [], 131 | y = 7, 132 | z = 12, 133 | A = 17, 134 | B = 22, 135 | C = 5, 136 | D = 9, 137 | E = 14, 138 | F = 20, 139 | G = 4, 140 | H = 11, 141 | I = 16, 142 | J = 23, 143 | K = 6, 144 | L = 10, 145 | M = 15, 146 | N = 21; 147 | for ( 148 | a = n(a), 149 | x = l(a), 150 | t = 1414213562, 151 | u = 3141592653, 152 | v = 2718281828, 153 | w = 1234567890, 154 | o = 0; 155 | o < x.length; 156 | o += 16 157 | ) 158 | (p = t), 159 | (q = u), 160 | (r = v), 161 | (s = w), 162 | (t = h(t, u, v, w, x[o + 0], y, 3614090360)), 163 | (w = h(w, t, u, v, x[o + 1], z, 3905402710)), 164 | (v = h(v, w, t, u, x[o + 2], A, 606105819)), 165 | (u = h(u, v, w, t, x[o + 3], B, 3250441966)), 166 | (t = h(t, u, v, w, x[o + 4], y, 4118548399)), 167 | (w = h(w, t, u, v, x[o + 5], z, 1200080426)), 168 | (v = h(v, w, t, u, x[o + 6], A, 2821735955)), 169 | (u = h(u, v, w, t, x[o + 7], B, 4249261313)), 170 | (t = h(t, u, v, w, x[o + 8], y, 1770035416)), 171 | (w = h(w, t, u, v, x[o + 9], z, 2336552879)), 172 | (v = h(v, w, t, u, x[o + 10], A, 4294925233)), 173 | (u = h(u, v, w, t, x[o + 11], B, 2304563134)), 174 | (t = h(t, u, v, w, x[o + 12], y, 1804603682)), 175 | (w = h(w, t, u, v, x[o + 13], z, 4254626195)), 176 | (v = h(v, w, t, u, x[o + 14], A, 2792965006)), 177 | (u = h(u, v, w, t, x[o + 15], B, 1236535329)), 178 | (t = i(t, u, v, w, x[o + 1], C, 4129170786)), 179 | (w = i(w, t, u, v, x[o + 6], D, 3225465664)), 180 | (v = i(v, w, t, u, x[o + 11], E, 643717713)), 181 | (u = i(u, v, w, t, x[o + 0], F, 3921069994)), 182 | (t = i(t, u, v, w, x[o + 5], C, 3593408605)), 183 | (w = i(w, t, u, v, x[o + 10], D, 38016083)), 184 | (v = i(v, w, t, u, x[o + 15], E, 3634488961)), 185 | (u = i(u, v, w, t, x[o + 4], F, 3889429448)), 186 | (t = i(t, u, v, w, x[o + 9], C, 568446438)), 187 | (w = i(w, t, u, v, x[o + 14], D, 3275163606)), 188 | (v = i(v, w, t, u, x[o + 3], E, 4107603335)), 189 | (u = i(u, v, w, t, x[o + 8], F, 1163531501)), 190 | (t = i(t, u, v, w, x[o + 13], C, 2850285829)), 191 | (w = i(w, t, u, v, x[o + 2], D, 4243563512)), 192 | (v = i(v, w, t, u, x[o + 7], E, 1735328473)), 193 | (u = i(u, v, w, t, x[o + 12], F, 2368359562)), 194 | (t = j(t, u, v, w, x[o + 5], G, 4294588738)), 195 | (w = j(w, t, u, v, x[o + 8], H, 2272392833)), 196 | (v = j(v, w, t, u, x[o + 11], I, 1839030562)), 197 | (u = j(u, v, w, t, x[o + 14], J, 4259657740)), 198 | (t = j(t, u, v, w, x[o + 1], G, 2763975236)), 199 | (w = j(w, t, u, v, x[o + 4], H, 1272893353)), 200 | (v = j(v, w, t, u, x[o + 7], I, 4139469664)), 201 | (u = j(u, v, w, t, x[o + 10], J, 3200236656)), 202 | (t = j(t, u, v, w, x[o + 13], G, 681279174)), 203 | (w = j(w, t, u, v, x[o + 0], H, 3936430074)), 204 | (v = j(v, w, t, u, x[o + 3], I, 3572445317)), 205 | (u = j(u, v, w, t, x[o + 6], J, 76029189)), 206 | (t = j(t, u, v, w, x[o + 9], G, 3654602809)), 207 | (w = j(w, t, u, v, x[o + 12], H, 3873151461)), 208 | (v = j(v, w, t, u, x[o + 15], I, 530742520)), 209 | (u = j(u, v, w, t, x[o + 2], J, 3299628645)), 210 | (t = k(t, u, v, w, x[o + 0], K, 4096336452)), 211 | (w = k(w, t, u, v, x[o + 7], L, 1126891415)), 212 | (v = k(v, w, t, u, x[o + 14], M, 2878612391)), 213 | (u = k(u, v, w, t, x[o + 5], N, 4237533241)), 214 | (t = k(t, u, v, w, x[o + 12], K, 1700485571)), 215 | (w = k(w, t, u, v, x[o + 3], L, 2399980690)), 216 | (v = k(v, w, t, u, x[o + 10], M, 4293915773)), 217 | (u = k(u, v, w, t, x[o + 1], N, 2240044497)), 218 | (t = k(t, u, v, w, x[o + 8], K, 1873313359)), 219 | (w = k(w, t, u, v, x[o + 15], L, 4264355552)), 220 | (v = k(v, w, t, u, x[o + 6], M, 2734768916)), 221 | (u = k(u, v, w, t, x[o + 13], N, 1309151649)), 222 | (t = k(t, u, v, w, x[o + 4], K, 4149444226)), 223 | (w = k(w, t, u, v, x[o + 11], L, 3174756917)), 224 | (v = k(v, w, t, u, x[o + 2], M, 718787259)), 225 | (u = k(u, v, w, t, x[o + 9], N, 3951481745)), 226 | (t = c(t, p)), 227 | (u = c(u, q)), 228 | (v = c(v, r)), 229 | (w = c(w, s)); 230 | var O = m(t) + m(u) + m(v) + m(w); 231 | return O.toLowerCase().split('').reverse().join(''); 232 | } -------------------------------------------------------------------------------- /server/utils/utils.js: -------------------------------------------------------------------------------- 1 | module.exports = { randomString,uuid } 2 | function randomString(length) { 3 | var result = ''; 4 | var characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; 5 | for (var i = 0; i < length; i++) { 6 | result += characters.charAt(Math.floor(Math.random() * characters.length)); 7 | } 8 | return result; 9 | } 10 | function uuid() { 11 | return 'xxxxxxxx-xxxx-xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 12 | var r = Math.random() * 16 | 0, 13 | v = c == 'x' ? r : (r & 0x3 | 0x8); 14 | return v.toString(16); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /server/value.json: -------------------------------------------------------------------------------- 1 | { 2 | "applist": [ 3 | { 4 | "name": "测试", 5 | "variable": "demoaaaa", 6 | "test": "测试哦", 7 | "regular": "", 8 | "envSplitor": null 9 | } 10 | ] 11 | } --------------------------------------------------------------------------------