-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathnp.sh
More file actions
2070 lines (1847 loc) · 76.1 KB
/
np.sh
File metadata and controls
2070 lines (1847 loc) · 76.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env bash
# 当前脚本版本号
SCRIPT_VERSION='1.0.0'
# 环境变量用于在Debian或Ubuntu操作系统中设置非交互式(noninteractive)安装模式
export DEBIAN_FRONTEND=noninteractive
# Github 反代加速代理
GITHUB_PROXY=('https://v6.gh-proxy.org/' 'https://gh-proxy.com/' 'https://hub.glowp.xyz/' 'https://proxy.vvvv.ee/')
# 工作目录和临时目录
TEMP_DIR='/tmp/nodepass'
WORK_DIR='/etc/nodepass'
trap "rm -rf $TEMP_DIR >/dev/null 2>&1 ; echo -e '\n' ;exit" INT QUIT TERM EXIT
mkdir -p $TEMP_DIR
E[0]="\n Language:\n 1. 简体中文 (Default)\n 2. English"
C[0]="${E[0]}"
E[1]=""
C[1]=""
E[2]="The script must be run as root, you can enter sudo -i and then download and run again. Feedback: [https://github.com/NodePassProject/npsh/issues]"
C[2]="必须以 root 方式运行脚本,可以输入 sudo -i 后重新下载运行,问题反馈:[https://github.com/NodePassProject/npsh/issues]"
E[3]="Unsupported architecture: \$(uname -m)"
C[3]="不支持的架构: \$(uname -m)"
E[4]="Please choose: "
C[4]="请选择: "
E[5]="The script supports Linux systems only. Feedback: [https://github.com/NodePassProject/npsh/issues]"
C[5]="本脚本只支持 Linux 系统,问题反馈:[https://github.com/NodePassProject/npsh/issues]"
E[6]="NodePass help menu"
C[6]="NodePass 帮助菜单"
E[7]="Install dependence-list:"
C[7]="安装依赖列表:"
E[8]="Failed to install download tool (curl). Please install wget or curl manually."
C[8]="无法安装下载工具(curl)。请手动安装 wget 或 curl。"
E[9]="Failed to download \$APP"
C[9]="下载 \$APP 失败"
E[10]="NodePass installed successfully!"
C[10]="NodePass 安装成功!"
E[11]="NodePass has been uninstalled"
C[11]="NodePass 已卸载"
E[12]="The external network of the current machine is single-stack:\\\n 1. \${SERVER_IPV4_DEFAULT}\${SERVER_IPV6_DEFAULT}\(default\)\\\n 2. Do not listen on the public network, only listen locally"
C[12]="检测到本机的外网是单栈:\\\n 1. \${SERVER_IPV4_DEFAULT}\${SERVER_IPV6_DEFAULT},监听全栈 \(默认\)\\\n 2. 不对公网监听,只监听本地"
E[13]="Please enter the port (1024-65535, NAT machine must use an open port, press Enter for random port):"
C[13]="请输入端口 (1024-65535,NAT 机器必须使用开放的端口,回车使用随机端口):"
E[14]="Please enter API prefix (lowercase letters, numbers and / only, press Enter for default \"api\"):"
C[14]="请输入 API 前缀 (仅限小写字母、数字和斜杠/,回车使用默认 \"api\"):"
E[15]="Please select TLS mode (press Enter for none TLS encryption):"
C[15]="请选择 TLS 模式 (回车不使用 TLS 加密):"
E[16]="0. None TLS encryption (plain TCP) - Fastest performance, no overhead (default)\n 1. Self-signed certificate (auto-generated) - Fine security with simple setups\n 2. Custom certificate (requires pre-prepared crt and key files) - Highest security with certificate validation"
C[16]="0. 不使用 TLS 加密(明文 TCP) - 最快性能,无开销(默认)\n 1. 自签名证书(自动生成) - 设置简单的良好安全性\n 2. 自定义证书(须预备 crt 和 key 文件) - 具有证书验证的最高安全性"
E[17]="Please enter the correct option"
C[17]="请输入正确的选项"
E[18]="NodePass is already installed, please uninstall it before reinstalling"
C[18]="NodePass 已安装,请先卸载后再重新安装"
E[19]="NodePass \$LATEST\_VERSION and QRencode have been downloaded."
C[19]="已下载 NodePass \$LATEST_VERSION 和 QRencode"
E[20]="Failed to get latest version"
C[20]="无法获取最新版本"
E[21]="Running in container environment, skipping service creation and starting process directly"
C[21]="在容器环境中运行,跳过服务创建,直接启动进程"
E[22]="NodePass Script Usage / NodePass 脚本使用方法:\n np - Show menu / 显示菜单\n np -i - Install NodePass / 安装 NodePass\n np -u - Uninstall NodePass / 卸载 NodePass\n np -v - Upgrade NodePass / 升级 NodePass\n np -t - Switch NodePass version between stable and development / 在稳定版和开发版之间切换 NodePass\n np -o - Toggle service status (start/stop) / 切换服务状态 (开启/停止)\n np -k - Change NodePass API key / 更换 NodePass API key\n np -c - Change intranet penetration server / 更换内网穿透\n np -s - Show NodePass API info / 显示 NodePass API 信息\n np -h - Show help information / 显示帮助信息"
C[22]="${E[22]}"
E[23]="Please enter the path to your TLS certificate file:"
C[23]="请输入您的 TLS 证书文件路径:"
E[24]="Please enter the path to your TLS private key file:"
C[24]="请输入您的 TLS 私钥文件路径:"
E[25]="Certificate file does not exist:"
C[25]="证书文件不存在:"
E[26]="Private key file does not exist:"
C[26]="私钥文件不存在:"
E[27]="Using custom TLS certificate"
C[27]="使用自定义 TLS 证书"
E[28]="Install"
C[28]="安装"
E[29]="Uninstall"
C[29]="卸载"
E[30]="Upgrade core"
C[30]="升级内核"
E[31]="Exit"
C[31]="退出"
E[32]="not installed"
C[32]="未安装"
E[33]="stopped"
C[33]="已停止"
E[34]="running"
C[34]="运行中"
E[35]="NodePass Installation Information:"
C[35]="NodePass 安装信息:"
E[36]="Port is already in use, please try another one."
C[36]="端口已被占用,请尝试其他端口。"
E[37]="Using random port:"
C[37]="使用随机端口:"
E[38]="Please select: "
C[38]="请选择: "
E[39]="API URL:"
C[39]="API URL:"
E[40]="API KEY:"
C[40]="API KEY:"
E[41]="Invalid port number, please enter a number between 1024 and 65535."
C[41]="无效的端口号,请输入1024到65535之间的数字。"
E[42]="NodePass service has been stopped"
C[42]="NodePass 服务已关闭"
E[43]="NodePass service has been started"
C[43]="NodePass 服务已开启"
E[44]="Unable to get local version"
C[44]="无法获取本地版本"
E[45]="NodePass Local Core: Stable \$STABLE_LOCAL_VERSION Dev \$DEV_LOCAL_VERSION LTS \$LTS_LOCAL_VERSION"
C[45]="NodePass 本地核心: 稳定版 \$STABLE_LOCAL_VERSION 开发版 \$DEV_LOCAL_VERSION 经典版 \$LTS_LOCAL_VERSION"
E[46]="NodePass Latest Core: Stable \$STABLE_LATEST_VERSION Dev \$DEV_LATEST_VERSION LTS \$LTS_LATEST_VERSION"
C[46]="NodePass 最新核心: 稳定版 \$STABLE_LATEST_VERSION 开发版 \$DEV_LATEST_VERSION 经典版 \$LTS_LATEST_VERSION"
E[47]="Current version is already the latest, no need to upgrade"
C[47]="当前已是最新版本,不需要升级"
E[48]="Found new version, upgrade? (y/N)"
C[48]="发现新版本,是否升级?(y/N)"
E[49]="Upgrade cancelled"
C[49]="取消升级"
E[50]="Stopping NodePass service..."
C[50]="停止 NodePass 服务..."
E[51]="Starting NodePass service..."
C[51]="启动 NodePass 服务..."
E[52]="NodePass upgrade successful!"
C[52]="NodePass 升级成功!"
E[53]="Failed to start NodePass service, please check logs"
C[53]="NodePass 服务启动失败,请检查日志"
E[54]="Rolled back to previous version"
C[54]="已回滚到之前的版本"
E[55]="Rollback failed, please check manually"
C[55]="回滚失败,请手动检查"
E[56]="Stop API"
C[56]="关闭 API"
E[57]="Create shortcuts successfully: script can be run with [ np ] command, and [ nodepass ] binary is directly executable."
C[57]="创建快捷方式成功: 脚本可通过 [ np ] 命令运行,[ nodepass ] 应用可直接执行!"
E[58]="Start API"
C[58]="开启 API"
E[59]="NodePass is not installed. Configuration file not found"
C[59]="NodePass 未安装,配置文件不存在"
E[60]="NodePass API:"
C[60]="NodePass API:"
E[61]="PREFIX can only contain lowercase letters, numbers, and slashes (/), please re-enter"
C[61]="PREFIX 只能包含小写字母、数字和斜杠(/),请重新输入"
E[62]="Change KEY"
C[62]="更换 KEY"
E[63]="API KEY changed successfully!"
C[63]="API KEY 更换成功"
E[64]="Failed to change API KEY"
C[64]="API KEY 更换失败"
E[65]="Changing NodePass API KEY..."
C[65]="正在更换 NodePass API KEY..."
E[66]="Current running version: Development Version"
C[66]="当前运行版本为: 开发版"
E[67]="Current running version: Stable Version"
C[67]="当前运行版本为: 稳定版"
E[68]="Please enter the IP of the public machine (leave blank to not penetrate):"
C[68]="如要把内网的 API 穿透到公网的 NodePass 服务端,请输入公网机器的 IP (留空则不穿透):"
E[69]="Please enter the port of the public machine:"
C[69]="请输入穿透到公网的 NodePass 服务端的端口:"
E[70]="Change intranet penetration server"
C[70]="更换内网穿透"
E[71]="Please enter the password (default is no password):"
C[71]="输入密码(默认无密码):"
E[72]="The service of intranet penetration to remote has been created successfully"
C[72]="内网穿透到远程的服务已创建成功"
E[73]="API intranet penetration server creation failed!"
C[73]="API 内网穿透到远程的服务创建失败!"
E[74]="Not a valid IPv4,IPv6 address or domain name"
C[74]="不是有效的IPv4,IPv6地址或域名"
E[75]="Please enter the IP of the intranet penetration server:"
C[75]="输入新的内网穿透服务端 IP 或域名:"
E[76]="Successfully modified the intranet penetration instance"
C[76]="成功修改内网穿透实例"
E[77]="Failed to modify the intranet penetration instance"
C[77]="修改内网穿透实例失败"
E[78]="The external network of the current machine is dual-stack:\\\n 1. \${SERVER_IPV4_DEFAULT},listen all stacks \(default\)\\\n 2. \${SERVER_IPV6_DEFAULT},listen all stacks\\\n 3. Do not listen on the public network, only listen locally"
C[78]="检测到本机的外网是双栈:\\\n 1. \${SERVER_IPV4_DEFAULT},监听全栈 \(默认\)\\\n 2. \${SERVER_IPV6_DEFAULT},监听全栈\\\n 3. 不对公网监听,只监听本地"
E[79]="Please select or enter the domain or IP directly:"
C[79]="请选择或者直接输入域名或 IP:"
E[80]="The script runs today: \$TODAY. Total: \$TOTAL"
C[80]="脚本当天运行次数: \$TODAY,累计运行次数: \$TOTAL"
E[81]="Please enter the port on the server that the local machine will connect to for the tunnel (1024–65535):"
C[81]="请输入用于内网穿透中,本机连接到服务端的隧道端口(即服务端监听的端口)(1024–65535):"
E[82]="Running the service of intranet penetration on the server side:"
C[82]="内网穿透的服务端运行:"
E[83]="Failed to retrieve intranet penetration instance. Instance ID: \${INSTANCE\_ID}"
C[83]="获取内网穿透实例失败,实例ID: \${INSTANCE_ID}"
E[84]="Please select the NodePass core to run. Use [np -t] to switch after installation:\\\n 1. Stable \$STABLE_LATEST_VERSION \(NodePassProject/nodepass\) - Suitable for production environments \(default\)\\\n 2. Development \$DEV_LATEST_VERSION \(NodePassProject/nodepass\) - Contains latest features, may be unstable\\\n 3. Classic \$LTS_LATEST_VERSION \(NodePassProject/nodepass\) - Long-term support version"
C[84]="请选择要运行的 NodePass 内核,安装后可使用 [np -t] 切换:\\\n 1. 稳定版 \$STABLE_LATEST_VERSION \(NodePassProject/nodepass\) - 适合生产环境 \(默认\)\\\n 2. 开发版 \$DEV_LATEST_VERSION \(NodePassProject/nodepass\) - 包含最新功能,可能不稳定\\\n 3. 经典版 \$LTS_LATEST_VERSION \(NodePassProject/nodepass\) - 长期支持版本"
E[85]="Getting machine IP address..."
C[85]="获取机器 IP 地址中..."
E[86]="Switching NodePass version..."
C[86]="正在切换 NodePass 版本..."
E[87]="Switched successfully"
C[87]="已成功切换"
E[88]="Please select the version to switch to (default is 3):"
C[88]="请选择要切换到的版本 (默认为 3):"
E[89]="NodePass version switch failed"
C[89]="NodePass 版本切换失败"
E[90]="URI:"
C[90]="URI:"
E[91]="No upgrade available for both stable, development and classic versions"
C[91]="稳定版、开发版和经典版均无可用更新"
E[92]="Stable version can be upgraded from \$STABLE_LOCAL_VERSION to \$STABLE_LATEST_VERSION"
C[92]="稳定版可以从 \$STABLE_LOCAL_VERSION 升级到 \$STABLE_LATEST_VERSION"
E[93]="Development version can be upgraded from \$DEV_LOCAL_VERSION to \$DEV_LATEST_VERSION"
C[93]="开发版可以从 \$DEV_LOCAL_VERSION 升级到 \$DEV_LATEST_VERSION"
E[94]="Stable, development or classic version has available updates"
C[94]="稳定版,开发版或经典版有可用更新"
E[95]="Switch core version"
C[95]="切换内核版本"
E[96]="Waiting 5 seconds before starting the service..."
C[96]="正在等待5秒后启动服务..."
E[97]="Current running version:"
C[97]="当前运行版本:"
E[98]="Current running version: Classic Version"
C[98]="当前运行版本为: 经典版"
E[99]="Classic version can be upgraded from \$LTS_LOCAL_VERSION to \$LTS_LATEST_VERSION"
C[99]="经典版可以从 \$LTS_LOCAL_VERSION 升级到 \$LTS_LATEST_VERSION"
E[100]="Switch to stable version (np-stb)"
C[100]="切换到稳定版 (np-stb)"
E[101]="Switch to development version (np-dev)"
C[101]="切换到开发版 (np-dev)"
E[102]="Switch to classic version (np-lts)"
C[102]="切换到经典版 (np-lts)"
E[103]="Cancel switching"
C[103]="取消切换"
E[104]="Please select the version to switch to (default is 3):"
C[104]="请选择要切换到的版本 (默认为 3):"
# 自定义字体彩色,read 函数
warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色
error() { echo -e "\033[31m\033[01m$*\033[0m" && exit 1; } # 红色
info() { echo -e "\033[32m\033[01m$*\033[0m"; } # 绿色
hint() { echo -e "\033[33m\033[01m$*\033[0m"; } # 黄色
reading() { read -rp "$(info "$1")" "$2"; }
text() { grep -q '\$' <<< "${E[$*]}" && eval echo "\$(eval echo "\${${L}[$*]}")" || eval echo "\${${L}[$*]}"; }
# 显示帮助信息
help() {
hint " ${E[22]} "
}
# 必须以root运行脚本
check_root() {
[ "$(id -u)" != 0 ] && error " $(text 2) "
}
# 检查系统要求
check_system() {
# 只判断是否为 Linux 系统
[ "$(uname -s)" != "Linux" ] && error " $(text 5) "
# 检查系统信息
check_system_info
# 根据系统类型设置包管理和服务管理命令
case "$SYSTEM" in
alpine)
PACKAGE_INSTALL='apk add --no-cache'
PACKAGE_UPDATE='apk update -f'
PACKAGE_UNINSTALL='apk del'
SERVICE_START='rc-service nodepass start'
SERVICE_STOP='rc-service nodepass stop'
SERVICE_RESTART='rc-service nodepass restart'
SERVICE_STATUS='rc-service nodepass status'
SYSTEMCTL='rc-service'
SYSTEMCTL_ENABLE='rc-update add nodepass'
SYSTEMCTL_DISABLE='rc-update del nodepass'
;;
arch)
PACKAGE_INSTALL='pacman -S --noconfirm'
PACKAGE_UPDATE='pacman -Syu --noconfirm'
PACKAGE_UNINSTALL='pacman -R --noconfirm'
SERVICE_START='systemctl start nodepass'
SERVICE_STOP='systemctl stop nodepass'
SERVICE_RESTART='systemctl restart nodepass'
SERVICE_STATUS='systemctl status nodepass'
SYSTEMCTL='systemctl'
SYSTEMCTL_ENABLE='systemctl enable nodepass'
SYSTEMCTL_DISABLE='systemctl disable nodepass'
;;
debian|ubuntu)
PACKAGE_INSTALL='apt-get -y install'
PACKAGE_UPDATE='apt-get update'
PACKAGE_UNINSTALL='apt-get -y autoremove'
SERVICE_START='systemctl start nodepass'
SERVICE_STOP='systemctl stop nodepass'
SERVICE_RESTART='systemctl restart nodepass'
SERVICE_STATUS='systemctl status nodepass'
SYSTEMCTL='systemctl'
SYSTEMCTL_ENABLE='systemctl enable nodepass'
SYSTEMCTL_DISABLE='systemctl disable nodepass'
;;
centos|fedora)
PACKAGE_INSTALL='yum -y install'
PACKAGE_UPDATE='yum -y update'
PACKAGE_UNINSTALL='yum -y autoremove'
SERVICE_START='systemctl start nodepass'
SERVICE_STOP='systemctl stop nodepass'
SERVICE_RESTART='systemctl restart nodepass'
SERVICE_STATUS='systemctl status nodepass'
SYSTEMCTL='systemctl'
SYSTEMCTL_ENABLE='systemctl enable nodepass'
SYSTEMCTL_DISABLE='systemctl disable nodepass'
;;
OpenWRT)
PACKAGE_INSTALL='opkg install'
PACKAGE_UPDATE='opkg update'
PACKAGE_UNINSTALL='opkg remove'
SERVICE_START='/etc/init.d/nodepass start'
SERVICE_STOP='/etc/init.d/nodepass stop'
SERVICE_RESTART='/etc/init.d/nodepass restart'
SERVICE_STATUS='/etc/init.d/nodepass status'
SYSTEMCTL='/etc/init.d'
SYSTEMCTL_ENABLE='/etc/init.d/nodepass enable'
SYSTEMCTL_DISABLE='/etc/init.d/nodepass disable'
;;
*)
PACKAGE_INSTALL='apt-get -y install'
PACKAGE_UPDATE='apt-get update'
PACKAGE_UNINSTALL='apt-get -y autoremove'
SERVICE_START='systemctl start nodepass'
SERVICE_STOP='systemctl stop nodepass'
SERVICE_RESTART='systemctl restart nodepass'
SERVICE_STATUS='systemctl status nodepass'
SYSTEMCTL='systemctl'
SYSTEMCTL_ENABLE='systemctl enable nodepass'
SYSTEMCTL_DISABLE='systemctl disable nodepass'
;;
esac
# 如果在容器环境中,覆盖服务管理方式
[ "$IN_CONTAINER" = 1 ] && SERVICE_MANAGE="none"
}
# 检查安装状态,状态码: 2 未安装, 1 已安装未运行, 0 运行中
check_install() {
if [ ! -f "$WORK_DIR/nodepass" ]; then
return 2
else
# 根据服务管理方式获取 http 或 https
if [ "$IN_CONTAINER" = 1 ] || [ "$SERVICE_MANAGE" = "none" ]; then
grep -q '^CMD=.*tls=0' ${WORK_DIR}/data && HTTP_S="http" || HTTP_S="https"
elif [ "$SERVICE_MANAGE" = "systemctl" ]; then
grep -q '^ExecStart=.*tls=0' /etc/systemd/system/nodepass.service && HTTP_S="http" || HTTP_S="https"
elif [ "$SERVICE_MANAGE" = "rc-service" ]; then
grep -q '^command_args=.*tls=0' /etc/init.d/nodepass && HTTP_S="http" || HTTP_S="https"
elif [ "$SERVICE_MANAGE" = "init.d" ]; then
grep -q '^PROG=.*tls=0' /etc/init.d/nodepass && HTTP_S="http" || HTTP_S="https"
fi
fi
if [ "$IN_CONTAINER" = 1 ] || [ "$SERVICE_MANAGE" = "none" ]; then
if [ $(type -p pgrep) ]; then
# 过滤掉僵尸进程 <defunct>
if pgrep -laf "nodepass" | grep -vE "grep|<defunct>" | grep -q "nodepass"; then
return 0
else
return 1
fi
else
# 过滤掉僵尸进程 <defunct>
if ps -ef | grep -vE "grep|<defunct>" | grep -q "nodepass"; then
return 0
else
return 1
fi
fi
elif [ "$SERVICE_MANAGE" = "systemctl" ] && ! systemctl is-active nodepass &>/dev/null; then
return 1
elif [ "$SERVICE_MANAGE" = "rc-service" ] && ! rc-service nodepass status &>/dev/null; then
return 1
elif [ "$SERVICE_MANAGE" = "init.d" ]; then
# OpenWRT 系统检查服务状态
if [ -f "/var/run/nodepass.pid" ] && kill -0 $(cat "/var/run/nodepass.pid" 2>/dev/null) >/dev/null 2>&1; then
return 0
else
return 1
fi
else
return 0
fi
}
# 安装系统依赖及定义下载工具
check_dependencies() {
DEPS_INSTALL=()
# 检查 wget 和 curl
if [ -x "$(type -p curl)" ]; then
DOWNLOAD_TOOL="curl"
DOWNLOAD_CMD="curl -sL"
elif [ -x "$(type -p wget)" ]; then
DOWNLOAD_TOOL="wget"
DOWNLOAD_CMD="wget -q"
# 如果是 Alpine,先升级 wget
grep -qi 'alpine' <<< "$SYSTEM" && grep -qi 'busybox' <<< "$(wget 2>&1 | head -n 1)" && apk add --no-cache wget >/dev/null 2>&1
else
# 如果都没有,安装 curl
DEPS_INSTALL+=("curl")
DOWNLOAD_TOOL="curl"
DOWNLOAD_CMD="curl -sL"
fi
# 检查是否有 ps 或 pkill 命令
if [ ! -x "$(type -p ps)" ] && [ ! -x "$(type -p pkill)" ]; then
# 根据不同系统添加对应的包名
if grep -qi 'alpine' /etc/os-release 2>/dev/null; then
DEPS_INSTALL+=("procps")
elif grep -qi 'debian\|ubuntu' /etc/os-release 2>/dev/null; then
DEPS_INSTALL+=("procps")
elif grep -qi 'centos\|fedora' /etc/os-release 2>/dev/null; then
DEPS_INSTALL+=("procps-ng")
elif grep -qi 'arch' /etc/os-release 2>/dev/null; then
DEPS_INSTALL+=("procps-ng")
else
DEPS_INSTALL+=("procps")
fi
fi
# 检查其他依赖
local DEPS_CHECK=("tar")
local PACKAGE_DEPS=("tar")
for g in "${!DEPS_CHECK[@]}"; do
[ ! -x "$(type -p ${DEPS_CHECK[g]})" ] && DEPS_INSTALL+=("${PACKAGE_DEPS[g]}")
done
if [ "${#DEPS_INSTALL[@]}" -gt 0 ]; then
info "\n $(text 7) ${DEPS_INSTALL[@]} \n"
${PACKAGE_UPDATE} >/dev/null 2>&1
${PACKAGE_INSTALL} ${DEPS_INSTALL[@]} >/dev/null 2>&1
fi
}
# 检查系统信息
check_system_info() {
# 检查架构
case "$(uname -m)" in
x86_64 | amd64 ) ARCH=amd64 ;;
armv8 | arm64 | aarch64 ) ARCH=arm64 ;;
armv7l ) ARCH=arm ;;
s390x ) ARCH=s390x ;;
* ) error " $(text 3) " ;;
esac
# 检查系统
if [ -f /etc/openwrt_release ]; then
SYSTEM="OpenWRT"
SERVICE_MANAGE="init.d"
elif [ -f /etc/os-release ]; then
source /etc/os-release
SYSTEM=$ID
[[ $SYSTEM = "centos" && $(expr "$VERSION_ID" : '.*\s\([0-9]\{1,\}\)\.*') -ge 7 ]] && SYSTEM=centos
[[ $SYSTEM = "debian" && $(expr "$VERSION_ID" : '.*\s\([0-9]\{1,\}\)\.*') -ge 10 ]] && SYSTEM=debian
[[ $SYSTEM = "ubuntu" && $(expr "$VERSION_ID" : '.*\s\([0-9]\{1,\}\)\.*') -ge 16 ]] && SYSTEM=ubuntu
[[ $SYSTEM = "alpine" && $(expr "$VERSION_ID" : '.*\s\([0-9]\{1,\}\)\.*') -ge 3 ]] && SYSTEM=alpine
fi
# 确定服务管理方式
if [ -z "$SERVICE_MANAGE" ]; then
if [ -x "$(type -p systemctl)" ]; then
SERVICE_MANAGE="systemctl"
elif [ -x "$(type -p openrc-run)" ]; then
SERVICE_MANAGE="rc-service"
elif [[ -x "$(type -p service)" && -d /etc/init.d ]]; then
SERVICE_MANAGE="init.d"
else
SERVICE_MANAGE="none"
fi
fi
# 检查是否在容器环境中
if [ -f /.dockerenv ] || grep -q 'docker\|lxc' /proc/1/cgroup; then
IN_CONTAINER=1
else
IN_CONTAINER=0
fi
}
# 验证IPv4或IPv6地址格式,返回0表示有效,返回1表示无效
validate_ip_address() {
local IP="$1"
# IPv4正则表达式
local IPV4_REGEX='^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'
# IPv6正则表达式(简化版)
local IPV6_REGEX='^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$'
# 域名正则表达式(支持常规域名和带点的子域名,不支持特殊字符)
local DOMAIN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$'
# localhost 特殊处理
[ "$IP" = "localhost" ] && IP="127.0.0.1"
if [[ "$IP" =~ $IPV4_REGEX ]] || [[ "$IP" =~ $IPV6_REGEX ]] || [[ "$IP" =~ $DOMAIN_REGEX ]]; then
return 0 # 有效IP地址
else
warning " $(text 74) "
return 1 # 无效IP地址
fi
}
# 检查端口是否可用,返回0表示可用,返回1表示被占用,返回2表示端口不在有效范围内
check_port() {
local PORT=$1
local NO_CHECK_USED=$2
# 检查端口是否为数字且在有效范围内
if ! [[ "$PORT" =~ ^[0-9]+$ ]] || [ "$PORT" -lt 1024 ] || [ "$PORT" -gt 65535 ]; then
return 2 # 返回2表示端口不在有效范围内
fi
if ! grep -q 'no_check_used' <<< "$NO_CHECK_USED"; then
# 检查端口是否被占用
# 方法1: 使用 nc 命令
if [ $(type -p nc) ]; then
nc -z 127.0.0.1 "$PORT" >/dev/null 2>&1
if [ $? -eq 0 ]; then
return 1 # 返回1表示端口被占用
fi
# 方法2: 使用 lsof 命令
elif [ $(type -p lsof) ]; then
lsof -i:"$PORT" >/dev/null 2>&1
if [ $? -eq 0 ]; then
return 1 # 返回1表示端口被占用
fi
# 方法3: 使用 netstat 命令
elif [ $(type -p netstat) ]; then
netstat -nltup 2>/dev/null | grep -q ":$PORT "
if [ $? -eq 0 ]; then
return 1 # 返回1表示端口被占用
fi
# 方法4: 使用 ss 命令
elif [ $(type -p ss) ]; then
ss -nltup 2>/dev/null | grep -q ":$PORT "
if [ $? -eq 0 ]; then
return 1 # 返回1表示端口被占用
fi
# 方法5: 尝试使用/dev/tcp检查
else
(echo >/dev/tcp/127.0.0.1/"$PORT") >/dev/null 2>&1
if [ $? -eq 0 ]; then
return 1 # 返回1表示端口被占用
fi
fi
return 0 # 返回0表示端口可用
fi
}
# 检测是否需要启用 Github CDN,如能直接连通,则不使用
check_cdn() {
for PROXY_URL in "${GITHUB_PROXY[@]}"; do
if [ "$DOWNLOAD_TOOL" = "curl" ]; then
REMOTE_VERSION=$(curl -ksL --connect-timeout 3 --max-time 3 ${PROXY_URL}https://raw.githubusercontent.com/NodePassProject/npsh/refs/heads/main/README.md 2>/dev/null | sed -nE 's/^-[ ]+(Stable|Development|LTS):/\1:/p')
else
REMOTE_VERSION=$(wget -qO- --no-check-certificate --tries=2 --timeout=3 ${PROXY_URL}https://raw.githubusercontent.com/NodePassProject/npsh/refs/heads/main/README.md 2>/dev/null | sed -nE 's/^-[ ]+(Stable|Development|LTS):/\1:/p')
fi
grep -q 'Stable' <<< "$REMOTE_VERSION" && GH_PROXY="$PROXY_URL" && break
done
}
# 脚本当天及累计运行次数统计
statistics_of_run-times() {
local UPDATE_OR_GET=$1
local SCRIPT=$2
if grep -q 'update' <<< "$UPDATE_OR_GET"; then
{ wget --no-check-certificate -qO- --timeout=3 "https://stat.cloudflare.now.cc/api/updateStats?script=${SCRIPT}" > $TEMP_DIR/statistics 2>/dev/null || true; }&
elif grep -q 'get' <<< "$UPDATE_OR_GET"; then
[ -s $TEMP_DIR/statistics ] && [[ $(cat $TEMP_DIR/statistics) =~ \"todayCount\":([0-9]+),\"totalCount\":([0-9]+) ]] && local TODAY="${BASH_REMATCH[1]}" && local TOTAL="${BASH_REMATCH[2]}" && rm -f $TEMP_DIR/statistics
info "\n*******************************************\n\n $(text 80) \n"
fi
}
# 选择语言,先判断 ${WORK_DIR}/language 里的语言选择,没有的话再让用户选择,默认英语。处理中文显示的问题
select_language() {
UTF8_LOCALE=$(locale -a 2>/dev/null | grep -iEm1 "UTF-8|utf8")
[ -n "$UTF8_LOCALE" ] && export LC_ALL="$UTF8_LOCALE" LANG="$UTF8_LOCALE" LANGUAGE="$UTF8_LOCALE"
# 优先使用命令行参数指定的语言
if [ -n "$ARGS_LANGUAGE" ]; then
case "$ARGS_LANGUAGE" in
1|zh|CN|cn|chinese|C|c)
L=C
;;
2|en|EN|english|E|e)
L=E
;;
*)
L=C # 默认使用中文
;;
esac
# 其次读取保存的配置信息
elif [ -s ${WORK_DIR}/data ]; then
source ${WORK_DIR}/data
L=$LANGUAGE
# 最后使用交互方式选择
else
L=C && hint " $(text 0) \n" && reading " $(text 4) " LANGUAGE_CHOICE
[ "$LANGUAGE_CHOICE" = 2 ] && L=E
fi
}
# 查询 NodePass API URL
get_api_url() {
# 从data文件中获取SERVER_IP
[ -s "$WORK_DIR/data" ] && source "$WORK_DIR/data"
# 检查是否已安装
if [ -s "$WORK_DIR/gob/nodepass.gob" ]; then
# 在容器环境中优先从data文件获取参数
if [ "$IN_CONTAINER" = 1 ] || [ "$SERVICE_MANAGE" = "none" ]; then
if [ -s "$WORK_DIR/data" ] && grep -q "CMD=" "$WORK_DIR/data" ]; then
# 从data文件中获取CMD
local CMD_LINE=$(grep "CMD=" "$WORK_DIR/data" | cut -d= -f2-)
else
# 如果data文件中没有CMD,则从进程中获取,过滤掉僵尸进程
if [ $(type -p pgrep) ]; then
local CMD_LINE=$(pgrep -af "nodepass" | grep -v "grep\|sed\|<defunct>" | sed -n 's/.*nodepass \(.*\)/\1/p')
else
local CMD_LINE=$(ps -ef | grep -v "grep\|sed\|<defunct>" | grep "nodepass" | sed -n 's/.*nodepass \(.*\)/\1/p')
fi
fi
# 根据不同系统类型获取守护文件路径
elif [ "$SERVICE_MANAGE" = "systemctl" ] && [ -s "/etc/systemd/system/nodepass.service" ]; then
local CMD_LINE=$(sed -n 's/.*ExecStart=.*\(master.*\)"/\1/p' "/etc/systemd/system/nodepass.service")
elif [ "$SERVICE_MANAGE" = "rc-service" ] && [ -s "/etc/init.d/nodepass" ]; then
# 从OpenRC服务文件中提取CMD行
local CMD_LINE=$(sed -n 's/.*command_args.*\(master.*\)/\1/p' "/etc/init.d/nodepass")
elif [ "$SERVICE_MANAGE" = "init.d" ] && [ -s "/etc/init.d/nodepass" ]; then
# 从OpenWRT服务文件中提取CMD行
local CMD_LINE=$(sed -n 's/^CMD="\([^"]\+\)"/\1/p' "/etc/init.d/nodepass")
fi
# 如果找到了CMD行,通过正则提取各个参数
if [ -n "$CMD_LINE" ]; then
[[ "$CMD_LINE" =~ master://.*:([0-9]+)/([^?]+)\?(log=[^&]+&)?tls=([0-2]) ]]
PORT="${BASH_REMATCH[1]}"
PREFIX="${BASH_REMATCH[2]}"
TLS_MODE="${BASH_REMATCH[4]}"
grep -qw '0' <<< "$TLS_MODE" && local HTTP_S="http" || local HTTP_S="https"
fi
# 优先查找是否有内网穿透的服务器
if grep -q '.' <<< "$REMOTE"; then
[[ $REMOTE =~ (.*@)?(.*):([0-9]+)$ ]]
local URL_SERVER_PASSWORD="${BASH_REMATCH[1]}"
local URL_SERVER_IP="${BASH_REMATCH[2]}"
URL_SERVER_PORT="${BASH_REMATCH[3]}"
else
local URL_SERVER_PORT=$(sed -n 's#.*:\([0-9]\+\)\/.*#\1#p' <<< "$CMD_LINE")
# 处理IPv6地址格式
grep -q ':' <<< "$SERVER_IP" && local URL_SERVER_IP="[$SERVER_IP]" || local URL_SERVER_IP="$SERVER_IP"
fi
# 构建API URL
API_URL="${HTTP_S}://${URL_SERVER_IP}:${URL_SERVER_PORT}/${PREFIX:+${PREFIX%/}/}v1"
grep -q 'output' <<< "$1" && info " $(text 39) $API_URL "
else
warning " $(text 59) "
fi
}
# 查询 NodePass KEY
get_api_key() {
# 从nodepass.gob文件中提取KEY
if [ -s "$WORK_DIR/gob/nodepass.gob" ]; then
KEY=$(grep -a -o '[0-9a-f]\{32\}' $WORK_DIR/gob/nodepass.gob)
grep -q 'output' <<< "$1" && info " $(text 40) $KEY"
else
warning " $(text 59) "
fi
}
# 查询内网穿透的服务端命令行
get_intranet_penetration_server_cmd() {
if [ "$DOWNLOAD_TOOL" = "curl" ]; then
local CLIENT_CMD=$(curl -ksX 'GET' \
"$HTTP_S://127.0.0.1:${PORT}/${PREFIX}/v1/instances/${INSTANCE_ID}" \
-H 'accept: application/json' \
-H "X-API-Key: ${KEY}")
else
local CLIENT_CMD=$(wget --no-check-certificate -qO- --method=GET \
--header="accept: application/json" \
--header="X-API-Key: ${KEY}" \
"$HTTP_S://127.0.0.1:${PORT}/${PREFIX}/v1/instances/${INSTANCE_ID}")
fi
# 使用正则表达式匹配client URL,支持带密码和不带密码的情况
if [[ "$CLIENT_CMD" =~ \"url\":[[:space:]]*\"client://([^\@]*)@?([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+|\[[0-9a-fA-F:]+\]):([0-9]+)/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+\" ]]; then
grep -q '.' <<< "${BASH_REMATCH[1]}" && local REMOTE_PASSWORD_INPUT="${BASH_REMATCH[1]}@"
local REMOTE_SERVER_INPUT="${BASH_REMATCH[2]}"
local TUNNEL_PORT_INPUT="${BASH_REMATCH[3]}"
SERVER_CMD="server://${REMOTE_PASSWORD_INPUT}${REMOTE_SERVER_INPUT}:${TUNNEL_PORT_INPUT}/:${URL_SERVER_PORT}"
grep -q 'output' <<< "$1" && info " $(text 82) $SERVER_CMD"
else
warning " $(text 83) "
fi
}
# 生成 URI
get_uri() {
grep -q '^$' <<< "$API_URL" && get_api_url
grep -q '^$' <<< "$KEY" && get_api_key
URI="np://master?url=$(echo -n "$API_URL" | base64 -w0)&key=$(echo -n "$KEY" | base64 -w0)"
grep -q 'output' <<< "$1" && grep -q '.' <<< "$URI" && info " $(text 90) $URI" && ${WORK_DIR}/qrencode "$URI"
}
# 获取随机可用端口,目标范围是 1024-8192,共7168个
get_random_port() {
local RANDOM_PORT
while true; do
RANDOM_PORT=$((RANDOM % 7168 + 1024))
check_port "$RANDOM_PORT" "check_used" && break
done
echo "$RANDOM_PORT"
}
# 获取本地版本
get_local_version() {
if grep -qw 'all' <<< "$1"; then
DEV_LOCAL_VERSION=$(${WORK_DIR}/np-dev 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+[^[:space:]]*')
STABLE_LOCAL_VERSION=$(${WORK_DIR}/np-stb 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+[^[:space:]]*')
LTS_LOCAL_VERSION=$(${WORK_DIR}/np-lts 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+[^[:space:]]*')
fi
local GET_SYMLINK_TARGET=$(readlink ${WORK_DIR}/nodepass 2>/dev/null)
if grep -q 'np-dev' <<< "$GET_SYMLINK_TARGET"; then
VERSION_TYPE_TEXT=$(text 66)
elif grep -q 'np-stb' <<< "$GET_SYMLINK_TARGET"; then
VERSION_TYPE_TEXT=$(text 67)
elif grep -q 'np-lts' <<< "$GET_SYMLINK_TARGET"; then
VERSION_TYPE_TEXT=$(text 98)
fi
RUNNING_LOCAL_VERSION=$(${WORK_DIR}/nodepass 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+[^[:space:]]*')
}
# 获取最新版本
get_latest_version() {
STABLE_LATEST_VERSION=$(awk -F '[ ]' '/Stable/{print $NF}' <<< "$REMOTE_VERSION")
DEV_LATEST_VERSION=$(awk -F '[ ]' '/Development/{print $NF}' <<< "$REMOTE_VERSION")
LTS_LATEST_VERSION=$(awk -F '[ ]' '/LTS/{print $NF}' <<< "$REMOTE_VERSION")
[[ -z "$STABLE_LATEST_VERSION" || -z "$DEV_LATEST_VERSION" || -z "$LTS_LATEST_VERSION" ]] && error " $(text 20) "
# 去掉版本号前面的v
STABLE_VERSION_NUM=${STABLE_LATEST_VERSION#v}
DEV_VERSION_NUM=${DEV_LATEST_VERSION#v}
LTS_VERSION_NUM=${LTS_LATEST_VERSION#v}
}
# 切换 NodePass 服务状态(开启/停止)
on_off() {
# 检查 NodePass 是否正在运行
if [ "$IN_CONTAINER" = 1 ] || [ "$SERVICE_MANAGE" = "none" ]; then
if [ $(type -p pgrep) ]; then
# 过滤掉僵尸进程
if pgrep -laf "nodepass" | grep -vE "<defunct>|grep" | grep -q "nodepass"; then
RUNNING=1
else
RUNNING=0
fi
else
# 过滤掉僵尸进程
if ps -ef | grep -vE "grep|<defunct>" | grep -q "nodepass"; then
RUNNING=1
else
RUNNING=0
fi
fi
elif [ "$SERVICE_MANAGE" = "systemctl" ]; then
if systemctl is-active nodepass >/dev/null 2>&1; then
RUNNING=1
else
RUNNING=0
fi
elif [ "$SERVICE_MANAGE" = "rc-service" ]; then
if rc-service nodepass status | grep -q "started"; then
RUNNING=1
else
RUNNING=0
fi
elif [ "$SERVICE_MANAGE" = "init.d" ]; then
if [ -f "/var/run/nodepass.pid" ] && kill -0 $(cat "/var/run/nodepass.pid" 2>/dev/null) >/dev/null 2>&1; then
RUNNING=1
else
RUNNING=0
fi
fi
# 根据当前状态执行相反操作
if [ "$RUNNING" = 1 ]; then
stop_nodepass
info " $(text 42) "
else
start_nodepass
info " $(text 43) "
fi
}
# 启动 NodePass 服务
start_nodepass() {
info " $(text 51) "
# 先清理可能存在的僵尸进程
if [ "$IN_CONTAINER" = 1 ] || [ "$SERVICE_MANAGE" = "none" ]; then
# 查找僵尸进程并尝试清理
if [ $(type -p pgrep) ]; then
ZOMBIE_PIDS=$(pgrep -f "nodepass" | xargs ps -p 2>/dev/null | grep "<defunct>" | awk '{print $1}')
[ -n "$ZOMBIE_PIDS" ] && echo "$ZOMBIE_PIDS" | xargs -r kill -9 >/dev/null 2>&1
else
ZOMBIE_PIDS=$(ps -ef | grep -v grep | grep "nodepass" | grep "<defunct>" | awk '{print $2}')
[ -n "$ZOMBIE_PIDS" ] && echo "$ZOMBIE_PIDS" | xargs -r kill -9 >/dev/null 2>&1
fi
# 从 data 文件中获取 CMD 参数
if [ -s "$WORK_DIR/data" ] && grep -q "CMD=" "$WORK_DIR/data"; then
source "$WORK_DIR/data"
else
# 如果 data 文件中没有 CMD,使用默认值
CMD="master"
fi
nohup $WORK_DIR/nodepass $CMD >/dev/null 2>&1 &
elif [ "$SERVICE_MANAGE" = "systemctl" ]; then
systemctl start nodepass
elif [ "$SERVICE_MANAGE" = "rc-service" ]; then
rc-service nodepass start
elif [ "$SERVICE_MANAGE" = "init.d" ]; then
/etc/init.d/nodepass start
fi
sleep 2
}
# 停止 NodePass 服务
stop_nodepass() {
info " $(text 50) "
if [ "$IN_CONTAINER" = 1 ] || [ "$SERVICE_MANAGE" = "none" ]; then
# 查找所有nodepass进程(包括僵尸进程)并终止
if [ $(type -p pgrep) ]; then
pgrep -f "nodepass" | xargs -r kill -9 >/dev/null 2>&1
else
ps -ef | grep -v grep | grep "nodepass" | awk '{print $2}' | xargs -r kill -9 >/dev/null 2>&1
fi
elif [ "$SERVICE_MANAGE" = "systemctl" ]; then
systemctl stop nodepass
elif [ "$SERVICE_MANAGE" = "rc-service" ]; then
rc-service nodepass stop
elif [ "$SERVICE_MANAGE" = "init.d" ]; then
/etc/init.d/nodepass stop
fi
sleep 2
}
# 处理旧应用名
compatibility_old_binary() {
# 检查旧文件是否存在
[ -f "$WORK_DIR/stable-nodepass" ] && mv "$WORK_DIR/stable-nodepass" "$WORK_DIR/np-stb"
[ -f "$WORK_DIR/dev-nodepass" ] && mv "$WORK_DIR/dev-nodepass" "$WORK_DIR/np-dev"
# 检查软链接指向的文件
if [ -L "$WORK_DIR/nodepass" ]; then
local CURRENT_SYMLINK=$(readlink "$WORK_DIR/nodepass")
# 根据软链接指向的旧文件名更新为新文件名
if [[ "$CURRENT_SYMLINK" == *"stable-nodepass"* ]]; then
ln -sf "$WORK_DIR/np-stb" "$WORK_DIR/nodepass"
elif [[ "$CURRENT_SYMLINK" == *"dev-nodepass"* ]]; then
ln -sf "$WORK_DIR/np-dev" "$WORK_DIR/nodepass"
fi
fi
# 如果缺少LTS版本,下载它
if [ -d $WORK_DIR ] && ! [ -f "$WORK_DIR/np-lts" ]; then
# 获取LTS版本信息
get_latest_version
if [ "$DOWNLOAD_TOOL" = "curl" ]; then
curl -sL "${GH_PROXY}https://github.com/NodePassProject/nodepass/releases/download/${LTS_LATEST_VERSION}/nodepass_${LTS_VERSION_NUM}_linux_${ARCH}.tar.gz" | tar -xz -C "$TEMP_DIR"
else
wget "${GH_PROXY}https://github.com/NodePassProject/nodepass/releases/download/${LTS_LATEST_VERSION}/nodepass_${LTS_VERSION_NUM}_linux_${ARCH}.tar.gz" -qO- | tar -xz -C "$TEMP_DIR"
fi
[ -s "$TEMP_DIR/nodepass" ] && mv "$TEMP_DIR/nodepass" "$WORK_DIR/np-lts" && chmod +x "$WORK_DIR/np-lts"
get_local_version
fi
}
# 升级 NodePass
upgrade_nodepass() {
# 获取本地版本
get_local_version all
# 获取远程最新版本
get_latest_version
info "\n $(text 45) "
info " $(text 46) "
# 检查是否有可用更新
local HAS_UPGRADE=0
local HAS_STABLE_UPGRADE=0
local HAS_DEV_UPGRADE=0
local HAS_LTS_UPGRADE=0
# 显示可切换的版本选项
local OPTION_INDEX=1
local AVAILABLE_INDICES=()
local UPGRADE_INFO=""
# 检查稳定版是否有更新
if [ -n "$STABLE_LOCAL_VERSION" ] && [ -n "$STABLE_LATEST_VERSION" ] && [ "$STABLE_LOCAL_VERSION" != "$STABLE_LATEST_VERSION" ]; then
HAS_UPGRADE=1
HAS_STABLE_UPGRADE=1
UPGRADE_INFO+="\n $(text 92) "
fi
# 检查开发版是否有更新
if [ -n "$DEV_LOCAL_VERSION" ] && [ -n "$DEV_LATEST_VERSION" ] && [ "$DEV_LOCAL_VERSION" != "$DEV_LATEST_VERSION" ]; then
HAS_UPGRADE=1
HAS_DEV_UPGRADE=1
UPGRADE_INFO+="\n $(text 93) "
fi
# 检查经典版(LTS)是否有更新
if [ -n "$LTS_LOCAL_VERSION" ] && [ -n "$LTS_LATEST_VERSION" ] && [ "$LTS_LOCAL_VERSION" != "$LTS_LATEST_VERSION" ]; then
HAS_UPGRADE=1
HAS_LTS_UPGRADE=1
UPGRADE_INFO+="\n $(text 99) "
fi
# 如果有更新,提示用户
if [ "$HAS_UPGRADE" = 1 ]; then
info " $(text 94) "
echo -e "$UPGRADE_INFO"
reading "\n $(text 48) " UPGRADE_CHOICE
if [ "${UPGRADE_CHOICE,,}" != "y" ]; then
info " $(text 49) "
exit 0
fi
else
info " $(text 91) "
exit 0
fi
# 确定是否需要重启服务
local NEED_RESTART=0
# 如果当前运行的是开发版,且开发版有更新,则需要重启
if [ "$VERSION_TYPE_TEXT" = "$(text 67)" ] && [ "$HAS_STABLE_UPGRADE" = 1 ]; then
NEED_RESTART=1
# 如果当前运行的是稳定版,且稳定版有更新,则需要重启
elif [ "$VERSION_TYPE_TEXT" = "$(text 66)" ] && [ "$HAS_DEV_UPGRADE" = 1 ]; then
NEED_RESTART=1
# 如果当前运行的是经典版,且经典版有更新,则需要重启
elif [ "$VERSION_TYPE_TEXT" = "$(text 98)" ] && [ "$HAS_LTS_UPGRADE" = 1 ]; then
NEED_RESTART=1
# 如果三个版本都有更新,则需要重启
elif [ "$HAS_STABLE_UPGRADE" = 1 ] && [ "$HAS_DEV_UPGRADE" = 1 ] && [ "$HAS_LTS_UPGRADE" = 1 ]; then
NEED_RESTART=1
fi
# 如果需要重启服务,则停止服务
[ "$NEED_RESTART" = 1 ] && stop_nodepass
# 备份旧版本
[ "$HAS_STABLE_UPGRADE" = 1 ] && cp "$WORK_DIR/np-stb" "$WORK_DIR/np-stb.old" 2>/dev/null
[ "$HAS_DEV_UPGRADE" = 1 ] && cp "$WORK_DIR/np-dev" "$WORK_DIR/np-dev.old" 2>/dev/null
[ "$HAS_LTS_UPGRADE" = 1 ] && cp "$WORK_DIR/np-lts" "$WORK_DIR/np-lts.old" 2>/dev/null
# 下载并解压新版本
local DOWNLOAD_SUCCESS=1
if [ "$DOWNLOAD_TOOL" = "curl" ]; then
# 下载稳定版
if [ "$HAS_STABLE_UPGRADE" = 1 ]; then
curl -sL "${GH_PROXY}https://github.com/NodePassProject/nodepass/releases/download/${STABLE_LATEST_VERSION}/nodepass_${STABLE_VERSION_NUM}_linux_${ARCH}.tar.gz" | tar -xz -C "$TEMP_DIR"
if [ -f "$TEMP_DIR/nodepass" ]; then
mv "$TEMP_DIR/nodepass" "$WORK_DIR/np-stb"
chmod +x "$WORK_DIR/np-stb"
else
DOWNLOAD_SUCCESS=0
fi
fi
# 下载开发版
if [ "$HAS_DEV_UPGRADE" = 1 ]; then
curl -sL "${GH_PROXY}https://github.com/NodePassProject/nodepass/releases/download/${DEV_LATEST_VERSION}/nodepass_${DEV_VERSION_NUM}_linux_${ARCH}.tar.gz" | tar -xz -C "$TEMP_DIR"
if [ -f "$TEMP_DIR/nodepass" ]; then
mv "$TEMP_DIR/nodepass" "$WORK_DIR/np-dev"
chmod +x "$WORK_DIR/np-dev"
else
DOWNLOAD_SUCCESS=0
fi
fi
# 下载经典版(LTS)
if [ "$HAS_LTS_UPGRADE" = 1 ]; then
curl -sL "${GH_PROXY}https://github.com/NodePassProject/nodepass/releases/download/${LTS_LATEST_VERSION}/nodepass_${LTS_VERSION_NUM}_linux_${ARCH}.tar.gz" | tar -xz -C "$TEMP_DIR"
if [ -f "$TEMP_DIR/nodepass" ]; then