├── .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 |
2 |
8 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 网站名称:
14 | 网站公告:
15 | 修改
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 青龙Url: 例如http://127.0.0.1:5700
24 | 青龙应用id: 青龙系统设置 应用设置
25 | 青龙应用secret: 青龙系统设置 应用设置
26 | 青龙版本: 暂时只支持大于版本
27 |
28 | 大于>V2.11.X
29 | 小于>V2.11.X
30 |
31 |
32 | 连通测试
33 | 修改
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 项目昵称
45 |
46 |
47 | 变量名
48 |
49 | 变量值示例
50 |
51 | 变量正则非必填
52 |
53 | 一对一变量模式
54 |
56 | 请输入多个账号的分隔符
57 |
58 | 保存
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
209 |
--------------------------------------------------------------------------------
/client/src/components/AliCaptcha.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/client/src/components/Default.vue:
--------------------------------------------------------------------------------
1 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 | 密码登录
429 | 手机登录
430 | 扫码登录
431 | 自定义上传
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
{{ testTips }}
451 |
452 |
453 |
454 |
455 | {{ sendSMSText }}
456 |
457 |
458 |
459 |
460 | {{ tips }}
461 |
462 |
463 |
464 |
465 |
466 |
![QR Code]()
467 |
468 |
获取/刷新 二维码
469 |
470 |
471 |
变量名
472 |
473 |
{{ customValueTestText }}
474 |
475 |
476 | {{ customValueUpdateConfig.test }}
477 |
478 |
变量值
479 |
480 |
481 |
482 |
483 |
484 |
485 | 登录
486 |
487 |
488 |
上传变量
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
502 |
503 |
504 |
505 |
--------------------------------------------------------------------------------
/client/src/components/Dialog.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 | {{ store.dialog.message }}
26 |
27 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/client/src/components/Geetest3Captcha.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
48 |
49 |
--------------------------------------------------------------------------------
/client/src/components/Geetest4Captcha.vue:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/client/src/components/ImageCaptcha.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |
5 |
6 |
7 |
20 |
--------------------------------------------------------------------------------
/client/src/components/Login.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
管理员 - 登录/注册
7 |
8 |
9 |
10 |
11 |
登录
12 |
注册
13 |
14 |
15 |
16 |
57 |
--------------------------------------------------------------------------------
/client/src/components/Message.vue:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/client/src/components/Notification.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
18 |
--------------------------------------------------------------------------------
/client/src/components/TencentCaptcha.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
91 |
--------------------------------------------------------------------------------
/client/src/components/YiDunCapacha.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 | }
--------------------------------------------------------------------------------