diff --git a/web/html/inbounds.html b/web/html/inbounds.html index fda4aca2..397a510c 100644 --- a/web/html/inbounds.html +++ b/web/html/inbounds.html @@ -845,9 +845,9 @@ }, getClientCounts(dbInbound, inbound) { let clientCount = 0, active = [], deactive = [], depleted = [], expiring = [], online = [], comments = new Map(); - clients = inbound.clients; - clientStats = dbInbound.clientStats - now = new Date().getTime() + const clients = inbound.clients; + const clientStats = dbInbound.clientStats; + const now = new Date().getTime(); if (clients) { clientCount = clients.length; if (dbInbound.enable) { @@ -862,17 +862,19 @@ deactive.push(client.email); } }); - clientStats.forEach(stats => { - const exhausted = stats.total > 0 && (stats.up + stats.down) >= stats.total; - const expired = stats.expiryTime > 0 && stats.expiryTime <= now; - if (expired || exhausted) { - depleted.push(stats.email); - } else { - const expiringSoon = (stats.expiryTime > 0 && (stats.expiryTime - now < this.expireDiff)) || - (stats.total > 0 && (stats.total - (stats.up + stats.down) < this.trafficDiff)); - if (expiringSoon) expiring.push(stats.email); - } - }); + if (Array.isArray(clientStats)) { + clientStats.forEach(stats => { + const exhausted = stats.total > 0 && (stats.up + stats.down) >= stats.total; + const expired = stats.expiryTime > 0 && stats.expiryTime <= now; + if (expired || exhausted) { + depleted.push(stats.email); + } else { + const expiringSoon = (stats.expiryTime > 0 && (stats.expiryTime - now < this.expireDiff)) || + (stats.total > 0 && (stats.total - (stats.up + stats.down) < this.trafficDiff)); + if (expiringSoon) expiring.push(stats.email); + } + }); + } } else { clients.forEach(client => { deactive.push(client.email); @@ -1060,7 +1062,8 @@ }); }, openEditInbound(dbInboundId) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; const inbound = dbInbound.toInbound(); inModal.show({ title: '{{ i18n "pages.inbounds.modifyInbound"}}', @@ -1127,7 +1130,8 @@ await this.submit(`/panel/api/inbounds/update/${dbInbound.id}`, data, inModal); }, openAddClient(dbInboundId) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; clientModal.show({ title: '{{ i18n "pages.client.add"}}', okText: '{{ i18n "pages.client.submitAdd"}}', @@ -1139,7 +1143,8 @@ }); }, openAddBulkClient(dbInboundId) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; clientsBulkModal.show({ title: '{{ i18n "pages.client.bulk"}} ' + dbInbound.remark, okText: '{{ i18n "pages.client.bulk"}}', @@ -1150,11 +1155,11 @@ }); }, openEditClient(dbInboundId, client) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); if (!dbInbound) return; - clients = this.getInboundClients(dbInbound); + const clients = this.getInboundClients(dbInbound); if (!clients || !Array.isArray(clients)) return; - index = this.findIndexOfClient(dbInbound.protocol, clients, client); + const index = this.findIndexOfClient(dbInbound.protocol, clients, client); if (index < 0) return; clientModal.show({ title: '{{ i18n "pages.client.edit"}}', @@ -1195,7 +1200,8 @@ await this.submit(`/panel/api/inbounds/updateClient/${clientId}`, data, clientModal); }, resetTraffic(dbInboundId) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; this.$confirm({ title: '{{ i18n "pages.inbounds.resetTraffic"}}' + ' #' + dbInboundId, content: '{{ i18n "pages.inbounds.resetTrafficContent"}}', @@ -1211,6 +1217,8 @@ }); }, delInbound(dbInboundId) { + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; this.$confirm({ title: '{{ i18n "pages.inbounds.deleteInbound"}}' + ' #' + dbInboundId, content: '{{ i18n "pages.inbounds.deleteInboundContent"}}', @@ -1221,8 +1229,9 @@ }); }, delClient(dbInboundId, client, confirmation = true) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); - clientId = this.getClientId(dbInbound.protocol, client); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; + const clientId = this.getClientId(dbInbound.protocol, client); if (confirmation) { this.$confirm({ title: '{{ i18n "pages.inbounds.deleteClient"}}' + ' ' + client.email, @@ -1274,9 +1283,9 @@ } }, checkFallback(dbInbound) { - newDbInbound = new DBInbound(dbInbound); + const newDbInbound = new DBInbound(dbInbound); if (dbInbound.listen.startsWith("@")) { - rootInbound = this.inbounds.find((i) => + const rootInbound = this.inbounds.find((i) => i.isTcp && ['trojan', 'vless'].includes(i.protocol) && i.settings.fallbacks.find(f => f.dest === dbInbound.listen) @@ -1294,43 +1303,48 @@ return newDbInbound; }, showQrcode(dbInboundId, client) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); - newDbInbound = this.checkFallback(dbInbound); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; + const newDbInbound = this.checkFallback(dbInbound); qrModal.show('{{ i18n "qrCode"}}', newDbInbound, client); }, showInfo(dbInboundId, client) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); if (!dbInbound) return; - index = 0; + let index = 0; if (dbInbound.isMultiUser()) { - inbound = dbInbound.toInbound(); - clients = inbound && inbound.clients ? inbound.clients : null; + const inbound = dbInbound.toInbound(); + const clients = inbound && inbound.clients ? inbound.clients : null; if (clients && Array.isArray(clients)) { index = this.findIndexOfClient(dbInbound.protocol, clients, client); if (index < 0) index = 0; } } - newDbInbound = this.checkFallback(dbInbound); + const newDbInbound = this.checkFallback(dbInbound); infoModal.show(newDbInbound, index); }, switchEnable(dbInboundId, state) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; dbInbound.enable = state; this.submit(`/panel/api/inbounds/update/${dbInboundId}`, dbInbound); }, async switchEnableClient(dbInboundId, client) { - this.loading() - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); - if (!dbInbound) return; - inbound = dbInbound.toInbound(); - clients = inbound && inbound.clients ? inbound.clients : null; - if (!clients || !Array.isArray(clients)) return; - index = this.findIndexOfClient(dbInbound.protocol, clients, client); - if (index < 0 || !clients[index]) return; - clients[index].enable = !clients[index].enable; - clientId = this.getClientId(dbInbound.protocol, clients[index]); - await this.updateClient(clients[index], dbInboundId, clientId); - this.loading(false); + this.loading(); + try { + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; + const inbound = dbInbound.toInbound(); + const clients = inbound && inbound.clients ? inbound.clients : null; + if (!clients || !Array.isArray(clients)) return; + const index = this.findIndexOfClient(dbInbound.protocol, clients, client); + if (index < 0 || !clients[index]) return; + clients[index].enable = !clients[index].enable; + const clientId = this.getClientId(dbInbound.protocol, clients[index]); + await this.updateClient(clients[index], dbInboundId, clientId); + } finally { + this.loading(false); + } }, async submit(url, data, modal) { const msg = await HttpUtil.postWithModal(url, data, modal); @@ -1489,15 +1503,18 @@ return new Date(ts).toLocaleString() }, isRemovable(dbInboundId) { - return this.getInboundClients(this.dbInbounds.find(row => row.id === dbInboundId)).length > 1; + const clients = this.getInboundClients(this.dbInbounds.find(row => row.id === dbInboundId)); + return Array.isArray(clients) && clients.length > 1; }, inboundLinks(dbInboundId) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); - newDbInbound = this.checkFallback(dbInbound); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; + const newDbInbound = this.checkFallback(dbInbound); txtModal.show('{{ i18n "pages.inbounds.export"}}', newDbInbound.genInboundLinks(this.remarkModel), newDbInbound.remark); }, exportSubs(dbInboundId) { const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; const clients = this.getInboundClients(dbInbound); let subLinks = [] if (clients != null) { @@ -1548,7 +1565,8 @@ txtModal.show('{{ i18n "pages.inbounds.export"}}', copyText.join('\r\n'), 'All-Inbounds'); }, copy(dbInboundId) { - dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + const dbInbound = this.dbInbounds.find(row => row.id === dbInboundId); + if (!dbInbound) return; txtModal.show('{{ i18n "pages.inbounds.inboundData" }}', JSON.stringify(dbInbound, null, 2)); }, async startDataRefreshLoop() { @@ -1613,9 +1631,13 @@ this.getClientEmailOptions(); // Initial data fetch - this.getDBInbounds().then(() => { - this.loading(false); - }); + this.getDBInbounds() + .catch((e) => { + console.error(e); + }) + .finally(() => { + this.loading(false); + }); // Setup WebSocket for real-time updates if (window.wsClient) { diff --git a/web/html/index.html b/web/html/index.html index e442a022..4eb4077e 100644 --- a/web/html/index.html +++ b/web/html/index.html @@ -1018,23 +1018,29 @@ }, async openLogs() { logModal.loading = true; - const msg = await HttpUtil.post('/panel/api/server/logs/' + logModal.rows, { level: logModal.level, syslog: logModal.syslog }); - if (!msg.success) { - return; + try { + const msg = await HttpUtil.post('/panel/api/server/logs/' + logModal.rows, { level: logModal.level, syslog: logModal.syslog }); + if (!msg.success) { + return; + } + logModal.show(msg.obj); + await PromiseUtil.sleep(500); + } finally { + logModal.loading = false; } - logModal.show(msg.obj); - await PromiseUtil.sleep(500); - logModal.loading = false; }, async openXrayLogs() { xraylogModal.loading = true; - const msg = await HttpUtil.post('/panel/api/server/xraylogs/' + xraylogModal.rows, { filter: xraylogModal.filter, showDirect: xraylogModal.showDirect, showBlocked: xraylogModal.showBlocked, showProxy: xraylogModal.showProxy }); - if (!msg.success) { - return; + try { + const msg = await HttpUtil.post('/panel/api/server/xraylogs/' + xraylogModal.rows, { filter: xraylogModal.filter, showDirect: xraylogModal.showDirect, showBlocked: xraylogModal.showBlocked, showProxy: xraylogModal.showProxy }); + if (!msg.success) { + return; + } + xraylogModal.show(msg.obj); + await PromiseUtil.sleep(500); + } finally { + xraylogModal.loading = false; } - xraylogModal.show(msg.obj); - await PromiseUtil.sleep(500); - xraylogModal.loading = false; }, downloadXrayLogs() { if (!Array.isArray(this.xraylogModal.logs) || this.xraylogModal.logs.length === 0) { diff --git a/web/html/login.html b/web/html/login.html index a4ceb831..9ef14cb5 100644 --- a/web/html/login.html +++ b/web/html/login.html @@ -167,10 +167,20 @@ }, async mounted() { this.lang = LanguageManager.getLanguage(); - this.twoFactorEnable = await this.getTwoFactorEnable(); - this.turnstileSiteKey = await this.getTurnstileSiteKey(); - if (this.turnstileSiteKey) { - this.$nextTick(() => this.ensureTurnstileRendered()); + try { + this.twoFactorEnable = await this.getTwoFactorEnable(); + this.turnstileSiteKey = await this.getTurnstileSiteKey(); + } finally { + this.loadingStates.fetched = true; + this.$nextTick(() => { + if (!this.animationStarted) { + this.animationStarted = true; + this.initHeadline(); + } + if (this.turnstileSiteKey) { + this.ensureTurnstileRendered(); + } + }); } }, computed: { @@ -248,15 +258,9 @@ const msg = await HttpUtil.post('/getTwoFactorEnable'); if (msg.success) { this.twoFactorEnable = msg.obj; - this.loadingStates.fetched = true; - this.$nextTick(() => { - if (!this.animationStarted) { - this.animationStarted = true; - this.initHeadline(); - } - }); return msg.obj; } + return false; }, initHeadline() { const animationDelay = 2000; diff --git a/web/html/modals/client_bulk_modal.html b/web/html/modals/client_bulk_modal.html index ac0fa011..1726771c 100644 --- a/web/html/modals/client_bulk_modal.html +++ b/web/html/modals/client_bulk_modal.html @@ -150,8 +150,13 @@ delayedStart: false, reset: 0, ok() { - clients = []; - method = clientsBulkModal.emailMethod; + const clients = []; + const method = clientsBulkModal.emailMethod; + let start; + let end; + let prefix; + let useNum; + let postfix; if (method > 1) { start = clientsBulkModal.firstNum; end = clientsBulkModal.lastNum + 1; @@ -163,7 +168,7 @@ useNum = (method > 1); postfix = (method > 2 && clientsBulkModal.emailPostfix.length > 0) ? clientsBulkModal.emailPostfix : ""; for (let i = start; i < end; i++) { - newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol); + const newClient = clientsBulkModal.newClient(clientsBulkModal.dbInbound.protocol); if (method == 4) newClient.email = ""; newClient.email += useNum ? prefix + i.toString() + postfix : prefix + postfix; if (clientsBulkModal.subId.length > 0) newClient.subId = clientsBulkModal.subId; @@ -186,6 +191,9 @@ dbInbound = null, confirm = (inbound, dbInbound) => { } }) { + if (!dbInbound) { + return; + } this.visible = true; this.title = title; this.okText = okText; @@ -213,7 +221,10 @@ case Protocols.VMESS: return new Inbound.VmessSettings.VMESS(); case Protocols.VLESS: return new Inbound.VLESSSettings.VLESS(); case Protocols.TROJAN: return new Inbound.TrojanSettings.Trojan(); - case Protocols.SHADOWSOCKS: return new Inbound.ShadowsocksSettings.Shadowsocks(clientsBulkModal.inbound.settings.shadowsockses[0].method); + case Protocols.SHADOWSOCKS: { + const method = clientsBulkModal.inbound?.settings?.method || ''; + return new Inbound.ShadowsocksSettings.Shadowsocks(method, RandomUtil.randomShadowsocksPassword(method)); + } default: return null; } }, @@ -247,4 +258,4 @@ }); -{{end}} \ No newline at end of file +{{end}} diff --git a/web/html/modals/client_modal.html b/web/html/modals/client_modal.html index 27364d96..b9a58d1e 100644 --- a/web/html/modals/client_modal.html +++ b/web/html/modals/client_modal.html @@ -32,6 +32,9 @@ } }, show({ title = '', okText = '{{ i18n "sure" }}', index = null, dbInbound = null, confirm = () => { }, isEdit = false }) { + if (!dbInbound) { + return; + } this.visible = true; this.title = title; this.okText = okText; @@ -42,14 +45,22 @@ this.index = index === null ? this.clients.length : index; this.delayedStart = false; if (isEdit) { - if (this.clients[index].expiryTime < 0) { + const currentClient = this.clients[index]; + if (!currentClient) { + this.visible = false; + return; + } + if (currentClient.expiryTime < 0) { this.delayedStart = true; } - this.oldClientId = this.getClientId(dbInbound.protocol, clients[index]); + this.oldClientId = this.getClientId(dbInbound.protocol, currentClient); } else { this.addClient(this.inbound, this.clients); } - this.clientStats = this.dbInbound.clientStats.find(row => row.email === this.clients[this.index].email); + const activeClient = this.clients[this.index]; + this.clientStats = Array.isArray(this.dbInbound.clientStats) + ? this.dbInbound.clientStats.find(row => row.email === activeClient?.email) + : null; this.confirm = confirm; }, getClientId(protocol, client) { @@ -64,7 +75,7 @@ case Protocols.VMESS: return clients.push(new Inbound.VmessSettings.VMESS()); case Protocols.VLESS: return clients.push(new Inbound.VLESSSettings.VLESS()); case Protocols.TROJAN: return clients.push(new Inbound.TrojanSettings.Trojan()); - case Protocols.SHADOWSOCKS: return clients.push(new Inbound.ShadowsocksSettings.Shadowsocks(clients[0].method, RandomUtil.randomShadowsocksPassword(inbound.settings.method))); + case Protocols.SHADOWSOCKS: return clients.push(new Inbound.ShadowsocksSettings.Shadowsocks(inbound.settings.method, RandomUtil.randomShadowsocksPassword(inbound.settings.method))); default: return null; } }, diff --git a/web/html/modals/warp_modal.html b/web/html/modals/warp_modal.html index 4bfb7ca1..8d9d7a0b 100644 --- a/web/html/modals/warp_modal.html +++ b/web/html/modals/warp_modal.html @@ -131,26 +131,27 @@ }, methods: { collectConfig() { - config = warpModal.warpConfig.config; - peer = config.peers[0]; - if (config) { - warpModal.warpOutbound = Outbound.fromJson({ - tag: 'warp', - protocol: Protocols.Wireguard, - settings: { - mtu: 1420, - secretKey: warpModal.warpData.private_key, - address: this.getAddresses(config.interface.addresses), - reserved: this.getResolved(config.client_id), - domainStrategy: 'ForceIP', - peers: [{ - publicKey: peer.public_key, - endpoint: peer.endpoint.host, - }], - noKernelTun: false, - } - }); + const config = warpModal.warpConfig?.config; + if (!config || !Array.isArray(config.peers) || config.peers.length === 0) { + return; } + const peer = config.peers[0]; + warpModal.warpOutbound = Outbound.fromJson({ + tag: 'warp', + protocol: Protocols.Wireguard, + settings: { + mtu: 1420, + secretKey: warpModal.warpData.private_key, + address: this.getAddresses(config.interface.addresses), + reserved: this.getResolved(config.client_id), + domainStrategy: 'ForceIP', + peers: [{ + publicKey: peer.public_key, + endpoint: peer.endpoint.host, + }], + noKernelTun: false, + } + }); }, getAddresses(addrs) { let addresses = []; @@ -243,4 +244,4 @@ }); -{{end}} \ No newline at end of file +{{end}} diff --git a/web/html/modals/xray_outbound_modal.html b/web/html/modals/xray_outbound_modal.html index 2edb5fc0..ce70bc6d 100644 --- a/web/html/modals/xray_outbound_modal.html +++ b/web/html/modals/xray_outbound_modal.html @@ -55,7 +55,7 @@ } }, toggleJson(jsonTab) { - textAreaObj = document.getElementById('outboundJson'); + const textAreaObj = document.getElementById('outboundJson'); if(jsonTab){ if(this.cm != null) { this.cm.toTextArea(); @@ -64,7 +64,7 @@ textAreaObj.value = JSON.stringify(this.outbound.toJson(), null, 2); this.cm = CodeMirror.fromTextArea(textAreaObj, app.cmOptions); this.cm.on('change',editor => { - value = editor.getValue(); + const value = editor.getValue(); if(this.isJsonString(value)){ this.outbound = Outbound.fromJson(JSON.parse(value)); this.check(); @@ -107,11 +107,11 @@ canEnableTls() { return this.outModal.outbound.canEnableTls(); }, - convertLink(){ - newOutbound = Outbound.fromLink(outModal.link); - if(newOutbound){ - this.outModal.outbound = newOutbound; - this.outModal.toggleJson(true); + convertLink(){ + const newOutbound = Outbound.fromLink(outModal.link); + if(newOutbound){ + this.outModal.outbound = newOutbound; + this.outModal.toggleJson(true); this.outModal.check(); this.$message.success('Link imported successfully...'); outModal.link = ''; diff --git a/web/html/settings.html b/web/html/settings.html index 21294da7..fd86657c 100644 --- a/web/html/settings.html +++ b/web/html/settings.html @@ -626,8 +626,12 @@ this.entryPort = window.location.port; this.entryProtocol = window.location.protocol; this.entryIsIP = this._isIp(this.entryHost); - await this.getAllSetting(); - await this.loadInboundTags(); + try { + await this.getAllSetting(); + await this.loadInboundTags(); + } finally { + this.loadingStates.fetched = true; + } while (true) { await PromiseUtil.sleep(1000); this.saveBtnDisable = this.oldAllSetting.equals(this.allSetting); @@ -635,4 +639,4 @@ } }); -{{ template "page/body_end" .}} \ No newline at end of file +{{ template "page/body_end" .}} diff --git a/web/html/xray.html b/web/html/xray.html index ebe31f48..5a04910b 100644 --- a/web/html/xray.html +++ b/web/html/xray.html @@ -398,8 +398,8 @@ this.loadingStates.fetched = true } - result = JSON.parse(msg.obj); - xs = JSON.stringify(result.xraySetting, null, 2); + const result = JSON.parse(msg.obj); + const xs = JSON.stringify(result.xraySetting, null, 2); this.oldXraySetting = xs; this.xraySetting = xs; this.inboundTags = result.inboundTags; @@ -1063,9 +1063,13 @@ if (window.location.protocol !== "https:") { this.showAlert = true; } - await this.getXraySetting(); - await this.getXrayResult(); - await this.getOutboundsTraffic(); + try { + await this.getXraySetting(); + await this.getXrayResult(); + await this.getOutboundsTraffic(); + } finally { + this.loadingStates.fetched = true; + } if (window.wsClient) { window.wsClient.connect(); @@ -1562,4 +1566,4 @@ }, }); -{{ template "page/body_end" .}} \ No newline at end of file +{{ template "page/body_end" .}}