tanyu_admin 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +16 -0
- package/.github/workflows/docker-build.yml +52 -0
- package/CLAUDE.md +85 -0
- package/DEPLOY.md +367 -0
- package/Dockerfile +27 -0
- package/archive/dataCrypto.js +124 -0
- package/archive/delte.js +29 -0
- package/archive/edit.js +29 -0
- package/axios-interceptor-example.js +57 -0
- package/axios-interceptor.js +191 -0
- package/cli.js +313 -0
- package/design-output.txt +5 -0
- package/design-system/virtual-host-management/MASTER.md +202 -0
- package/design-system-output.md +5 -0
- package/design-system-result.md +50 -0
- package/design-system.md +0 -0
- package/docker-compose.yml +18 -0
- package/index.js +404 -0
- package/jsencrypt.min.js +2 -0
- package/modem-api.js +419 -0
- package/package.json +42 -0
- package/parser.js +146 -0
- package/public/index.html +656 -0
- package/readme.md +1 -0
- package/server.js +268 -0
- package/test.js +7 -0
package/archive/delte.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const qs = require('qs');
|
|
3
|
+
|
|
4
|
+
let data = qs.stringify({
|
|
5
|
+
'IF_ENCODE': 'V3+M9KUe3Wem533P6CXo7Pr79X8pmCLI/WAQPybu1Rmrzk8fvXbcz97Kx+z9BIJnOyo7s4DsV4GI6CLGxLHZEciVX5Os5+u5/yIrU0k+LZ+BiYMVL2q7Zxda/krU+2XHRdi/E1L+VjUh5P1PQ4WN5xpFgfY4eCGqhsjEnAg28ZBGapBB7/14UxZnD6JX230kUa3lfdT6LPnTPU+Mf8cB0dJjU5v62ba9QjI6dYmhffXochfDh3ndeGZoYlgxQpL1FSyJTIRRCu+P15BXKekTKWEJ2Uhi9iZY0RUY3Ne6dp5K85KIowxG9eBC5tNXFB55M3MQvN9762HQmoyLZMTm3A==',
|
|
6
|
+
'IF_ENCODEPARAM': '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'
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
let config = {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
url: 'http://192.168.1.1/getpage.gch?pid=1002&nextpage=app_virtual_conf_t.gch',
|
|
12
|
+
headers: {
|
|
13
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
|
|
14
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
15
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
16
|
+
'Accept-Language': 'zh-CN,zh;q=0.9',
|
|
17
|
+
'Cache-Control': 'max-age=0',
|
|
18
|
+
'Origin': 'http://192.168.1.1',
|
|
19
|
+
'Proxy-Connection': 'keep-alive',
|
|
20
|
+
'Referer': 'http://192.168.1.1/getpage.gch?pid=1002&nextpage=app_virtual_conf_t.gch',
|
|
21
|
+
'Upgrade-Insecure-Requests': '1',
|
|
22
|
+
'Cookie': '_TESTCOOKIESUPPORT=1; SID=28b56d3b5a6b6eb4f32557ba8b843f634deabd4f69c4dceaa5b445adc47e06fb'
|
|
23
|
+
},
|
|
24
|
+
data: data
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
axios.request(config)
|
|
28
|
+
.then(response => console.log(response))
|
|
29
|
+
.catch(error => console.log('error', error));
|
package/archive/edit.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const qs = require('qs');
|
|
3
|
+
|
|
4
|
+
let data = qs.stringify({
|
|
5
|
+
'IF_ENCODE': "cBdTJBUFObmLbtm99LwstDJzhVkcPOvShgpiGnwhLYdFNeJ3PqrgOgfFosOeve6BxfSXfLDouNwrDuxWS0VnLDE+XdANTjYFt0TJghOE+3cfZ6s0KVap6WSkMyySfdsoYaK2kctFFnrw8pUxCeIh8LAoGi33DFGeUo6ZL3oMxrCHo1gM54pl/kulVrC6u/Efol/bkD3BDNeyjLmMwZhb17pmejEoDj6KqJJftG4xMdEQTlm/iblEcoHu5NTP7aBitAT+rMAizC+pygmvGqlxgPklrS5GOGrF/NI08j/yfeDKzgIyj4+qELC/riUuF5M6i0b13+1+jYDU98lZZxx1Jg==",
|
|
6
|
+
'IF_ENCODEPARAM': "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"
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
let config = {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
url: 'http://192.168.1.1/getpage.gch?pid=1002&nextpage=app_virtual_conf_t.gch',
|
|
12
|
+
headers: {
|
|
13
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
|
|
14
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
15
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
16
|
+
'Accept-Language': 'zh-CN,zh;q=0.9',
|
|
17
|
+
'Cache-Control': 'max-age=0',
|
|
18
|
+
'Origin': 'http://192.168.1.1',
|
|
19
|
+
'Proxy-Connection': 'keep-alive',
|
|
20
|
+
'Referer': 'http://192.168.1.1/template.gch?pid=1002&nextpage=app_virtual_conf_t.gch',
|
|
21
|
+
'Upgrade-Insecure-Requests': '1',
|
|
22
|
+
'Cookie': 'SID=946e3dfb38e6fdbf66ffabe0d58a63573ebef289d9b008545415989d10b1e1e0; _TESTCOOKIESUPPORT=1'
|
|
23
|
+
},
|
|
24
|
+
data: data
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
axios.request(config)
|
|
28
|
+
.then(response => console.log(response))
|
|
29
|
+
.catch(error => console.log('error', error));
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* axios-interceptor 使用示例
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 方式1: 使用默认实例
|
|
6
|
+
const { axios } = require('./axios-interceptor');
|
|
7
|
+
|
|
8
|
+
async function example1() {
|
|
9
|
+
console.log('=== 示例1: 使用默认实例 ===\n');
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// GET 请求
|
|
13
|
+
await axios.get('http://192.168.1.1/cu.html');
|
|
14
|
+
|
|
15
|
+
// POST 请求
|
|
16
|
+
await axios.post('http://192.168.1.1/cu.html', {
|
|
17
|
+
username: 'admin',
|
|
18
|
+
password: 'test123'
|
|
19
|
+
});
|
|
20
|
+
} catch (error) {
|
|
21
|
+
// 错误已经被拦截器记录
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 方式2: 创建自定义实例
|
|
26
|
+
const { createAxiosInstance } = require('./axios-interceptor');
|
|
27
|
+
|
|
28
|
+
async function example2() {
|
|
29
|
+
console.log('\n=== 示例2: 创建自定义实例 ===\n');
|
|
30
|
+
|
|
31
|
+
const customAxios = createAxiosInstance({
|
|
32
|
+
baseURL: 'http://192.168.1.1',
|
|
33
|
+
timeout: 5000,
|
|
34
|
+
headers: {
|
|
35
|
+
'User-Agent': 'Custom Agent'
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
await customAxios.get('/cu.html');
|
|
41
|
+
} catch (error) {
|
|
42
|
+
// 错误已经被拦截器记录
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 方式3: 在现有代码中替换 axios
|
|
47
|
+
// 在 index.js 或 modem-api.js 中:
|
|
48
|
+
// const axios = require('axios'); // 旧代码
|
|
49
|
+
// const { axios } = require('./axios-interceptor'); // 新代码
|
|
50
|
+
|
|
51
|
+
// 运行示例
|
|
52
|
+
if (require.main === module) {
|
|
53
|
+
(async () => {
|
|
54
|
+
await example1();
|
|
55
|
+
await example2();
|
|
56
|
+
})();
|
|
57
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 格式化日志时间戳
|
|
5
|
+
*/
|
|
6
|
+
function formatTimestamp() {
|
|
7
|
+
const now = new Date();
|
|
8
|
+
return now.toISOString().replace('T', ' ').substring(0, 23);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 格式化请求数据用于日志输出
|
|
13
|
+
*/
|
|
14
|
+
function formatRequestData(data) {
|
|
15
|
+
if (!data) return '';
|
|
16
|
+
|
|
17
|
+
// 如果是字符串且很长,截断显示
|
|
18
|
+
if (typeof data === 'string') {
|
|
19
|
+
return data.length > 200 ? data.substring(0, 200) + '...' : data;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 如果是对象,转为JSON
|
|
23
|
+
try {
|
|
24
|
+
const json = JSON.stringify(data);
|
|
25
|
+
return json.length > 200 ? json.substring(0, 200) + '...' : json;
|
|
26
|
+
} catch (e) {
|
|
27
|
+
return '[Complex Data]';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 创建配置好拦截器的 axios 实例
|
|
33
|
+
*/
|
|
34
|
+
function createAxiosInstance(options = {}) {
|
|
35
|
+
// 合并默认配置和用户配置
|
|
36
|
+
const defaultConfig = {
|
|
37
|
+
// 代理配置 - 代理到本地7897端口(用于调试/抓包)
|
|
38
|
+
// 可通过环境变量 ENABLE_PROXY=false 禁用
|
|
39
|
+
proxy: {
|
|
40
|
+
host: '127.0.0.1',
|
|
41
|
+
port: 7897,
|
|
42
|
+
protocol: 'http'
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const instance = axios.create({ ...defaultConfig, ...options });
|
|
47
|
+
|
|
48
|
+
// 请求拦截器
|
|
49
|
+
instance.interceptors.request.use(
|
|
50
|
+
(config) => {
|
|
51
|
+
// 记录请求开始时间
|
|
52
|
+
config.metadata = { startTime: Date.now() };
|
|
53
|
+
|
|
54
|
+
// 构建日志信息
|
|
55
|
+
const logParts = [
|
|
56
|
+
`[${formatTimestamp()}]`,
|
|
57
|
+
`[REQUEST]`,
|
|
58
|
+
`${config.method?.toUpperCase() || 'GET'}`,
|
|
59
|
+
config.url
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// 添加查询参数信息
|
|
63
|
+
if (config.params) {
|
|
64
|
+
logParts.push(`| Params: ${JSON.stringify(config.params)}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 添加请求体信息(如果有)
|
|
68
|
+
if (config.data) {
|
|
69
|
+
const formattedData = formatRequestData(config.data);
|
|
70
|
+
if (formattedData) {
|
|
71
|
+
logParts.push(`| Data: ${formattedData}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 添加重要的请求头信息
|
|
76
|
+
if (config.headers) {
|
|
77
|
+
const importantHeaders = {};
|
|
78
|
+
if (config.headers['Content-Type']) {
|
|
79
|
+
importantHeaders['Content-Type'] = config.headers['Content-Type'];
|
|
80
|
+
}
|
|
81
|
+
if (config.headers['Cookie']) {
|
|
82
|
+
importantHeaders['Cookie'] = '[REDACTED]'; // 隐藏敏感信息
|
|
83
|
+
}
|
|
84
|
+
if (config.headers['Authorization']) {
|
|
85
|
+
importantHeaders['Authorization'] = '[REDACTED]'; // 隐藏敏感信息
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (Object.keys(importantHeaders).length > 0) {
|
|
89
|
+
logParts.push(`| Headers: ${JSON.stringify(importantHeaders)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// console.log(logParts.join(' '));
|
|
94
|
+
|
|
95
|
+
return config;
|
|
96
|
+
},
|
|
97
|
+
(error) => {
|
|
98
|
+
console.error(`[${formatTimestamp()}] [REQUEST ERROR]`, error.message);
|
|
99
|
+
return Promise.reject(error);
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// 响应拦截器
|
|
104
|
+
instance.interceptors.response.use(
|
|
105
|
+
(response) => {
|
|
106
|
+
// 计算请求耗时
|
|
107
|
+
const duration = response.config.metadata
|
|
108
|
+
? Date.now() - response.config.metadata.startTime
|
|
109
|
+
: 0;
|
|
110
|
+
|
|
111
|
+
// 构建日志信息
|
|
112
|
+
const logParts = [
|
|
113
|
+
`[${formatTimestamp()}]`,
|
|
114
|
+
`[RESPONSE]`,
|
|
115
|
+
`${response.config.method?.toUpperCase() || 'GET'}`,
|
|
116
|
+
response.config.url,
|
|
117
|
+
`| Status: ${response.status}`,
|
|
118
|
+
`| Duration: ${duration}ms`
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
// 添加响应大小信息
|
|
122
|
+
if (response.data) {
|
|
123
|
+
let dataSize = 0;
|
|
124
|
+
if (typeof response.data === 'string') {
|
|
125
|
+
dataSize = response.data.length;
|
|
126
|
+
} else if (Buffer.isBuffer(response.data)) {
|
|
127
|
+
dataSize = response.data.length;
|
|
128
|
+
} else {
|
|
129
|
+
try {
|
|
130
|
+
dataSize = JSON.stringify(response.data).length;
|
|
131
|
+
} catch (e) {
|
|
132
|
+
dataSize = 0;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (dataSize > 0) {
|
|
137
|
+
const sizeKB = (dataSize / 1024).toFixed(2);
|
|
138
|
+
logParts.push(`| Size: ${sizeKB}KB`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// console.log(logParts.join(' ')); // 已禁用 RESPONSE 日志
|
|
143
|
+
|
|
144
|
+
return response;
|
|
145
|
+
},
|
|
146
|
+
(error) => {
|
|
147
|
+
// 计算请求耗时
|
|
148
|
+
const duration = error.config?.metadata
|
|
149
|
+
? Date.now() - error.config.metadata.startTime
|
|
150
|
+
: 0;
|
|
151
|
+
|
|
152
|
+
// 构建错误日志
|
|
153
|
+
const logParts = [
|
|
154
|
+
`[${formatTimestamp()}]`,
|
|
155
|
+
`[RESPONSE ERROR]`,
|
|
156
|
+
`${error.config?.method?.toUpperCase() || 'GET'}`,
|
|
157
|
+
error.config?.url || 'Unknown URL'
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
if (error.response) {
|
|
161
|
+
// 服务器返回了错误状态码
|
|
162
|
+
logParts.push(`| Status: ${error.response.status}`);
|
|
163
|
+
logParts.push(`| Duration: ${duration}ms`);
|
|
164
|
+
logParts.push(`| Error: ${error.message}`);
|
|
165
|
+
} else if (error.request) {
|
|
166
|
+
// 请求已发送但没有收到响应
|
|
167
|
+
logParts.push(`| Duration: ${duration}ms`);
|
|
168
|
+
logParts.push(`| Error: No response received - ${error.message}`);
|
|
169
|
+
} else {
|
|
170
|
+
// 请求配置出错
|
|
171
|
+
logParts.push(`| Error: ${error.message}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// console.error(logParts.join(' ')); // 已禁用 RESPONSE ERROR 日志
|
|
175
|
+
|
|
176
|
+
return Promise.reject(error);
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
return instance;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 创建默认实例
|
|
184
|
+
const axiosInstance = createAxiosInstance();
|
|
185
|
+
|
|
186
|
+
// 导出
|
|
187
|
+
module.exports = {
|
|
188
|
+
default: axiosInstance,
|
|
189
|
+
createAxiosInstance,
|
|
190
|
+
axios: axiosInstance
|
|
191
|
+
};
|
package/cli.js
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { Command } = require('commander');
|
|
4
|
+
const Table = require('cli-table3');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const { refreshFromModem, addHost, deleteHost } = require('./modem-api');
|
|
7
|
+
const { loadConfigFromFile, saveConfigToJson } = require('./parser');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const program = new Command();
|
|
12
|
+
|
|
13
|
+
// 配置文件路径
|
|
14
|
+
const CACHE_DIR = './.cache';
|
|
15
|
+
const CACHE_HTML = path.join(CACHE_DIR, 'page.html');
|
|
16
|
+
const DATA_FILE = './virtual_hosts.json';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 格式化协议显示
|
|
20
|
+
*/
|
|
21
|
+
function formatProtocol(protocol) {
|
|
22
|
+
const protocolMap = {
|
|
23
|
+
'0': 'TCP',
|
|
24
|
+
'1': 'UDP',
|
|
25
|
+
'2': 'TCP/UDP'
|
|
26
|
+
};
|
|
27
|
+
return protocolMap[protocol] || protocol;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 格式化启用状态
|
|
32
|
+
*/
|
|
33
|
+
function formatEnable(enable) {
|
|
34
|
+
if (enable === '1') {
|
|
35
|
+
return chalk.green('✓ 启用');
|
|
36
|
+
} else {
|
|
37
|
+
return chalk.red('✗ 禁用');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 验证 IP 地址格式
|
|
43
|
+
*/
|
|
44
|
+
function isValidIP(ip) {
|
|
45
|
+
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
46
|
+
if (!ipRegex.test(ip)) return false;
|
|
47
|
+
|
|
48
|
+
const parts = ip.split('.');
|
|
49
|
+
return parts.every(part => {
|
|
50
|
+
const num = parseInt(part, 10);
|
|
51
|
+
return num >= 0 && num <= 255;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 验证端口号
|
|
57
|
+
*/
|
|
58
|
+
function isValidPort(port) {
|
|
59
|
+
const portNum = parseInt(port, 10);
|
|
60
|
+
return !isNaN(portNum) && portNum >= 1 && portNum <= 65535;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* router add 命令 - 快速添加端口转发规则
|
|
65
|
+
*/
|
|
66
|
+
async function addRouter(ip, port, name) {
|
|
67
|
+
try {
|
|
68
|
+
// 验证 IP 地址
|
|
69
|
+
if (!isValidIP(ip)) {
|
|
70
|
+
console.error(chalk.red('✗ 无效的 IP 地址:'), ip);
|
|
71
|
+
console.log(chalk.yellow('提示: IP 地址格式应为 xxx.xxx.xxx.xxx'));
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 验证端口号
|
|
76
|
+
if (!isValidPort(port)) {
|
|
77
|
+
console.error(chalk.red('✗ 无效的端口号:'), port);
|
|
78
|
+
console.log(chalk.yellow('提示: 端口号范围应为 1-65535'));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(chalk.blue('正在添加端口转发规则...'));
|
|
83
|
+
console.log(chalk.gray(` 名称: ${name}`));
|
|
84
|
+
console.log(chalk.gray(` 内部主机: ${ip}`));
|
|
85
|
+
console.log(chalk.gray(` 端口: ${port} (外部) -> ${port} (内部)`));
|
|
86
|
+
console.log(chalk.gray(` 协议: TCP/UDP`));
|
|
87
|
+
|
|
88
|
+
// 构建配置对象
|
|
89
|
+
const hostConfig = {
|
|
90
|
+
Name: name,
|
|
91
|
+
InternalHost: ip,
|
|
92
|
+
MinExtPort: port,
|
|
93
|
+
MaxExtPort: port,
|
|
94
|
+
MinIntPort: port,
|
|
95
|
+
MaxIntPort: port,
|
|
96
|
+
Protocol: '2', // TCP/UDP
|
|
97
|
+
Enable: '1', // 启用
|
|
98
|
+
WANCViewName: 'IGD.WD1.WCD2.WCPPP1',
|
|
99
|
+
WANCName: '',
|
|
100
|
+
Description: 'NULL',
|
|
101
|
+
LeaseDuration: 'NULL',
|
|
102
|
+
PortMappCreator: 'NULL',
|
|
103
|
+
MinRemoteHost: '0.0.0.0',
|
|
104
|
+
MaxRemoteHost: '0.0.0.0',
|
|
105
|
+
InternalMacHost: 'NULL',
|
|
106
|
+
MacEnable: '0'
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// 提交到光猫
|
|
110
|
+
const result = await addHost(hostConfig);
|
|
111
|
+
|
|
112
|
+
if (result.success) {
|
|
113
|
+
console.log(chalk.green('\n✓ 端口转发规则添加成功!'));
|
|
114
|
+
|
|
115
|
+
// 更新本地缓存
|
|
116
|
+
if (result.html) {
|
|
117
|
+
// 确保 .cache 目录存在
|
|
118
|
+
if (!fs.existsSync(CACHE_DIR)) {
|
|
119
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
fs.writeFileSync(CACHE_HTML, result.html);
|
|
123
|
+
const configs = loadConfigFromFile(CACHE_HTML);
|
|
124
|
+
saveConfigToJson(configs, DATA_FILE);
|
|
125
|
+
|
|
126
|
+
console.log(chalk.gray(`配置已同步到本地缓存`));
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
console.error(chalk.red('\n✗ 添加失败:'), result.error || '未知错误');
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
} catch (error) {
|
|
134
|
+
console.error(chalk.red('✗ 错误:'), error.message);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* router del 命令 - 根据索引删除端口转发规则
|
|
141
|
+
*/
|
|
142
|
+
async function deleteRouter(index) {
|
|
143
|
+
try {
|
|
144
|
+
// 验证索引是否为有效数字
|
|
145
|
+
const indexNum = parseInt(index, 10);
|
|
146
|
+
if (isNaN(indexNum) || indexNum < 0) {
|
|
147
|
+
console.error(chalk.red('✗ 无效的索引号:'), index);
|
|
148
|
+
console.log(chalk.yellow('提示: 索引号必须是非负整数'));
|
|
149
|
+
console.log(chalk.gray('使用'), chalk.cyan('router list'), chalk.gray('查看所有配置的索引号'));
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log(chalk.blue(`正在删除索引为 ${indexNum} 的配置...`));
|
|
154
|
+
|
|
155
|
+
// 执行删除
|
|
156
|
+
const result = await deleteHost(indexNum);
|
|
157
|
+
|
|
158
|
+
if (result.success) {
|
|
159
|
+
console.log(chalk.green('\n✓ 端口转发规则删除成功!'));
|
|
160
|
+
|
|
161
|
+
// 更新本地缓存
|
|
162
|
+
if (result.html) {
|
|
163
|
+
// 确保 .cache 目录存在
|
|
164
|
+
if (!fs.existsSync(CACHE_DIR)) {
|
|
165
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
fs.writeFileSync(CACHE_HTML, result.html);
|
|
169
|
+
const updatedConfigs = loadConfigFromFile(CACHE_HTML);
|
|
170
|
+
saveConfigToJson(updatedConfigs, DATA_FILE);
|
|
171
|
+
|
|
172
|
+
console.log(chalk.gray(`配置已同步到本地缓存`));
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
console.error(chalk.red('\n✗ 删除失败:'), result.error || '未知错误');
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error(chalk.red('✗ 错误:'), error.message);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* router list 命令 - 列出所有虚拟主机配置
|
|
187
|
+
*/
|
|
188
|
+
async function listRouters(options) {
|
|
189
|
+
try {
|
|
190
|
+
// console.log(chalk.blue('正在从光猫获取配置...'));
|
|
191
|
+
|
|
192
|
+
// 从光猫刷新配置
|
|
193
|
+
const refreshResult = await refreshFromModem();
|
|
194
|
+
|
|
195
|
+
if (!refreshResult.success) {
|
|
196
|
+
console.error(chalk.red('✗ 获取配置失败:'), refreshResult.error);
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 确保 .cache 目录存在
|
|
201
|
+
if (!fs.existsSync(CACHE_DIR)) {
|
|
202
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 保存 HTML 到缓存
|
|
206
|
+
fs.writeFileSync(CACHE_HTML, refreshResult.html);
|
|
207
|
+
|
|
208
|
+
// 解析配置
|
|
209
|
+
const configs = loadConfigFromFile(CACHE_HTML);
|
|
210
|
+
|
|
211
|
+
// 保存到 JSON
|
|
212
|
+
saveConfigToJson(configs, DATA_FILE);
|
|
213
|
+
|
|
214
|
+
if (configs.length === 0) {
|
|
215
|
+
console.log(chalk.yellow('没有找到任何虚拟主机配置'));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// console.log(chalk.green(`\n✓ 成功获取 ${configs.length} 个虚拟主机配置\n`));
|
|
220
|
+
|
|
221
|
+
// 创建表格
|
|
222
|
+
const table = new Table({
|
|
223
|
+
head: [
|
|
224
|
+
chalk.cyan('索引'),
|
|
225
|
+
chalk.cyan('名称'),
|
|
226
|
+
chalk.cyan('状态'),
|
|
227
|
+
chalk.cyan('协议'),
|
|
228
|
+
chalk.cyan('外部端口'),
|
|
229
|
+
chalk.cyan('内部主机'),
|
|
230
|
+
chalk.cyan('内部端口'),
|
|
231
|
+
chalk.cyan('WAN连接')
|
|
232
|
+
],
|
|
233
|
+
colWidths: [6, 20, 10, 10, 12, 16, 12, 25]
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// 添加数据行
|
|
237
|
+
configs.forEach((config) => {
|
|
238
|
+
const extPort = config.MinExtPort === config.MaxExtPort
|
|
239
|
+
? config.MinExtPort
|
|
240
|
+
: `${config.MinExtPort}-${config.MaxExtPort}`;
|
|
241
|
+
|
|
242
|
+
const intPort = config.MinIntPort === config.MaxIntPort
|
|
243
|
+
? config.MinIntPort
|
|
244
|
+
: `${config.MinIntPort}-${config.MaxIntPort}`;
|
|
245
|
+
|
|
246
|
+
table.push([
|
|
247
|
+
config.index,
|
|
248
|
+
config.Name || '-',
|
|
249
|
+
formatEnable(config.Enable),
|
|
250
|
+
formatProtocol(config.Protocol),
|
|
251
|
+
extPort,
|
|
252
|
+
config.InternalHost || '-',
|
|
253
|
+
intPort,
|
|
254
|
+
config.WANCName || '-'
|
|
255
|
+
]);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
console.log(table.toString());
|
|
259
|
+
|
|
260
|
+
// 显示详细信息选项
|
|
261
|
+
if (options.verbose) {
|
|
262
|
+
console.log(chalk.gray('\n详细信息:'));
|
|
263
|
+
configs.forEach((config, idx) => {
|
|
264
|
+
console.log(chalk.gray(`\n[${idx + 1}] ${config.Name}`));
|
|
265
|
+
console.log(chalk.gray(` ViewName: ${config.ViewName}`));
|
|
266
|
+
console.log(chalk.gray(` WANCViewName: ${config.WANCViewName}`));
|
|
267
|
+
console.log(chalk.gray(` Description: ${config.Description || '无'}`));
|
|
268
|
+
console.log(chalk.gray(` RemoteHost: ${config.MinRemoteHost}-${config.MaxRemoteHost}`));
|
|
269
|
+
console.log(chalk.gray(` MacEnable: ${config.MacEnable}`));
|
|
270
|
+
console.log(chalk.gray(` InternalMacHost: ${config.InternalMacHost}`));
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// console.log(chalk.gray(`\n配置已保存到: ${DATA_FILE}`));
|
|
275
|
+
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error(chalk.red('✗ 错误:'), error.message);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// 配置 CLI
|
|
283
|
+
program
|
|
284
|
+
.name('router')
|
|
285
|
+
.description('虚拟主机管理命令行工具')
|
|
286
|
+
.version('1.0.0');
|
|
287
|
+
|
|
288
|
+
// router list 命令
|
|
289
|
+
program
|
|
290
|
+
.command('list')
|
|
291
|
+
.description('列出所有虚拟主机配置')
|
|
292
|
+
.option('-v, --verbose', '显示详细信息')
|
|
293
|
+
.action(listRouters);
|
|
294
|
+
|
|
295
|
+
// router add 命令
|
|
296
|
+
program
|
|
297
|
+
.command('add <ip> <port> <name>')
|
|
298
|
+
.description('快速添加端口转发规则 (外部端口和内部端口一致)')
|
|
299
|
+
.action(addRouter);
|
|
300
|
+
|
|
301
|
+
// router del 命令
|
|
302
|
+
program
|
|
303
|
+
.command('del <index>')
|
|
304
|
+
.description('根据索引删除端口转发规则')
|
|
305
|
+
.action(deleteRouter);
|
|
306
|
+
|
|
307
|
+
// 解析命令行参数
|
|
308
|
+
program.parse(process.argv);
|
|
309
|
+
|
|
310
|
+
// 如果没有提供任何命令,显示帮助信息
|
|
311
|
+
if (!process.argv.slice(2).length) {
|
|
312
|
+
program.outputHelp();
|
|
313
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Traceback (most recent call last):
|
|
2
|
+
File "<string>", line 1, in <module>
|
|
3
|
+
import sys; sys.stdout.reconfigure(encoding='utf-8'); exec(open('search.py').read())
|
|
4
|
+
~~~~~~~~~~~~~~~~~~~~~~^^
|
|
5
|
+
UnicodeDecodeError: 'gbk' codec can't decode byte 0x85 in position 3913: illegal multibyte sequence
|