vk-ssl-auto-deploy 0.8.5 → 0.8.6
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/package.json +1 -1
- package/routes/admin.js +99 -0
- package/views/admin.ejs +122 -1
package/package.json
CHANGED
package/routes/admin.js
CHANGED
|
@@ -410,4 +410,103 @@ router.get('/api/cert/download/:fileName', verifyPassword, (req, res) => {
|
|
|
410
410
|
}
|
|
411
411
|
});
|
|
412
412
|
|
|
413
|
+
// 检查更新
|
|
414
|
+
router.post('/check-update', verifyPassword, async (req, res) => {
|
|
415
|
+
try {
|
|
416
|
+
const https = require('https');
|
|
417
|
+
const currentVersion = require('../package.json').version;
|
|
418
|
+
|
|
419
|
+
// 获取远程 package.json
|
|
420
|
+
const remoteUrl = 'https://gitee.com/vk1688/vk-ssl-auto-deploy/raw/master/package.json';
|
|
421
|
+
|
|
422
|
+
https.get(remoteUrl, (response) => {
|
|
423
|
+
let data = '';
|
|
424
|
+
|
|
425
|
+
response.on('data', (chunk) => {
|
|
426
|
+
data += chunk;
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
response.on('end', () => {
|
|
430
|
+
try {
|
|
431
|
+
const remotePackage = JSON.parse(data);
|
|
432
|
+
const remoteVersion = remotePackage.version;
|
|
433
|
+
|
|
434
|
+
const hasUpdate = currentVersion !== remoteVersion;
|
|
435
|
+
|
|
436
|
+
res.json({
|
|
437
|
+
code: 0,
|
|
438
|
+
msg: hasUpdate ? '发现新版本' : '已是最新版本',
|
|
439
|
+
data: {
|
|
440
|
+
currentVersion,
|
|
441
|
+
remoteVersion,
|
|
442
|
+
hasUpdate
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
} catch (error) {
|
|
446
|
+
res.status(500).json({
|
|
447
|
+
code: 500,
|
|
448
|
+
msg: '解析远程版本信息失败: ' + error.message,
|
|
449
|
+
data: null
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}).on('error', (error) => {
|
|
454
|
+
res.status(500).json({
|
|
455
|
+
code: 500,
|
|
456
|
+
msg: '获取远程版本信息失败: ' + error.message,
|
|
457
|
+
data: null
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
} catch (error) {
|
|
461
|
+
res.status(500).json({
|
|
462
|
+
code: 500,
|
|
463
|
+
msg: '检查更新失败: ' + error.message,
|
|
464
|
+
data: null
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
// 执行更新
|
|
470
|
+
router.post('/execute-update', verifyPassword, async (req, res) => {
|
|
471
|
+
try {
|
|
472
|
+
const platform = process.platform;
|
|
473
|
+
let command;
|
|
474
|
+
|
|
475
|
+
if (platform === 'win32') {
|
|
476
|
+
// Windows 系统
|
|
477
|
+
command = 'powershell -c "iwr -useb https://gitee.com/vk1688/vk-ssl-auto-deploy/raw/master/install.ps1 | iex"';
|
|
478
|
+
} else {
|
|
479
|
+
// Linux/Unix 系统
|
|
480
|
+
command = 'curl -fsSL https://gitee.com/vk1688/vk-ssl-auto-deploy/raw/master/install.sh | sudo bash';
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// 异步执行更新命令
|
|
484
|
+
exec(command, (error, stdout, stderr) => {
|
|
485
|
+
if (error) {
|
|
486
|
+
console.error('更新失败:', error);
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
console.log('更新输出:', stdout);
|
|
490
|
+
if (stderr) {
|
|
491
|
+
console.error('更新错误:', stderr);
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
res.json({
|
|
496
|
+
code: 0,
|
|
497
|
+
msg: '更新命令已执行,程序将在更新完成后自动重启',
|
|
498
|
+
data: {
|
|
499
|
+
platform,
|
|
500
|
+
command
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
} catch (error) {
|
|
504
|
+
res.status(500).json({
|
|
505
|
+
code: 500,
|
|
506
|
+
msg: '执行更新失败: ' + error.message,
|
|
507
|
+
data: null
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
|
|
413
512
|
module.exports = router;
|
package/views/admin.ejs
CHANGED
|
@@ -363,7 +363,7 @@
|
|
|
363
363
|
/* 操作面板按钮组 */
|
|
364
364
|
.operation-buttons {
|
|
365
365
|
display: grid;
|
|
366
|
-
grid-template-columns: 1fr 1fr;
|
|
366
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
367
367
|
gap: 15px;
|
|
368
368
|
margin-top: 20px;
|
|
369
369
|
}
|
|
@@ -372,6 +372,31 @@
|
|
|
372
372
|
width: 100%;
|
|
373
373
|
height: 60px;
|
|
374
374
|
font-size: 1em;
|
|
375
|
+
position: relative;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* 红点提示 */
|
|
379
|
+
.update-badge {
|
|
380
|
+
position: absolute;
|
|
381
|
+
top: 8px;
|
|
382
|
+
right: 8px;
|
|
383
|
+
width: 10px;
|
|
384
|
+
height: 10px;
|
|
385
|
+
background: #f44336;
|
|
386
|
+
border-radius: 50%;
|
|
387
|
+
box-shadow: 0 0 0 2px #ff0000, 0 0 10px rgba(244, 67, 54, 0.6);
|
|
388
|
+
animation: pulse-badge 2s infinite;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
@keyframes pulse-badge {
|
|
392
|
+
0%, 100% {
|
|
393
|
+
transform: scale(1);
|
|
394
|
+
opacity: 1;
|
|
395
|
+
}
|
|
396
|
+
50% {
|
|
397
|
+
transform: scale(1.2);
|
|
398
|
+
opacity: 0.8;
|
|
399
|
+
}
|
|
375
400
|
}
|
|
376
401
|
|
|
377
402
|
/* 弹窗样式 */
|
|
@@ -622,6 +647,9 @@
|
|
|
622
647
|
<button onclick="executeUpdate()">
|
|
623
648
|
更新证书
|
|
624
649
|
</button>
|
|
650
|
+
<button id="updateBtn" onclick="checkForUpdates()">
|
|
651
|
+
软件更新
|
|
652
|
+
</button>
|
|
625
653
|
</div>
|
|
626
654
|
|
|
627
655
|
<div style="margin-top: 30px; padding-top: 30px; border-top: 1px solid rgba(255, 255, 255, 0.05);">
|
|
@@ -890,6 +918,7 @@
|
|
|
890
918
|
connectWebSocket();
|
|
891
919
|
startScheduleInfoSync();
|
|
892
920
|
updateCallbackApiUrl();
|
|
921
|
+
checkForUpdates(true); // 静默检查更新
|
|
893
922
|
|
|
894
923
|
// 搜索框事件
|
|
895
924
|
document.getElementById('certSearch').addEventListener('input', filterCerts);
|
|
@@ -1206,6 +1235,98 @@
|
|
|
1206
1235
|
}
|
|
1207
1236
|
}
|
|
1208
1237
|
|
|
1238
|
+
// 检查程序更新
|
|
1239
|
+
async function checkForUpdates(silent = false) {
|
|
1240
|
+
if (!silent) {
|
|
1241
|
+
addLog('→ 正在检查更新...', 'info');
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
try {
|
|
1245
|
+
const response = await authenticatedFetch('/admin/check-update', {
|
|
1246
|
+
method: 'POST'
|
|
1247
|
+
});
|
|
1248
|
+
const result = await response.json();
|
|
1249
|
+
|
|
1250
|
+
if (result.code === 0) {
|
|
1251
|
+
const { currentVersion, remoteVersion, hasUpdate } = result.data;
|
|
1252
|
+
|
|
1253
|
+
if (hasUpdate) {
|
|
1254
|
+
// 显示红点提示
|
|
1255
|
+
const updateBtn = document.getElementById('updateBtn');
|
|
1256
|
+
if (updateBtn && !updateBtn.querySelector('.update-badge')) {
|
|
1257
|
+
const badge = document.createElement('span');
|
|
1258
|
+
badge.className = 'update-badge';
|
|
1259
|
+
updateBtn.appendChild(badge);
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
if (!silent) {
|
|
1263
|
+
addLog(`✓ 发现新版本: ${remoteVersion} (当前版本: ${currentVersion})`, 'success');
|
|
1264
|
+
const confirmed = await showConfirm(
|
|
1265
|
+
`发现新版本 ${remoteVersion}`,
|
|
1266
|
+
`当前版本: ${currentVersion}\n新版本: ${remoteVersion}\n\n确定要立即更新吗?更新完成后程序将自动重启。`
|
|
1267
|
+
);
|
|
1268
|
+
|
|
1269
|
+
if (confirmed) {
|
|
1270
|
+
await performUpdate();
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
} else {
|
|
1274
|
+
// 移除红点(如果有)
|
|
1275
|
+
const updateBtn = document.getElementById('updateBtn');
|
|
1276
|
+
if (updateBtn) {
|
|
1277
|
+
const badge = updateBtn.querySelector('.update-badge');
|
|
1278
|
+
if (badge) {
|
|
1279
|
+
badge.remove();
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
if (!silent) {
|
|
1284
|
+
addLog(`✓ 已是最新版本: ${currentVersion}`, 'success');
|
|
1285
|
+
showAlert('检查更新', `当前已是最新版本 ${currentVersion}`, 'success');
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
} else {
|
|
1289
|
+
if (!silent) {
|
|
1290
|
+
addLog('✗ 检查更新失败: ' + result.msg, 'error');
|
|
1291
|
+
showAlert('检查更新失败', result.msg, 'error');
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
} catch (error) {
|
|
1295
|
+
if (error.message !== '未设置密码' && error.message !== '密码验证失败') {
|
|
1296
|
+
if (!silent) {
|
|
1297
|
+
addLog('✗ 检查更新失败: ' + error.message, 'error');
|
|
1298
|
+
showAlert('检查更新失败', error.message, 'error');
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
// 执行更新
|
|
1305
|
+
async function performUpdate() {
|
|
1306
|
+
addLog('→ 开始执行更新...', 'info');
|
|
1307
|
+
|
|
1308
|
+
try {
|
|
1309
|
+
const response = await authenticatedFetch('/admin/execute-update', {
|
|
1310
|
+
method: 'POST'
|
|
1311
|
+
});
|
|
1312
|
+
const result = await response.json();
|
|
1313
|
+
|
|
1314
|
+
if (result.code === 0) {
|
|
1315
|
+
addLog('✓ 更新命令已执行,程序将在更新完成后自动重启', 'success');
|
|
1316
|
+
addLog('→ 请稍等片刻,更新完成后刷新页面即可', 'info');
|
|
1317
|
+
showAlert('更新中', '更新命令已执行,程序将在更新完成后自动重启。请稍等片刻后刷新页面。', 'success');
|
|
1318
|
+
} else {
|
|
1319
|
+
addLog('✗ 执行更新失败: ' + result.msg, 'error');
|
|
1320
|
+
showAlert('执行更新失败', result.msg, 'error');
|
|
1321
|
+
}
|
|
1322
|
+
} catch (error) {
|
|
1323
|
+
if (error.message !== '未设置密码' && error.message !== '密码验证失败') {
|
|
1324
|
+
addLog('✗ 执行更新失败: ' + error.message, 'error');
|
|
1325
|
+
showAlert('执行更新失败', error.message, 'error');
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1209
1330
|
// 同步定时任务信息
|
|
1210
1331
|
function startScheduleInfoSync() {
|
|
1211
1332
|
// 立即同步一次
|