| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | <!DOCTYPE html> | 
					
						
							|  |  |  | <html lang="en"> | 
					
						
							|  |  |  | {{template "head" .}} | 
					
						
							|  |  |  | <style> | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |   @media (min-width: 769px) { | 
					
						
							|  |  |  |     .ant-layout-content { | 
					
						
							|  |  |  |       margin: 24px 16px; | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |   } | 
					
						
							|  |  |  |   @media (max-width: 768px) { | 
					
						
							|  |  |  |     .ant-tabs-nav .ant-tabs-tab { | 
					
						
							|  |  |  |       margin: 0; | 
					
						
							|  |  |  |       padding: 12px .5rem; | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |   } | 
					
						
							|  |  |  |   .ant-tabs-bar { | 
					
						
							|  |  |  |     margin: 0; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   .ant-list-item { | 
					
						
							|  |  |  |     display: block; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   .alert-msg { | 
					
						
							|  |  |  |     color: rgb(194, 117, 18); | 
					
						
							|  |  |  |     font-weight: normal; | 
					
						
							|  |  |  |     font-size: 16px; | 
					
						
							|  |  |  |     padding: .5rem 1rem; | 
					
						
							|  |  |  |     text-align: center; | 
					
						
							|  |  |  |     background: rgb(255 145 0 / 15%); | 
					
						
							| 
									
										
										
										
											2024-11-11 21:58:00 +00:00
										 |  |  |     margin: 1.5rem 2.5rem 0rem; | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |     border-radius: .5rem; | 
					
						
							|  |  |  |     transition: all 0.5s; | 
					
						
							|  |  |  |     animation: signal 3s cubic-bezier(0.18, 0.89, 0.32, 1.28) infinite; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   .alert-msg:hover { | 
					
						
							|  |  |  |     cursor: default; | 
					
						
							|  |  |  |     transition-duration: .3s; | 
					
						
							|  |  |  |     animation: signal 0.9s ease infinite; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   @keyframes signal { | 
					
						
							|  |  |  |     0% { | 
					
						
							|  |  |  |       box-shadow: 0 0 0 0 rgba(194, 118, 18, 0.5); | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |     50% { | 
					
						
							|  |  |  |       box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |     100% { | 
					
						
							|  |  |  |       box-shadow: 0 0 0 6px rgba(0, 0, 0, 0); | 
					
						
							| 
									
										
										
										
											2023-05-20 14:27:10 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |   } | 
					
						
							|  |  |  |   .alert-msg>i { | 
					
						
							|  |  |  |     color: inherit; | 
					
						
							|  |  |  |     font-size: 24px; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |   .dark .ant-input-password-icon { | 
					
						
							|  |  |  |     color: var(--dark-color-text-primary); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2025-04-06 22:45:52 +00:00
										 |  |  |   .ant-collapse-content-box .ant-alert { | 
					
						
							|  |  |  |     margin-block-end: 12px; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | </style> | 
					
						
							|  |  |  | <body> | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |   <a-layout id="app" v-cloak :class="themeSwitcher.currentTheme"> | 
					
						
							| 
									
										
										
										
											2025-03-24 11:19:27 +00:00
										 |  |  |     <a-sidebar></a-sidebar> | 
					
						
							| 
									
										
										
										
											2023-12-04 18:17:38 +00:00
										 |  |  |     <a-layout id="content-layout"> | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |       <a-layout-content> | 
					
						
							|  |  |  |         <a-spin :spinning="spinning" :delay="500" tip='{{ i18n "loading"}}'> | 
					
						
							|  |  |  |           <transition name="list" appear> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |             <a-alert type="error" v-if="confAlerts.length>0" :style="{ marginBottom: '10px' }" | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |                 message='{{ i18n "secAlertTitle" }}' | 
					
						
							|  |  |  |                 color="red" | 
					
						
							|  |  |  |                 show-icon closable> | 
					
						
							|  |  |  |               <template slot="description"> | 
					
						
							|  |  |  |                 <b>{{ i18n "secAlertConf" }}</b> | 
					
						
							|  |  |  |                 <ul><li v-for="a in confAlerts">[[ a ]]</li></ul> | 
					
						
							|  |  |  |               </template> | 
					
						
							|  |  |  |             </a-alert> | 
					
						
							|  |  |  |           </transition> | 
					
						
							|  |  |  |           <a-space direction="vertical"> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |             <a-card hoverable :style="{ marginBottom: '.5rem', overflowX: 'hidden' }"> | 
					
						
							|  |  |  |               <a-row :style="{ display: 'flex', flexWrap: 'wrap', alignItems: 'center' }"> | 
					
						
							|  |  |  |                 <a-col :xs="24" :sm="10" :style="{ padding: '4px' }"> | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |                   <a-space direction="horizontal"> | 
					
						
							|  |  |  |                     <a-button type="primary" :disabled="saveBtnDisable" @click="updateAllSetting">{{ i18n "pages.settings.save" }}</a-button> | 
					
						
							|  |  |  |                     <a-button type="danger" :disabled="!saveBtnDisable" @click="restartPanel">{{ i18n "pages.settings.restartPanel" }}</a-button> | 
					
						
							|  |  |  |                   </a-space> | 
					
						
							|  |  |  |                 </a-col> | 
					
						
							|  |  |  |                 <a-col :xs="24" :sm="14"> | 
					
						
							|  |  |  |                   <template> | 
					
						
							|  |  |  |                     <div> | 
					
						
							|  |  |  |                       <a-back-top :target="() => document.getElementById('content-layout')" visibility-height="200"></a-back-top> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |                       <a-alert type="warning" :style="{ float: 'right', width: 'fit-content' }" | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |                         message='{{ i18n "pages.settings.infoDesc" }}' | 
					
						
							|  |  |  |                         show-icon> | 
					
						
							|  |  |  |                       </a-alert> | 
					
						
							|  |  |  |                     </div> | 
					
						
							|  |  |  |                   </template> | 
					
						
							|  |  |  |                 </a-col> | 
					
						
							|  |  |  |               </a-row> | 
					
						
							|  |  |  |             </a-card> | 
					
						
							|  |  |  |             <a-tabs default-active-key="1"> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |               <a-tab-pane key="1" tab='{{ i18n "pages.settings.panelSettings" }}' :style="{ paddingTop: '20px' }"> | 
					
						
							| 
									
										
										
										
											2025-03-24 09:45:15 +00:00
										 |  |  |                 {{ template "settings/panel/general" . }} | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |               </a-tab-pane> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |               <a-tab-pane key="2" tab='{{ i18n "pages.settings.securitySettings" }}' :style="{ paddingTop: '20px' }"> | 
					
						
							| 
									
										
										
										
											2025-03-24 09:45:15 +00:00
										 |  |  |                 {{ template "settings/panel/security" . }} | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |               </a-tab-pane> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |               <a-tab-pane key="3" tab='{{ i18n "pages.settings.TGBotSettings" }}' :style="{ paddingTop: '20px' }"> | 
					
						
							| 
									
										
										
										
											2025-03-24 09:45:15 +00:00
										 |  |  |                 {{ template "settings/panel/telegram" . }} | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |               </a-tab-pane> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |               <a-tab-pane key="4" tab='{{ i18n "pages.settings.subSettings" }}' :style="{ paddingTop: '20px' }"> | 
					
						
							| 
									
										
										
										
											2025-03-24 09:45:15 +00:00
										 |  |  |                 {{ template "settings/panel/subscription/general" . }} | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |               </a-tab-pane> | 
					
						
							| 
									
										
										
										
											2025-04-06 09:40:33 +00:00
										 |  |  |               <a-tab-pane key="5" tab='{{ i18n "pages.settings.subSettings" }} Json' v-if="allSetting.subEnable" :style="{ paddingTop: '20px' }"> | 
					
						
							| 
									
										
										
										
											2025-03-24 09:45:15 +00:00
										 |  |  |                 {{ template "settings/panel/subscription/json" . }} | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |               </a-tab-pane> | 
					
						
							|  |  |  |             </a-tabs> | 
					
						
							|  |  |  |           </a-space> | 
					
						
							|  |  |  |         </a-spin> | 
					
						
							|  |  |  |       </a-layout-content> | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  |     </a-layout> | 
					
						
							| 
									
										
										
										
											2024-03-20 10:43:37 +00:00
										 |  |  |   </a-layout> | 
					
						
							| 
									
										
										
										
											2023-05-08 14:44:22 +00:00
										 |  |  | {{template "js" .}} | 
					
						
							| 
									
										
										
										
											2025-05-08 14:20:58 +00:00
										 |  |  | <script src="{{ .base_path }}assets/qrcode/qrious2.min.js?{{ .cur_ver }}"></script> | 
					
						
							|  |  |  | <script src="{{ .base_path }}assets/otpauth/otpauth.umd.min.js?{{ .cur_ver }}"></script> | 
					
						
							| 
									
										
										
										
											2023-12-05 17:13:36 +00:00
										 |  |  | <script src="{{ .base_path }}assets/js/model/setting.js?{{ .cur_ver }}"></script> | 
					
						
							| 
									
										
										
										
											2025-03-24 11:19:27 +00:00
										 |  |  | {{template "component/aSidebar" .}} | 
					
						
							| 
									
										
										
										
											2025-03-17 11:26:07 +00:00
										 |  |  | {{template "component/aThemeSwitch" .}} | 
					
						
							|  |  |  | {{template "component/aSettingListItem" .}} | 
					
						
							| 
									
										
										
										
											2025-05-08 14:20:58 +00:00
										 |  |  | {{template "modals/twoFactorModal"}} | 
					
						
							| 
									
										
										
										
											2023-05-08 14:44:22 +00:00
										 |  |  | <script> | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |   const app = new Vue({ | 
					
						
							|  |  |  |     delimiters: ['[[', ']]'], | 
					
						
							|  |  |  |     el: '#app', | 
					
						
							|  |  |  |     data: { | 
					
						
							|  |  |  |       themeSwitcher, | 
					
						
							|  |  |  |       spinning: false, | 
					
						
							|  |  |  |       oldAllSetting: new AllSetting(), | 
					
						
							|  |  |  |       allSetting: new AllSetting(), | 
					
						
							|  |  |  |       saveBtnDisable: true, | 
					
						
							|  |  |  |       user: {}, | 
					
						
							| 
									
										
										
										
											2025-03-08 02:54:41 +00:00
										 |  |  |       lang: LanguageManager.getLanguage(), | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |       remarkModels: { i: 'Inbound', e: 'Email', o: 'Other' }, | 
					
						
							|  |  |  |       remarkSeparators: [' ', '-', '_', '@', ':', '~', '|', ',', '.', '/'], | 
					
						
							|  |  |  |       datepickerList: [{ name: 'Gregorian (Standard)', value: 'gregorian' }, { name: 'Jalalian (شمسی)', value: 'jalalian' }], | 
					
						
							|  |  |  |       remarkSample: '', | 
					
						
							|  |  |  |       defaultFragment: { | 
					
						
							|  |  |  |         tag: "fragment", | 
					
						
							|  |  |  |         protocol: "freedom", | 
					
						
							|  |  |  |         settings: { | 
					
						
							|  |  |  |           domainStrategy: "AsIs", | 
					
						
							|  |  |  |           fragment: { | 
					
						
							|  |  |  |             packets: "tlshello", | 
					
						
							|  |  |  |             length: "100-200", | 
					
						
							|  |  |  |             interval: "10-20" | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2023-05-08 14:44:22 +00:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         streamSettings: { | 
					
						
							|  |  |  |           sockopt: { | 
					
						
							|  |  |  |             tcpKeepAliveIdle: 100, | 
					
						
							| 
									
										
										
										
											2024-05-22 16:35:46 +00:00
										 |  |  |             tcpMptcp: true, | 
					
						
							| 
									
										
										
										
											2025-01-01 17:42:50 +00:00
										 |  |  |             penetrate: true | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-09-17 07:33:44 +00:00
										 |  |  |       defaultNoises: { | 
					
						
							|  |  |  |         tag: "noises", | 
					
						
							| 
									
										
										
										
											2024-08-29 09:27:43 +00:00
										 |  |  |         protocol: "freedom", | 
					
						
							|  |  |  |         settings: { | 
					
						
							|  |  |  |           domainStrategy: "AsIs", | 
					
						
							| 
									
										
										
										
											2024-09-24 09:38:10 +00:00
										 |  |  |           noises: [ | 
					
						
							|  |  |  |             { type: "rand", packet: "10-20", delay: "10-16" }, | 
					
						
							|  |  |  |           ], | 
					
						
							| 
									
										
										
										
											2024-08-29 09:27:43 +00:00
										 |  |  |         }, | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |       defaultMux: { | 
					
						
							|  |  |  |         enabled: true, | 
					
						
							|  |  |  |         concurrency: 8, | 
					
						
							|  |  |  |         xudpConcurrency: 16, | 
					
						
							|  |  |  |         xudpProxyUDP443: "reject" | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       defaultRules: [ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           type: "field", | 
					
						
							|  |  |  |           outboundTag: "direct", | 
					
						
							|  |  |  |           domain: [ | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |             "geosite:category-ir" | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           ] | 
					
						
							| 
									
										
										
										
											2023-05-08 14:44:22 +00:00
										 |  |  |         }, | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         { | 
					
						
							|  |  |  |           type: "field", | 
					
						
							|  |  |  |           outboundTag: "direct", | 
					
						
							|  |  |  |           ip: [ | 
					
						
							|  |  |  |             "geoip:private", | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |             "geoip:ir" | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           ] | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         }, | 
					
						
							|  |  |  |       ], | 
					
						
							| 
									
										
										
										
											2025-01-26 18:43:02 +00:00
										 |  |  |       directIPsOptions: [ | 
					
						
							|  |  |  |         { label: 'Private IP', value: 'geoip:private' }, | 
					
						
							|  |  |  |         { label: '🇮🇷 Iran', value: 'geoip:ir' }, | 
					
						
							|  |  |  |         { label: '🇨🇳 China', value: 'geoip:cn' }, | 
					
						
							|  |  |  |         { label: '🇷🇺 Russia', value: 'geoip:ru' }, | 
					
						
							|  |  |  |         { label: '🇻🇳 Vietnam', value: 'geoip:vn' }, | 
					
						
							|  |  |  |         { label: '🇪🇸 Spain', value: 'geoip:es' }, | 
					
						
							|  |  |  |         { label: '🇮🇩 Indonesia', value: 'geoip:id' }, | 
					
						
							|  |  |  |         { label: '🇺🇦 Ukraine', value: 'geoip:ua' }, | 
					
						
							|  |  |  |         { label: '🇹🇷 Türkiye', value: 'geoip:tr' }, | 
					
						
							|  |  |  |         { label: '🇧🇷 Brazil', value: 'geoip:br' }, | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |       ], | 
					
						
							| 
									
										
										
										
											2025-01-26 18:43:02 +00:00
										 |  |  |       diretDomainsOptions: [ | 
					
						
							|  |  |  |         { label: 'Private DNS', value: 'geosite:private' }, | 
					
						
							|  |  |  |         { label: '🇮🇷 Iran', value: 'geosite:category-ir' }, | 
					
						
							|  |  |  |         { label: '🇨🇳 China', value: 'geosite:cn' }, | 
					
						
							|  |  |  |         { label: '🇷🇺 Russia', value: 'geosite:category-ru' }, | 
					
						
							|  |  |  |         { label: 'Apple', value: 'geosite:apple' }, | 
					
						
							|  |  |  |         { label: 'Meta', value: 'geosite:meta' }, | 
					
						
							|  |  |  |         { label: 'Google', value: 'geosite:google' }, | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |       ], | 
					
						
							|  |  |  |       get remarkModel() { | 
					
						
							|  |  |  |         rm = this.allSetting.remarkModel; | 
					
						
							|  |  |  |         return rm.length > 1 ? rm.substring(1).split('') : []; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       set remarkModel(value) { | 
					
						
							|  |  |  |         rs = this.allSetting.remarkModel[0]; | 
					
						
							|  |  |  |         this.allSetting.remarkModel = rs + value.join(''); | 
					
						
							|  |  |  |         this.changeRemarkSample(); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       get remarkSeparator() { | 
					
						
							|  |  |  |         return this.allSetting.remarkModel.length > 1 ? this.allSetting.remarkModel.charAt(0) : '-'; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       set remarkSeparator(value) { | 
					
						
							|  |  |  |         this.allSetting.remarkModel = value + this.allSetting.remarkModel.substring(1); | 
					
						
							|  |  |  |         this.changeRemarkSample(); | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       get datepicker() { | 
					
						
							|  |  |  |         return this.allSetting.datepicker ? this.allSetting.datepicker : 'gregorian'; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       set datepicker(value) { | 
					
						
							|  |  |  |         this.allSetting.datepicker = value; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       changeRemarkSample() { | 
					
						
							|  |  |  |         sample = [] | 
					
						
							|  |  |  |         this.remarkModel.forEach(r => sample.push(this.remarkModels[r])); | 
					
						
							|  |  |  |         this.remarkSample = sample.length == 0 ? '' : sample.join(this.remarkSeparator); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     methods: { | 
					
						
							|  |  |  |       loading(spinning = true) { | 
					
						
							|  |  |  |         this.spinning = spinning; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       async getAllSetting() { | 
					
						
							|  |  |  |         this.loading(true); | 
					
						
							|  |  |  |         const msg = await HttpUtil.post("/panel/setting/all"); | 
					
						
							|  |  |  |         this.loading(false); | 
					
						
							|  |  |  |         if (msg.success) { | 
					
						
							|  |  |  |           this.oldAllSetting = new AllSetting(msg.obj); | 
					
						
							|  |  |  |           this.allSetting = new AllSetting(msg.obj); | 
					
						
							|  |  |  |           app.changeRemarkSample(); | 
					
						
							|  |  |  |           this.saveBtnDisable = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       async updateAllSetting() { | 
					
						
							|  |  |  |         this.loading(true); | 
					
						
							|  |  |  |         const msg = await HttpUtil.post("/panel/setting/update", this.allSetting); | 
					
						
							|  |  |  |         this.loading(false); | 
					
						
							|  |  |  |         if (msg.success) { | 
					
						
							|  |  |  |           await this.getAllSetting(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       async updateUser() { | 
					
						
							|  |  |  |         this.loading(true); | 
					
						
							|  |  |  |         const msg = await HttpUtil.post("/panel/setting/updateUser", this.user); | 
					
						
							|  |  |  |         this.loading(false); | 
					
						
							|  |  |  |         if (msg.success) { | 
					
						
							|  |  |  |           this.user = {}; | 
					
						
							| 
									
										
										
										
											2024-07-05 12:33:04 +00:00
										 |  |  |           window.location.replace(basePath + "logout"); | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       async restartPanel() { | 
					
						
							|  |  |  |         await new Promise(resolve => { | 
					
						
							|  |  |  |           this.$confirm({ | 
					
						
							|  |  |  |             title: '{{ i18n "pages.settings.restartPanel" }}', | 
					
						
							|  |  |  |             content: '{{ i18n "pages.settings.restartPanelDesc" }}', | 
					
						
							|  |  |  |             class: themeSwitcher.currentTheme, | 
					
						
							|  |  |  |             okText: '{{ i18n "sure" }}', | 
					
						
							|  |  |  |             cancelText: '{{ i18n "cancel" }}', | 
					
						
							|  |  |  |             onOk: () => resolve(), | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         this.loading(true); | 
					
						
							|  |  |  |         const msg = await HttpUtil.post("/panel/setting/restartPanel"); | 
					
						
							|  |  |  |         this.loading(false); | 
					
						
							|  |  |  |         if (msg.success) { | 
					
						
							|  |  |  |           this.loading(true); | 
					
						
							|  |  |  |           await PromiseUtil.sleep(5000); | 
					
						
							| 
									
										
										
										
											2024-08-10 22:47:44 +00:00
										 |  |  |           var { webCertFile, webKeyFile, webDomain: host, webPort: port, webBasePath: base } = this.allSetting; | 
					
						
							|  |  |  |           if (host == this.oldAllSetting.webDomain) host = null; | 
					
						
							|  |  |  |           if (port == this.oldAllSetting.webPort) port = null; | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |           const isTLS = webCertFile !== "" || webKeyFile !== ""; | 
					
						
							| 
									
										
										
										
											2025-03-07 09:07:23 +00:00
										 |  |  |           const url = URLBuilder.buildURL({ host, port, isTLS, base, path: "panel/settings" }); | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |           window.location.replace(url); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2025-05-08 14:20:58 +00:00
										 |  |  |       toggleTwoFactor(newValue) { | 
					
						
							|  |  |  |         if (newValue) { | 
					
						
							|  |  |  |           const newTwoFactorToken = RandomUtil.randomBase32String() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           twoFactorModal.show({ | 
					
						
							|  |  |  |             title: '{{ i18n "pages.settings.security.twoFactorModalSetTitle" }}', | 
					
						
							|  |  |  |             token: newTwoFactorToken, | 
					
						
							|  |  |  |             type: 'set', | 
					
						
							|  |  |  |             confirm: (success) => { | 
					
						
							|  |  |  |               if (success) { | 
					
						
							|  |  |  |                 this.allSetting.twoFactorToken = newTwoFactorToken | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               this.allSetting.twoFactorEnable = success | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }) | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2025-05-08 14:20:58 +00:00
										 |  |  |           twoFactorModal.show({ | 
					
						
							|  |  |  |             title: '{{ i18n "pages.settings.security.twoFactorModalDeleteTitle" }}', | 
					
						
							|  |  |  |             token: this.allSetting.twoFactorToken, | 
					
						
							|  |  |  |             type: 'remove', | 
					
						
							|  |  |  |             confirm: (success) => { | 
					
						
							|  |  |  |               if (success) { | 
					
						
							|  |  |  |                 this.allSetting.twoFactorEnable = false | 
					
						
							|  |  |  |                 this.allSetting.twoFactorToken = "" | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           }) | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-09-24 09:38:10 +00:00
										 |  |  |       addNoise() { | 
					
						
							|  |  |  |         const newNoise = { type: "rand", packet: "10-20", delay: "10-16" }; | 
					
						
							|  |  |  |         this.noisesArray = [...this.noisesArray, newNoise]; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       removeNoise(index) { | 
					
						
							|  |  |  |         const newNoises = [...this.noisesArray]; | 
					
						
							|  |  |  |         newNoises.splice(index, 1); | 
					
						
							|  |  |  |         this.noisesArray = newNoises; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       updateNoiseType(index, value) { | 
					
						
							|  |  |  |         const updatedNoises = [...this.noisesArray]; | 
					
						
							|  |  |  |         updatedNoises[index] = { ...updatedNoises[index], type: value }; | 
					
						
							|  |  |  |         this.noisesArray = updatedNoises; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       updateNoisePacket(index, value) { | 
					
						
							|  |  |  |         const updatedNoises = [...this.noisesArray]; | 
					
						
							|  |  |  |         updatedNoises[index] = { ...updatedNoises[index], packet: value }; | 
					
						
							|  |  |  |         this.noisesArray = updatedNoises; | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       updateNoiseDelay(index, value) { | 
					
						
							|  |  |  |         const updatedNoises = [...this.noisesArray]; | 
					
						
							|  |  |  |         updatedNoises[index] = { ...updatedNoises[index], delay: value }; | 
					
						
							|  |  |  |         this.noisesArray = updatedNoises; | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |     }, | 
					
						
							|  |  |  |     computed: { | 
					
						
							|  |  |  |       fragment: { | 
					
						
							|  |  |  |         get: function () { return this.allSetting?.subJsonFragment != ""; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           this.allSetting.subJsonFragment = v ? JSON.stringify(this.defaultFragment) : ""; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       fragmentPackets: { | 
					
						
							|  |  |  |         get: function () { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.packets : ""; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           if (v != "") { | 
					
						
							|  |  |  |             newFragment = JSON.parse(this.allSetting.subJsonFragment); | 
					
						
							|  |  |  |             newFragment.settings.fragment.packets = v; | 
					
						
							|  |  |  |             this.allSetting.subJsonFragment = JSON.stringify(newFragment); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       fragmentLength: { | 
					
						
							|  |  |  |         get: function () { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.length : ""; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           if (v != "") { | 
					
						
							|  |  |  |             newFragment = JSON.parse(this.allSetting.subJsonFragment); | 
					
						
							|  |  |  |             newFragment.settings.fragment.length = v; | 
					
						
							|  |  |  |             this.allSetting.subJsonFragment = JSON.stringify(newFragment); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       fragmentInterval: { | 
					
						
							|  |  |  |         get: function () { return this.fragment ? JSON.parse(this.allSetting.subJsonFragment).settings.fragment.interval : ""; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           if (v != "") { | 
					
						
							|  |  |  |             newFragment = JSON.parse(this.allSetting.subJsonFragment); | 
					
						
							|  |  |  |             newFragment.settings.fragment.interval = v; | 
					
						
							|  |  |  |             this.allSetting.subJsonFragment = JSON.stringify(newFragment); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-09-17 07:33:44 +00:00
										 |  |  |       noises: { | 
					
						
							| 
									
										
										
										
											2024-09-24 09:38:10 +00:00
										 |  |  |         get() { | 
					
						
							|  |  |  |           return this.allSetting?.subJsonNoises != ""; | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         set(v) { | 
					
						
							|  |  |  |           if (v) { | 
					
						
							|  |  |  |             this.allSetting.subJsonNoises = JSON.stringify(this.defaultNoises); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             this.allSetting.subJsonNoises = ""; | 
					
						
							| 
									
										
										
										
											2024-08-29 09:27:43 +00:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-09-24 09:38:10 +00:00
										 |  |  |       noisesArray: { | 
					
						
							|  |  |  |         get() { | 
					
						
							|  |  |  |           return this.noises ? JSON.parse(this.allSetting.subJsonNoises).settings.noises : []; | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         set(value) { | 
					
						
							|  |  |  |           if (this.noises) { | 
					
						
							|  |  |  |             const newNoises = JSON.parse(this.allSetting.subJsonNoises); | 
					
						
							|  |  |  |             newNoises.settings.noises = value; | 
					
						
							| 
									
										
										
										
											2024-09-17 07:33:44 +00:00
										 |  |  |             this.allSetting.subJsonNoises = JSON.stringify(newNoises); | 
					
						
							| 
									
										
										
										
											2024-08-29 09:27:43 +00:00
										 |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |       enableMux: { | 
					
						
							|  |  |  |         get: function () { return this.allSetting?.subJsonMux != ""; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           this.allSetting.subJsonMux = v ? JSON.stringify(this.defaultMux) : ""; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       muxConcurrency: { | 
					
						
							|  |  |  |         get: function () { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).concurrency : -1; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           newMux = JSON.parse(this.allSetting.subJsonMux); | 
					
						
							|  |  |  |           newMux.concurrency = v; | 
					
						
							|  |  |  |           this.allSetting.subJsonMux = JSON.stringify(newMux); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       muxXudpConcurrency: { | 
					
						
							|  |  |  |         get: function () { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpConcurrency : -1; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           newMux = JSON.parse(this.allSetting.subJsonMux); | 
					
						
							|  |  |  |           newMux.xudpConcurrency = v; | 
					
						
							|  |  |  |           this.allSetting.subJsonMux = JSON.stringify(newMux); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       muxXudpProxyUDP443: { | 
					
						
							|  |  |  |         get: function () { return this.enableMux ? JSON.parse(this.allSetting.subJsonMux).xudpProxyUDP443 : "reject"; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           newMux = JSON.parse(this.allSetting.subJsonMux); | 
					
						
							|  |  |  |           newMux.xudpProxyUDP443 = v; | 
					
						
							|  |  |  |           this.allSetting.subJsonMux = JSON.stringify(newMux); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       enableDirect: { | 
					
						
							|  |  |  |         get: function () { return this.allSetting?.subJsonRules != ""; }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							|  |  |  |           this.allSetting.subJsonRules = v ? JSON.stringify(this.defaultRules) : ""; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-10-17 09:25:39 +00:00
										 |  |  |       directIPs: { | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         get: function () { | 
					
						
							|  |  |  |           if (!this.enableDirect) return []; | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |           const rules = JSON.parse(this.allSetting.subJsonRules); | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           if (!Array.isArray(rules)) return []; | 
					
						
							|  |  |  |           const ipRule = rules.find(r => r.ip); | 
					
						
							| 
									
										
										
										
											2025-01-26 18:43:02 +00:00
										 |  |  |           return ipRule?.ip ?? []; | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |         }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           let rules = JSON.parse(this.allSetting.subJsonRules); | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |           if (!Array.isArray(rules)) return; | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           if (v.length == 0) { | 
					
						
							|  |  |  |             rules = rules.filter(r => !r.ip); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             let ruleIndex = rules.findIndex(r => r.ip); | 
					
						
							|  |  |  |             if (ruleIndex == -1) ruleIndex = rules.push(this.defaultRules[1]) - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rules[ruleIndex].ip = []; | 
					
						
							|  |  |  |             v.forEach(d => { | 
					
						
							| 
									
										
										
										
											2025-01-26 18:43:02 +00:00
										 |  |  |               rules[ruleIndex].ip.push(d); | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |           this.allSetting.subJsonRules = JSON.stringify(rules); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2024-10-17 09:25:39 +00:00
										 |  |  |       directDomains: { | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |         get: function () { | 
					
						
							|  |  |  |           if (!this.enableDirect) return []; | 
					
						
							|  |  |  |           const rules = JSON.parse(this.allSetting.subJsonRules); | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           if (!Array.isArray(rules)) return []; | 
					
						
							|  |  |  |           const domainRule = rules.find(r => r.domain); | 
					
						
							| 
									
										
										
										
											2025-01-26 18:43:02 +00:00
										 |  |  |           return domainRule?.domain ?? []; | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |         }, | 
					
						
							|  |  |  |         set: function (v) { | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           let rules = JSON.parse(this.allSetting.subJsonRules); | 
					
						
							| 
									
										
										
										
											2024-09-24 12:57:14 +00:00
										 |  |  |           if (!Array.isArray(rules)) return; | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           if (v.length == 0) { | 
					
						
							|  |  |  |             rules = rules.filter(r => !r.domain); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             let ruleIndex = rules.findIndex(r => r.domain); | 
					
						
							|  |  |  |             if (ruleIndex == -1) ruleIndex = rules.push(this.defaultRules[0]) - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-26 18:43:02 +00:00
										 |  |  |             rules[ruleIndex].domain = v; | 
					
						
							| 
									
										
										
										
											2024-10-10 20:33:44 +00:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |           this.allSetting.subJsonRules = JSON.stringify(rules); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }, | 
					
						
							|  |  |  |       confAlerts: { | 
					
						
							|  |  |  |         get: function () { | 
					
						
							|  |  |  |           if (!this.allSetting) return []; | 
					
						
							|  |  |  |           var alerts = [] | 
					
						
							|  |  |  |           if (window.location.protocol !== "https:") alerts.push('{{ i18n "secAlertSSL" }}'); | 
					
						
							|  |  |  |           if (this.allSetting.webPort == 54321) alerts.push('{{ i18n "secAlertPanelPort" }}'); | 
					
						
							|  |  |  |           panelPath = window.location.pathname.split('/').length < 4 | 
					
						
							|  |  |  |           if (panelPath && this.allSetting.webBasePath == '/') alerts.push('{{ i18n "secAlertPanelURI" }}'); | 
					
						
							|  |  |  |           if (this.allSetting.subEnable) { | 
					
						
							|  |  |  |             subPath = this.allSetting.subURI.length > 0 ? new URL(this.allSetting.subURI).pathname : this.allSetting.subPath; | 
					
						
							|  |  |  |             if (subPath == '/sub/') alerts.push('{{ i18n "secAlertSubURI" }}'); | 
					
						
							|  |  |  |             subJsonPath = this.allSetting.subJsonURI.length > 0 ? new URL(this.allSetting.subJsonURI).pathname : this.allSetting.subJsonPath; | 
					
						
							|  |  |  |             if (subJsonPath == '/json/') alerts.push('{{ i18n "secAlertSubJsonURI" }}'); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           return alerts | 
					
						
							| 
									
										
										
										
											2024-02-21 08:36:49 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     async mounted() { | 
					
						
							|  |  |  |       await this.getAllSetting(); | 
					
						
							| 
									
										
										
										
											2025-05-08 14:20:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-02 20:13:16 +00:00
										 |  |  |       while (true) { | 
					
						
							|  |  |  |         await PromiseUtil.sleep(1000); | 
					
						
							|  |  |  |         this.saveBtnDisable = this.oldAllSetting.equals(this.allSetting); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2023-05-08 14:44:22 +00:00
										 |  |  | </script> | 
					
						
							| 
									
										
										
										
											2023-02-09 19:18:06 +00:00
										 |  |  | </body> | 
					
						
							| 
									
										
										
										
											2025-01-26 18:43:02 +00:00
										 |  |  | </html> |