@chenpu17/tcpmapping 2.0.0 → 2.1.0
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/README.md +148 -66
- package/bin/tcpmapping.js +131 -34
- package/package.json +2 -3
- package/public/dashboard.html +388 -125
- package/public/login.html +157 -67
- package/server.js +83 -20
- package/setup-password.js +19 -2
- package/config.json +0 -46
package/public/login.html
CHANGED
|
@@ -14,19 +14,32 @@
|
|
|
14
14
|
body {
|
|
15
15
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
16
16
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
17
|
-
height: 100vh;
|
|
17
|
+
min-height: 100vh;
|
|
18
18
|
display: flex;
|
|
19
19
|
align-items: center;
|
|
20
20
|
justify-content: center;
|
|
21
|
+
padding: 1rem;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
.login-container {
|
|
24
25
|
background: white;
|
|
25
|
-
padding:
|
|
26
|
-
border-radius:
|
|
27
|
-
box-shadow: 0
|
|
26
|
+
padding: 2.5rem;
|
|
27
|
+
border-radius: 20px;
|
|
28
|
+
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
|
|
28
29
|
width: 100%;
|
|
29
|
-
max-width:
|
|
30
|
+
max-width: 420px;
|
|
31
|
+
animation: slideUp 0.5s ease;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@keyframes slideUp {
|
|
35
|
+
from {
|
|
36
|
+
opacity: 0;
|
|
37
|
+
transform: translateY(30px);
|
|
38
|
+
}
|
|
39
|
+
to {
|
|
40
|
+
opacity: 1;
|
|
41
|
+
transform: translateY(0);
|
|
42
|
+
}
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
.login-header {
|
|
@@ -34,14 +47,33 @@
|
|
|
34
47
|
margin-bottom: 2rem;
|
|
35
48
|
}
|
|
36
49
|
|
|
50
|
+
.login-header .logo {
|
|
51
|
+
width: 70px;
|
|
52
|
+
height: 70px;
|
|
53
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
54
|
+
border-radius: 20px;
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
margin: 0 auto 1.5rem;
|
|
59
|
+
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.login-header .logo svg {
|
|
63
|
+
width: 36px;
|
|
64
|
+
height: 36px;
|
|
65
|
+
color: white;
|
|
66
|
+
}
|
|
67
|
+
|
|
37
68
|
.login-header h1 {
|
|
38
|
-
color: #
|
|
69
|
+
color: #2d3436;
|
|
39
70
|
font-size: 24px;
|
|
71
|
+
font-weight: 700;
|
|
40
72
|
margin-bottom: 0.5rem;
|
|
41
73
|
}
|
|
42
74
|
|
|
43
75
|
.login-header p {
|
|
44
|
-
color: #
|
|
76
|
+
color: #636e72;
|
|
45
77
|
font-size: 14px;
|
|
46
78
|
}
|
|
47
79
|
|
|
@@ -52,125 +84,176 @@
|
|
|
52
84
|
.form-group label {
|
|
53
85
|
display: block;
|
|
54
86
|
margin-bottom: 0.5rem;
|
|
55
|
-
color: #
|
|
56
|
-
font-weight:
|
|
87
|
+
color: #2d3436;
|
|
88
|
+
font-weight: 600;
|
|
89
|
+
font-size: 14px;
|
|
57
90
|
}
|
|
58
91
|
|
|
59
92
|
.form-group input {
|
|
60
93
|
width: 100%;
|
|
61
|
-
padding: 0.
|
|
62
|
-
border:
|
|
63
|
-
border-radius:
|
|
64
|
-
font-size:
|
|
65
|
-
transition:
|
|
94
|
+
padding: 0.9rem 1rem;
|
|
95
|
+
border: 2px solid #e9ecef;
|
|
96
|
+
border-radius: 12px;
|
|
97
|
+
font-size: 15px;
|
|
98
|
+
transition: all 0.3s ease;
|
|
66
99
|
}
|
|
67
100
|
|
|
68
101
|
.form-group input:focus {
|
|
69
102
|
outline: none;
|
|
70
103
|
border-color: #667eea;
|
|
71
|
-
box-shadow: 0 0 0
|
|
104
|
+
box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.15);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.form-group input::placeholder {
|
|
108
|
+
color: #b2bec3;
|
|
72
109
|
}
|
|
73
110
|
|
|
74
111
|
.login-btn {
|
|
75
112
|
width: 100%;
|
|
76
|
-
padding: 0.
|
|
113
|
+
padding: 0.95rem;
|
|
77
114
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
78
115
|
color: white;
|
|
79
116
|
border: none;
|
|
80
|
-
border-radius:
|
|
117
|
+
border-radius: 12px;
|
|
81
118
|
font-size: 16px;
|
|
82
119
|
font-weight: 600;
|
|
83
120
|
cursor: pointer;
|
|
84
|
-
transition:
|
|
121
|
+
transition: all 0.3s ease;
|
|
122
|
+
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
|
|
85
123
|
}
|
|
86
124
|
|
|
87
125
|
.login-btn:hover {
|
|
88
|
-
transform: translateY(-
|
|
126
|
+
transform: translateY(-3px);
|
|
127
|
+
box-shadow: 0 15px 35px rgba(102, 126, 234, 0.5);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.login-btn:active {
|
|
131
|
+
transform: translateY(-1px);
|
|
89
132
|
}
|
|
90
133
|
|
|
91
134
|
.login-btn:disabled {
|
|
92
|
-
opacity: 0.
|
|
135
|
+
opacity: 0.7;
|
|
93
136
|
cursor: not-allowed;
|
|
94
137
|
transform: none;
|
|
138
|
+
box-shadow: none;
|
|
95
139
|
}
|
|
96
140
|
|
|
97
141
|
.error-message {
|
|
98
|
-
color: #
|
|
142
|
+
color: #ee5a5a;
|
|
99
143
|
font-size: 14px;
|
|
100
|
-
margin-top:
|
|
144
|
+
margin-top: 1rem;
|
|
145
|
+
padding: 0.85rem 1rem;
|
|
146
|
+
background: #fff5f5;
|
|
147
|
+
border-radius: 10px;
|
|
101
148
|
display: none;
|
|
149
|
+
text-align: center;
|
|
102
150
|
}
|
|
103
151
|
|
|
104
152
|
.success-message {
|
|
105
|
-
color: #
|
|
153
|
+
color: #2ed573;
|
|
106
154
|
font-size: 14px;
|
|
107
|
-
margin-top:
|
|
155
|
+
margin-top: 1rem;
|
|
156
|
+
padding: 0.85rem 1rem;
|
|
157
|
+
background: #f0fff4;
|
|
158
|
+
border-radius: 10px;
|
|
108
159
|
display: none;
|
|
160
|
+
text-align: center;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.help-info {
|
|
164
|
+
background: linear-gradient(135deg, #f8f9fa 0%, #f1f3f4 100%);
|
|
165
|
+
border-radius: 12px;
|
|
166
|
+
padding: 1rem 1.25rem;
|
|
167
|
+
margin-top: 1.5rem;
|
|
168
|
+
font-size: 13px;
|
|
169
|
+
color: #636e72;
|
|
170
|
+
line-height: 1.6;
|
|
109
171
|
}
|
|
110
172
|
|
|
111
|
-
.
|
|
112
|
-
background: #
|
|
113
|
-
|
|
173
|
+
.help-info code {
|
|
174
|
+
background: #e9ecef;
|
|
175
|
+
padding: 0.2rem 0.5rem;
|
|
114
176
|
border-radius: 5px;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
color: #666;
|
|
177
|
+
font-family: 'SFMono-Regular', Consolas, monospace;
|
|
178
|
+
font-size: 12px;
|
|
179
|
+
color: #764ba2;
|
|
119
180
|
}
|
|
120
181
|
|
|
121
|
-
.
|
|
122
|
-
|
|
182
|
+
.footer {
|
|
183
|
+
text-align: center;
|
|
184
|
+
margin-top: 2rem;
|
|
185
|
+
color: rgba(255,255,255,0.7);
|
|
186
|
+
font-size: 13px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.footer a {
|
|
190
|
+
color: rgba(255,255,255,0.9);
|
|
191
|
+
text-decoration: none;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.footer a:hover {
|
|
195
|
+
text-decoration: underline;
|
|
123
196
|
}
|
|
124
197
|
</style>
|
|
125
198
|
</head>
|
|
126
199
|
<body>
|
|
127
|
-
<div
|
|
128
|
-
<div class="login-
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
<
|
|
136
|
-
<
|
|
200
|
+
<div>
|
|
201
|
+
<div class="login-container">
|
|
202
|
+
<div class="login-header">
|
|
203
|
+
<div class="logo">
|
|
204
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
205
|
+
<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
|
|
206
|
+
</svg>
|
|
207
|
+
</div>
|
|
208
|
+
<h1>TCP转发服务器</h1>
|
|
209
|
+
<p>管理界面登录</p>
|
|
137
210
|
</div>
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
<
|
|
141
|
-
|
|
211
|
+
|
|
212
|
+
<form id="loginForm">
|
|
213
|
+
<div class="form-group">
|
|
214
|
+
<label for="username">用户名</label>
|
|
215
|
+
<input type="text" id="username" name="username" placeholder="请输入用户名" required autocomplete="username">
|
|
216
|
+
</div>
|
|
217
|
+
|
|
218
|
+
<div class="form-group">
|
|
219
|
+
<label for="password">密码</label>
|
|
220
|
+
<input type="password" id="password" name="password" placeholder="请输入密码" required autocomplete="current-password">
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<button type="submit" class="login-btn" id="loginBtn">登录</button>
|
|
224
|
+
|
|
225
|
+
<div class="error-message" id="errorMessage"></div>
|
|
226
|
+
<div class="success-message" id="successMessage"></div>
|
|
227
|
+
</form>
|
|
228
|
+
|
|
229
|
+
<div class="help-info">
|
|
230
|
+
忘记密码?运行 <code>tcpmapping setup-password</code> 或 <code>npm run reset-password</code> 重置
|
|
142
231
|
</div>
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
<
|
|
147
|
-
<div class="success-message" id="successMessage"></div>
|
|
148
|
-
</form>
|
|
149
|
-
|
|
150
|
-
<div class="default-info">
|
|
151
|
-
<strong>提示:</strong><br>
|
|
152
|
-
如忘记密码,请运行 <code>npm run reset-password</code> 重置
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<div class="footer">
|
|
235
|
+
<a href="https://github.com/chenpu17/TcpMapping" target="_blank">TcpMapping</a> - TCP端口转发服务器
|
|
153
236
|
</div>
|
|
154
237
|
</div>
|
|
155
238
|
|
|
156
239
|
<script>
|
|
157
240
|
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
158
241
|
e.preventDefault();
|
|
159
|
-
|
|
242
|
+
|
|
160
243
|
const loginBtn = document.getElementById('loginBtn');
|
|
161
244
|
const errorMessage = document.getElementById('errorMessage');
|
|
162
245
|
const successMessage = document.getElementById('successMessage');
|
|
163
246
|
const username = document.getElementById('username').value;
|
|
164
247
|
const password = document.getElementById('password').value;
|
|
165
|
-
|
|
248
|
+
|
|
166
249
|
// 重置消息
|
|
167
250
|
errorMessage.style.display = 'none';
|
|
168
251
|
successMessage.style.display = 'none';
|
|
169
|
-
|
|
252
|
+
|
|
170
253
|
// 禁用按钮
|
|
171
254
|
loginBtn.disabled = true;
|
|
172
255
|
loginBtn.textContent = '登录中...';
|
|
173
|
-
|
|
256
|
+
|
|
174
257
|
try {
|
|
175
258
|
const response = await fetch('/api/login', {
|
|
176
259
|
method: 'POST',
|
|
@@ -179,16 +262,16 @@
|
|
|
179
262
|
},
|
|
180
263
|
body: JSON.stringify({ username, password })
|
|
181
264
|
});
|
|
182
|
-
|
|
265
|
+
|
|
183
266
|
const data = await response.json();
|
|
184
|
-
|
|
267
|
+
|
|
185
268
|
if (data.success) {
|
|
186
|
-
successMessage.textContent =
|
|
269
|
+
successMessage.textContent = '登录成功,正在跳转...';
|
|
187
270
|
successMessage.style.display = 'block';
|
|
188
|
-
|
|
271
|
+
|
|
189
272
|
setTimeout(() => {
|
|
190
273
|
window.location.href = '/dashboard';
|
|
191
|
-
},
|
|
274
|
+
}, 800);
|
|
192
275
|
} else {
|
|
193
276
|
errorMessage.textContent = data.message;
|
|
194
277
|
errorMessage.style.display = 'block';
|
|
@@ -202,6 +285,13 @@
|
|
|
202
285
|
loginBtn.textContent = '登录';
|
|
203
286
|
}
|
|
204
287
|
});
|
|
288
|
+
|
|
289
|
+
// 回车提交
|
|
290
|
+
document.addEventListener('keypress', (e) => {
|
|
291
|
+
if (e.key === 'Enter') {
|
|
292
|
+
document.getElementById('loginForm').dispatchEvent(new Event('submit'));
|
|
293
|
+
}
|
|
294
|
+
});
|
|
205
295
|
</script>
|
|
206
296
|
</body>
|
|
207
|
-
</html>
|
|
297
|
+
</html>
|
package/server.js
CHANGED
|
@@ -1,11 +1,59 @@
|
|
|
1
1
|
const net = require('net');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
4
5
|
const express = require('express');
|
|
5
6
|
const session = require('express-session');
|
|
6
7
|
const bcrypt = require('bcryptjs');
|
|
7
8
|
const bodyParser = require('body-parser');
|
|
8
9
|
|
|
10
|
+
// 数据目录 - 用于存储用户配置(持久化)
|
|
11
|
+
const DATA_DIR = path.join(os.homedir(), '.tcpmapping');
|
|
12
|
+
|
|
13
|
+
// 获取配置文件路径(按优先级搜索)
|
|
14
|
+
function getConfigPath(filename) {
|
|
15
|
+
// 优先级1: 当前工作目录
|
|
16
|
+
const cwdPath = path.join(process.cwd(), filename);
|
|
17
|
+
if (fs.existsSync(cwdPath)) {
|
|
18
|
+
return cwdPath;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 优先级2: 用户数据目录 (~/.tcpmapping/)
|
|
22
|
+
const dataPath = path.join(DATA_DIR, filename);
|
|
23
|
+
if (fs.existsSync(dataPath)) {
|
|
24
|
+
return dataPath;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// 优先级3: 包安装目录(仅作为模板)
|
|
28
|
+
const pkgPath = path.join(__dirname, filename);
|
|
29
|
+
if (fs.existsSync(pkgPath)) {
|
|
30
|
+
return pkgPath;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 获取配置保存路径
|
|
37
|
+
function getConfigSavePath(filename) {
|
|
38
|
+
// 如果当前工作目录有配置文件,保存到当前目录
|
|
39
|
+
const cwdPath = path.join(process.cwd(), filename);
|
|
40
|
+
if (fs.existsSync(cwdPath)) {
|
|
41
|
+
return cwdPath;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 否则保存到用户数据目录
|
|
45
|
+
ensureDataDir();
|
|
46
|
+
return path.join(DATA_DIR, filename);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 确保数据目录存在
|
|
50
|
+
function ensureDataDir() {
|
|
51
|
+
if (!fs.existsSync(DATA_DIR)) {
|
|
52
|
+
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
53
|
+
console.log(`创建配置目录: ${DATA_DIR}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
9
57
|
// 全局变量
|
|
10
58
|
let config = {};
|
|
11
59
|
const servers = new Map(); // 存储所有TCP转发服务器实例
|
|
@@ -21,12 +69,16 @@ const loginAttempts = new Map();
|
|
|
21
69
|
// 加载认证配置
|
|
22
70
|
function loadAuthConfig() {
|
|
23
71
|
try {
|
|
24
|
-
const authConfigPath =
|
|
72
|
+
const authConfigPath = getConfigPath('auth-config.json');
|
|
73
|
+
if (!authConfigPath) {
|
|
74
|
+
throw new Error('认证配置文件不存在');
|
|
75
|
+
}
|
|
25
76
|
const authConfigData = fs.readFileSync(authConfigPath, 'utf8');
|
|
77
|
+
console.log(`加载认证配置: ${authConfigPath}`);
|
|
26
78
|
return JSON.parse(authConfigData);
|
|
27
79
|
} catch (error) {
|
|
28
80
|
console.error('警告: 未找到认证配置文件,使用默认配置');
|
|
29
|
-
console.error('请运行 "
|
|
81
|
+
console.error('请运行 "tcpmapping setup-password" 或 "npm run setup-password" 来设置安全密码');
|
|
30
82
|
|
|
31
83
|
// 返回默认配置(仅用于向后兼容)
|
|
32
84
|
return {
|
|
@@ -125,15 +177,21 @@ const LOG_LEVELS = {
|
|
|
125
177
|
// 读取配置文件
|
|
126
178
|
function loadConfig() {
|
|
127
179
|
try {
|
|
128
|
-
const configPath =
|
|
180
|
+
const configPath = getConfigPath('config.json');
|
|
181
|
+
if (!configPath) {
|
|
182
|
+
console.log('未找到配置文件,使用默认配置');
|
|
183
|
+
console.log('运行 "tcpmapping init" 创建配置文件');
|
|
184
|
+
return getDefaultConfig();
|
|
185
|
+
}
|
|
129
186
|
const configData = fs.readFileSync(configPath, 'utf8');
|
|
130
187
|
const loadedConfig = JSON.parse(configData);
|
|
131
|
-
|
|
188
|
+
console.log(`加载配置文件: ${configPath}`);
|
|
189
|
+
|
|
132
190
|
// 验证配置
|
|
133
191
|
if (!loadedConfig.mappings || !Array.isArray(loadedConfig.mappings)) {
|
|
134
192
|
loadedConfig.mappings = [];
|
|
135
193
|
}
|
|
136
|
-
|
|
194
|
+
|
|
137
195
|
// 添加默认WebUI配置
|
|
138
196
|
if (!loadedConfig.webui) {
|
|
139
197
|
loadedConfig.webui = {
|
|
@@ -142,32 +200,37 @@ function loadConfig() {
|
|
|
142
200
|
host: '0.0.0.0'
|
|
143
201
|
};
|
|
144
202
|
}
|
|
145
|
-
|
|
203
|
+
|
|
146
204
|
return loadedConfig;
|
|
147
205
|
} catch (error) {
|
|
148
206
|
console.error('读取配置文件失败:', error.message);
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
mappings: [],
|
|
152
|
-
webui: {
|
|
153
|
-
enabled: true,
|
|
154
|
-
port: 9999,
|
|
155
|
-
host: '0.0.0.0'
|
|
156
|
-
},
|
|
157
|
-
logging: {
|
|
158
|
-
enabled: true,
|
|
159
|
-
level: 'info'
|
|
160
|
-
}
|
|
161
|
-
};
|
|
207
|
+
return getDefaultConfig();
|
|
162
208
|
}
|
|
163
209
|
}
|
|
164
210
|
|
|
211
|
+
// 获取默认配置
|
|
212
|
+
function getDefaultConfig() {
|
|
213
|
+
return {
|
|
214
|
+
mappings: [],
|
|
215
|
+
webui: {
|
|
216
|
+
enabled: true,
|
|
217
|
+
port: 9999,
|
|
218
|
+
host: '0.0.0.0'
|
|
219
|
+
},
|
|
220
|
+
logging: {
|
|
221
|
+
enabled: true,
|
|
222
|
+
level: 'info'
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
165
227
|
// 保存配置文件
|
|
166
228
|
function saveConfig(newConfig) {
|
|
167
229
|
try {
|
|
168
|
-
const configPath =
|
|
230
|
+
const configPath = getConfigSavePath('config.json');
|
|
169
231
|
fs.writeFileSync(configPath, JSON.stringify(newConfig, null, 2));
|
|
170
232
|
config = newConfig;
|
|
233
|
+
console.log(`配置已保存: ${configPath}`);
|
|
171
234
|
return true;
|
|
172
235
|
} catch (error) {
|
|
173
236
|
console.error('保存配置文件失败:', error.message);
|
package/setup-password.js
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const os = require('os');
|
|
3
4
|
const bcrypt = require('bcryptjs');
|
|
4
5
|
const readline = require('readline');
|
|
5
6
|
|
|
7
|
+
// 获取配置保存目录
|
|
8
|
+
function getConfigDir() {
|
|
9
|
+
// 优先使用环境变量指定的目录
|
|
10
|
+
if (process.env.TCPMAPPING_DATA_DIR) {
|
|
11
|
+
return process.env.TCPMAPPING_DATA_DIR;
|
|
12
|
+
}
|
|
13
|
+
// 其次使用当前工作目录
|
|
14
|
+
return process.cwd();
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
// 创建readline接口
|
|
7
18
|
const rl = readline.createInterface({
|
|
8
19
|
input: process.stdin,
|
|
@@ -81,7 +92,7 @@ function getPassword(prompt) {
|
|
|
81
92
|
// 读取现有的认证配置
|
|
82
93
|
function loadAuthConfig() {
|
|
83
94
|
try {
|
|
84
|
-
const configPath = path.join(
|
|
95
|
+
const configPath = path.join(getConfigDir(), 'auth-config.json');
|
|
85
96
|
const configData = fs.readFileSync(configPath, 'utf8');
|
|
86
97
|
return JSON.parse(configData);
|
|
87
98
|
} catch (error) {
|
|
@@ -107,8 +118,14 @@ function loadAuthConfig() {
|
|
|
107
118
|
|
|
108
119
|
// 保存认证配置
|
|
109
120
|
function saveAuthConfig(config) {
|
|
110
|
-
const
|
|
121
|
+
const configDir = getConfigDir();
|
|
122
|
+
// 确保目录存在
|
|
123
|
+
if (!fs.existsSync(configDir)) {
|
|
124
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
125
|
+
}
|
|
126
|
+
const configPath = path.join(configDir, 'auth-config.json');
|
|
111
127
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
128
|
+
console.log(`配置已保存到: ${configPath}`);
|
|
112
129
|
}
|
|
113
130
|
|
|
114
131
|
// 主要设置流程
|
package/config.json
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"mappings": [
|
|
3
|
-
{
|
|
4
|
-
"name": "Dify",
|
|
5
|
-
"listen": {
|
|
6
|
-
"host": "0.0.0.0",
|
|
7
|
-
"port": 5588
|
|
8
|
-
},
|
|
9
|
-
"target": {
|
|
10
|
-
"host": "113.45.34.202",
|
|
11
|
-
"port": 5588
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"name": "语音助手",
|
|
16
|
-
"listen": {
|
|
17
|
-
"host": "0.0.0.0",
|
|
18
|
-
"port": 3443
|
|
19
|
-
},
|
|
20
|
-
"target": {
|
|
21
|
-
"host": "115.120.49.208",
|
|
22
|
-
"port": 443
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"name": "语音助手",
|
|
27
|
-
"listen": {
|
|
28
|
-
"host": "0.0.0.0",
|
|
29
|
-
"port": 443
|
|
30
|
-
},
|
|
31
|
-
"target": {
|
|
32
|
-
"host": "115.120.49.208",
|
|
33
|
-
"port": 443
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
],
|
|
37
|
-
"webui": {
|
|
38
|
-
"enabled": true,
|
|
39
|
-
"port": 9999,
|
|
40
|
-
"host": "0.0.0.0"
|
|
41
|
-
},
|
|
42
|
-
"logging": {
|
|
43
|
-
"enabled": true,
|
|
44
|
-
"level": "info"
|
|
45
|
-
}
|
|
46
|
-
}
|