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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vk-ssl-auto-deploy",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
4
4
  "description": "SSL证书自动部署工具 - 提供HTTP API接口,支持证书文件自动上传和部署",
5
5
  "main": "app.js",
6
6
  "scripts": {
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
  // 立即同步一次