bgsu commited on
Commit
095bd0f
·
verified ·
1 Parent(s): 05eb9b8

Upload 2 files

Browse files
Files changed (2) hide show
  1. package.json +16 -0
  2. server.js +411 -0
package.json ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "nodejs",
3
+ "main": "server.js",
4
+ "license": "MIT",
5
+ "private": false,
6
+ "scripts": {
7
+ "start": "node server.js"
8
+ },
9
+ "dependencies": {
10
+ "axios": "latest",
11
+ "express": "^4.18.2"
12
+ },
13
+ "engines": {
14
+ "node": ">=14"
15
+ }
16
+ }
server.js ADDED
@@ -0,0 +1,411 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require("express");
2
+ const app = express();
3
+ const axios = require("axios");
4
+ const os = require('os');
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ const { promisify } = require('util');
8
+ const exec = promisify(require('child_process').exec);
9
+ const { execSync } = require('child_process');
10
+ const FILE_PATH = process.env.FILE_PATH || './temp'; // 运行文件夹,节点文件存放目录
11
+ const projectPageURL = process.env.URL || ''; // 填写项目域名可开启自动访问保活,非标端口的前缀是http://
12
+ const intervalInseconds = process.env.TIME || 120; // 自动访问间隔时间(120秒)
13
+ const UUID = process.env.UUID || 'a5c7418b-a059-437d-86c1-d8a4a2568dee';
14
+ const NZ_SERVER = process.env.NZ_SERVER || 'nz.abc.cn'; // 哪吒3个变量不全不运行
15
+ const NZ_PORT = process.env.NZ_PORT || '5555'; // 哪吒端口为{443,8443,2096,2087,2083,2053}其中之一时开启tls
16
+ const NZ_KEY = process.env.NZ_KEY || ''; // 哪吒客户端密钥
17
+ const DOMAIN = process.env.DOMAIN || 'segfault.xvffueue.eu.org'; // 固定隧道域名,留空即启用临时隧道
18
+ const AUTH = process.env.AUTH || 'eyJhIjoiZWFlZTE1ZWZkZDA2MGNiNDRhOGEzMjE1ODlkMzQ4OGYiLCJ0IjoiNmNjY2JhMTctNzNjMC00MjJlLTkxYWMtMzk1MTMxNDMzODVlIiwicyI6Ik4yWXdNVEZtTXpRdFpqVTBPUzAwTVRJeExXSmxPRGt0T1dRMlpETTNabU5tTW1ZdyJ9'; // 固定隧道json或token,留空即启用临时隧道
19
+ const CFIP = process.env.CFIP || 'cfgs.org'; // 优选域名或优选ip
20
+ const CFPORT = process.env.CFPORT || 443; // 节点端口
21
+ const NAME = process.env.NAME || 'Segfault'; // 节点名称
22
+ const AG_PORT = process.env.AG_PORT || 8080; // Argo端口,使用固定隧道token需和cf后台设置的端口对应
23
+ const PORT = process.env.SERVER_PORT || process.env.PORT || 3000; // 节点订阅端口,若无法订阅请手动改为分配的端口
24
+
25
+
26
+ //创建运行文件夹
27
+ if (!fs.existsSync(FILE_PATH)) {
28
+ fs.mkdirSync(FILE_PATH);
29
+ console.log(`${FILE_PATH} is created`);
30
+ } else {
31
+ console.log(`${FILE_PATH} already exists`);
32
+ }
33
+
34
+ //清理历史文件
35
+ const pathsToDelete = [ 'web', 'bot', 'npm', 'sub.txt', 'boot.log'];
36
+ function cleanupOldFiles() {
37
+ pathsToDelete.forEach((file) => {
38
+ const filePath = path.join(FILE_PATH, file);
39
+ fs.unlink(filePath, (err) => {
40
+ if (err) {
41
+ console.error(`Skip Delete ${filePath}`);
42
+ } else {
43
+ console.log(`${filePath} deleted`);
44
+ }
45
+ });
46
+ });
47
+ }
48
+ cleanupOldFiles();
49
+
50
+
51
+ // 根路由
52
+ app.get("/", function(req, res) {
53
+ res.send("Have a great day!");
54
+ });
55
+
56
+
57
+
58
+ // 生成web配置文件
59
+ const config = {
60
+ log: { access: '/dev/null', error: '/dev/null', loglevel: 'none' },
61
+ inbounds: [
62
+ { port: AG_PORT, protocol: 'vless', settings: { clients: [{ id: UUID, flow: 'xtls-rprx-vision' }], decryption: 'none', fallbacks: [{ dest: 3001 }, { path: "/vl-2024-vl", dest: 3002 }, { path: "/vm-2024-vm", dest: 3003 }, { path: "/tr-2024-tr", dest: 3004 }] }, streamSettings: { network: 'tcp' } },
63
+ { port: 3001, listen: "127.0.0.1", protocol: "vless", settings: { clients: [{ id: UUID }], decryption: "none" }, streamSettings: { network: "ws", security: "none" } },
64
+ { port: 3002, listen: "127.0.0.1", protocol: "vless", settings: { clients: [{ id: UUID, level: 0 }], decryption: "none" }, streamSettings: { network: "ws", security: "none", wsSettings: { path: "/vl-2024-vl" } }, sniffing: { enabled: false, destOverride: ["http", "tls", "quic"], metadataOnly: false } },
65
+ { port: 3003, listen: "127.0.0.1", protocol: "vmess", settings: { clients: [{ id: UUID, alterId: 0 }] }, streamSettings: { network: "ws", wsSettings: { path: "/vm-2024-vm" } }, sniffing: { enabled: false, destOverride: ["http", "tls", "quic"], metadataOnly: false } },
66
+ { port: 3004, listen: "127.0.0.1", protocol: "trojan", settings: { clients: [{ password: UUID }] }, streamSettings: { network: "ws", security: "none", wsSettings: { path: "/tr-2024-tr" } }, sniffing: { enabled: false, destOverride: ["http", "tls", "quic"], metadataOnly: false } },
67
+ ],
68
+ dns: { servers: ["https+local://8.8.8.8/dns-query"] },
69
+ outbounds: [
70
+ { protocol: "freedom" },
71
+ {
72
+ tag: "WARP",
73
+ protocol: "wireguard",
74
+ settings: {
75
+ secretKey: "gEKluMrhzn1hcxikEmVLJtNZCKIsOuCZtU8EZYYge2E=",
76
+ address: ["172.16.0.2/32", "2606:4700:110:83fa:8b32:26ea:4329:2842/128"],
77
+ peers: [{ publicKey: "bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=", allowedIPs: ["0.0.0.0/0", "::/0"], endpoint: "162.159.193.10:2408" }],
78
+ reserved: [78, 135, 76],
79
+ mtu: 1280,
80
+ },
81
+ },
82
+ ],
83
+ routing: { domainStrategy: "AsIs", rules: [{ type: "field", domain: ["domain:openai.com", "domain:ai.com"], outboundTag: "WARP" }] },
84
+ };
85
+ fs.writeFileSync(path.join(FILE_PATH, 'config.json'), JSON.stringify(config, null, 2));
86
+
87
+ // 判断系统架构
88
+ function getSystemArchitecture() {
89
+ const arch = os.arch();
90
+ if (arch === 'arm' || arch === 'arm64' || arch === 'aarch64') {
91
+ return 'arm';
92
+ } else {
93
+ return 'amd';
94
+ }
95
+ }
96
+
97
+ // 下载对应系统架构的依赖文件
98
+ function downloadFile(fileName, fileUrl, callback) {
99
+ const filePath = path.join(FILE_PATH, fileName);
100
+ const writer = fs.createWriteStream(filePath);
101
+
102
+ axios({
103
+ method: 'get',
104
+ url: fileUrl,
105
+ responseType: 'stream',
106
+ })
107
+ .then(response => {
108
+ response.data.pipe(writer);
109
+
110
+ writer.on('finish', () => {
111
+ writer.close();
112
+ console.log(`Download ${fileName} successfully`);
113
+ callback(null, fileName);
114
+ });
115
+
116
+ writer.on('error', err => {
117
+ fs.unlink(filePath, () => { });
118
+ const errorMessage = `Download ${fileName} failed: ${err.message}`;
119
+ console.error(errorMessage); // 下载失败时输出错误消息
120
+ callback(errorMessage);
121
+ });
122
+ })
123
+ .catch(err => {
124
+ const errorMessage = `Download ${fileName} failed: ${err.message}`;
125
+ console.error(errorMessage); // 下载失败时输出错误消息
126
+ callback(errorMessage);
127
+ });
128
+ }
129
+
130
+ // 下载并运行依赖文件
131
+ async function downloadFilesAndRun() {
132
+ const architecture = getSystemArchitecture();
133
+ const filesToDownload = getFilesForArchitecture(architecture);
134
+
135
+ if (filesToDownload.length === 0) {
136
+ console.log(`Can't find a file for the current architecture`);
137
+ return;
138
+ }
139
+
140
+ const downloadPromises = filesToDownload.map(fileInfo => {
141
+ return new Promise((resolve, reject) => {
142
+ downloadFile(fileInfo.fileName, fileInfo.fileUrl, (err, fileName) => {
143
+ if (err) {
144
+ reject(err);
145
+ } else {
146
+ resolve(fileName);
147
+ }
148
+ });
149
+ });
150
+ });
151
+
152
+ try {
153
+ await Promise.all(downloadPromises); // 等待所有文件下载完成
154
+ } catch (err) {
155
+ console.error('Error downloading files:', err);
156
+ return;
157
+ }
158
+
159
+ // 授权和运行
160
+ function authorizeFiles(filePaths) {
161
+ const newPermissions = 0o775;
162
+
163
+ filePaths.forEach(relativeFilePath => {
164
+ const absoluteFilePath = path.join(FILE_PATH, relativeFilePath);
165
+
166
+ fs.chmod(absoluteFilePath, newPermissions, (err) => {
167
+ if (err) {
168
+ console.error(`Empowerment failed for ${absoluteFilePath}: ${err}`);
169
+ } else {
170
+ console.log(`Empowerment success for ${absoluteFilePath}: ${newPermissions.toString(8)}`);
171
+ }
172
+ });
173
+ });
174
+ }
175
+ const filesToAuthorize = ['./npm', './web', './bot'];
176
+ authorizeFiles(filesToAuthorize);
177
+
178
+ //运行ne-zha
179
+ let NZ_TLS = '';
180
+ if (NZ_SERVER && NZ_PORT && NZ_KEY) {
181
+ const tlsPorts = ['443', '8443', '2096', '2087', '2083', '2053'];
182
+ if (tlsPorts.includes(NZ_PORT)) {
183
+ NZ_TLS = '--tls';
184
+ } else {
185
+ NZ_TLS = '';
186
+ }
187
+ const command = `nohup ${FILE_PATH}/npm -s ${NZ_SERVER}:${NZ_PORT} -p ${NZ_KEY} ${NZ_TLS} >/dev/null 2>&1 &`;
188
+ try {
189
+ await exec(command);
190
+ console.log('npm is running');
191
+ await new Promise((resolve) => setTimeout(resolve, 1000));
192
+ } catch (error) {
193
+ console.error(`npm running error: ${error}`);
194
+ }
195
+ } else {
196
+ console.log('NZ variable is empty,skip running');
197
+ }
198
+
199
+ //运行xr-ay
200
+ const command1 = `nohup ${FILE_PATH}/web -c ${FILE_PATH}/config.json >/dev/null 2>&1 &`;
201
+ try {
202
+ await exec(command1);
203
+ console.log('web is running');
204
+ await new Promise((resolve) => setTimeout(resolve, 1000));
205
+ } catch (error) {
206
+ console.error(`web running error: ${error}`);
207
+ }
208
+
209
+ // 运行cloud-fared
210
+ if (fs.existsSync(path.join(FILE_PATH, 'bot'))) {
211
+ let args;
212
+
213
+ if (AUTH.match(/^[A-Z0-9a-z=]{120,250}$/)) {
214
+ args = `tunnel --edge-ip-version auto --no-autoupdate --protocol http2 run --token ${AUTH}`;
215
+ } else if (AUTH.match(/TunnelSecret/)) {
216
+ args = `tunnel --edge-ip-version auto --config ${FILE_PATH}/tunnel.yml run`;
217
+ } else {
218
+ args = `tunnel --edge-ip-version auto --no-autoupdate --protocol http2 --logfile ${FILE_PATH}/boot.log --loglevel info --url http://localhost:${AG_PORT}`;
219
+ }
220
+
221
+ try {
222
+ await exec(`nohup ${FILE_PATH}/bot ${args} >/dev/null 2>&1 &`);
223
+ console.log('bot is running');
224
+ await new Promise((resolve) => setTimeout(resolve, 2000));
225
+ } catch (error) {
226
+ console.error(`Error executing command: ${error}`);
227
+ }
228
+ }
229
+ await new Promise((resolve) => setTimeout(resolve, 5000));
230
+
231
+ }
232
+ //根据系统架构返回对应的url
233
+ function getFilesForArchitecture(architecture) {
234
+ if (architecture === 'arm') {
235
+ return [
236
+ { fileName: "npm", fileUrl: "https://github.com/eooce/test/releases/download/ARM/swith" },
237
+ { fileName: "web", fileUrl: "https://github.com/eooce/test/releases/download/ARM/web" },
238
+ { fileName: "bot", fileUrl: "https://github.com/eooce/test/releases/download/arm64/bot13" },
239
+ ];
240
+ } else if (architecture === 'amd') {
241
+ return [
242
+ { fileName: "npm", fileUrl: "https://github.com/eooce/test/releases/download/amd64/npm" },
243
+ { fileName: "web", fileUrl: "https://github.com/eooce/test/releases/download/amd64/web" },
244
+ { fileName: "bot", fileUrl: "https://github.com/eooce/test/releases/download/amd64/bot13" },
245
+ ];
246
+ }
247
+ return [];
248
+ }
249
+
250
+ // 获取固定隧道json
251
+ function argoType() {
252
+ if (!AUTH || !DOMAIN) {
253
+ console.log("DOMAIN or AUTH variable is empty, use quick tunnels");
254
+ return;
255
+ }
256
+
257
+ if (AUTH.includes('TunnelSecret')) {
258
+ fs.writeFileSync(path.join(FILE_PATH, 'tunnel.json'), AUTH);
259
+ const tunnelYaml = `
260
+ tunnel: ${AUTH.split('"')[11]}
261
+ credentials-file: ${path.join(FILE_PATH, 'tunnel.json')}
262
+ protocol: http2
263
+
264
+ ingress:
265
+ - hostname: ${DOMAIN}
266
+ service: http://localhost:${AG_PORT}
267
+ originRequest:
268
+ noTLSVerify: true
269
+ - service: http_status:404
270
+ `;
271
+ fs.writeFileSync(path.join(FILE_PATH, 'tunnel.yml'), tunnelYaml);
272
+ } else {
273
+ console.log("AUTH mismatch TunnelSecret,use token connect to tunnel");
274
+ }
275
+ }
276
+ argoType();
277
+
278
+ // 获取临时隧道domain
279
+ async function extractDomains() {
280
+ let argoDomain;
281
+
282
+ if (AUTH && DOMAIN) {
283
+ argoDomain = DOMAIN;
284
+ console.log('DOMAIN:', argoDomain);
285
+ await generateLinks(argoDomain);
286
+ } else {
287
+ try {
288
+ const fileContent = fs.readFileSync(path.join(FILE_PATH, 'boot.log'), 'utf-8');
289
+ const lines = fileContent.split('\n');
290
+ const argoDomains = [];
291
+ lines.forEach((line) => {
292
+ const domainMatch = line.match(/https?:\/\/([^ ]*trycloudflare\.com)\/?/);
293
+ if (domainMatch) {
294
+ const domain = domainMatch[1];
295
+ argoDomains.push(domain);
296
+ }
297
+ });
298
+
299
+ if (argoDomains.length > 0) {
300
+ argoDomain = argoDomains[0];
301
+ console.log('ArgoDomain:', argoDomain);
302
+ await generateLinks(argoDomain);
303
+ } else {
304
+ console.log('ArgoDomain not found, re-running bot to obtain ArgoDomain');
305
+ // 删除 boot.log 文件,等待 2s 重新运行 server 以获取 ArgoDomain
306
+ fs.unlinkSync(path.join(FILE_PATH, 'boot.log'));
307
+ await new Promise((resolve) => setTimeout(resolve, 2000));
308
+ const args = `tunnel --edge-ip-version auto --no-autoupdate --protocol http2 --logfile ${FILE_PATH}/boot.log --loglevel info --url http://localhost:${AG_PORT}`;
309
+ try {
310
+ await exec(`nohup ${path.join(FILE_PATH, 'bot')} ${args} >/dev/null 2>&1 &`);
311
+ console.log('bot is running.');
312
+ await new Promise((resolve) => setTimeout(resolve, 3000));
313
+ await extractDomains(); // 重新提取域名
314
+ } catch (error) {
315
+ console.error(`Error executing command: ${error}`);
316
+ }
317
+ }
318
+ } catch (error) {
319
+ console.error('Error reading boot.log:', error);
320
+ }
321
+ }
322
+
323
+ // 生成 list 和 sub 信息
324
+ async function generateLinks(argoDomain) {
325
+ const metaInfo = execSync(
326
+ 'curl -s https://speed.cloudflare.com/meta | awk -F\\" \'{print $26"-"$18}\' | sed -e \'s/ /_/g\'',
327
+ { encoding: 'utf-8' }
328
+ );
329
+ const ISP = metaInfo.trim();
330
+
331
+ return new Promise((resolve) => {
332
+ setTimeout(() => {
333
+ const VMESS = { v: '2', ps: `${NAME}-${ISP}`, add: CFIP, port: CFPORT, id: UUID, aid: '0', scy: 'none', net: 'ws', type: 'none', host: argoDomain, path: '/vm-2024-vm?ed=2048', tls: 'tls', sni: argoDomain, alpn: '' };
334
+ const subTxt = `
335
+ vless://${UUID}@${CFIP}:${CFPORT}?encryption=none&security=tls&sni=${argoDomain}&type=ws&host=${argoDomain}&path=%2Fvl-2024-vl%3Fed%3D2048#${NAME}-${ISP}
336
+
337
+ vmess://${Buffer.from(JSON.stringify(VMESS)).toString('base64')}
338
+
339
+ trojan://${UUID}@${CFIP}:${CFPORT}?security=tls&sni=${argoDomain}&type=ws&host=${argoDomain}&path=%2Ftr-2024-tr%3Fed%3D2048#${NAME}-${ISP}
340
+ `;
341
+
342
+ // 打印 sub.txt 内容到控制台
343
+ console.log(Buffer.from(subTxt).toString('base64'));
344
+ const filePath = path.join(FILE_PATH, 'sub.txt');
345
+ fs.writeFileSync(filePath, Buffer.from(subTxt).toString('base64'));
346
+ console.log('File saved successfully');
347
+ console.log('Thank you for using this script,enjoy!');
348
+ // 将内容进行 base64 编码并写入 /sub-sub 路由
349
+ app.get('/sub-sub', (req, res) => {
350
+ const encodedContent = Buffer.from(subTxt).toString('base64');
351
+ res.set('Content-Type', 'text/plain; charset=utf-8');
352
+ res.send(encodedContent);
353
+ });
354
+ resolve(subTxt);
355
+ }, 2000);
356
+ });
357
+ }
358
+ }
359
+
360
+ // 2分钟后删除boot,config文件
361
+ const bootLogPath = path.join(FILE_PATH, 'boot.log');
362
+ const configPath = path.join(FILE_PATH, 'config.json');
363
+ function cleanFiles() {
364
+ setTimeout(() => {
365
+ exec(`rm -rf ${bootLogPath} ${configPath}`, (error, stdout, stderr) => {
366
+ if (error) {
367
+ console.error(`Error while deleting files: ${error}`);
368
+ return;
369
+ }
370
+ console.clear()
371
+ console.log('App is running');
372
+ console.log('Thank you for using this script,enjoy!');
373
+ });
374
+ }, 120000); // 120 秒
375
+ }
376
+ cleanFiles();
377
+
378
+ // 自动访问项目URL
379
+ let hasLoggedEmptyMessage = false;
380
+ async function visitProjectPage() {
381
+ try {
382
+ // 如果URL和TIME变量为空时跳过���问项目URL
383
+ if (!projectPageURL || !intervalInseconds) {
384
+ if (!hasLoggedEmptyMessage) {
385
+ console.log("URL or TIME variable is empty,skip visit url");
386
+ hasLoggedEmptyMessage = true;
387
+ }
388
+ return;
389
+ } else {
390
+ hasLoggedEmptyMessage = false;
391
+ }
392
+
393
+ await axios.get(projectPageURL);
394
+ // console.log(`Visiting project page: ${URL}`);
395
+ console.log('Page visited successfully');
396
+ console.clear()
397
+ } catch (error) {
398
+ console.error('Error visiting project page:', error.message);
399
+ }
400
+ }
401
+ setInterval(visitProjectPage, intervalInseconds * 1000);
402
+
403
+ // 回调运行
404
+ async function startserver() {
405
+ await downloadFilesAndRun();
406
+ await extractDomains();
407
+ visitProjectPage();
408
+ }
409
+ startserver();
410
+
411
+ app.listen(PORT, () => console.log(`Http server is running on port:${PORT}!`));