From 121b6e0bd04a4a0dcddc1d93370016329f338237 Mon Sep 17 00:00:00 2001 From: Black Date: Tue, 19 May 2026 17:15:10 +0500 Subject: [PATCH 01/11] feat(panel): copy connection strings for `mixed` inbound (#4450) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(panel): copy connection strings for `mixed` inbound * feat(panel): inline share buttons on desktop, dropdown on mobile Replace the credentials-copy dropdown with three labeled share buttons (SOCKS5 / HTTP / Telegram), each with a tooltip preview of the full URL. Reverse the URI auth position so the format becomes `scheme://host:port@user:pass` (matches Hiddify-style sharing). Add a Telegram t.me/socks link with URL-encoded user/pass. On viewports <=600px the inline row collapses into a single Copy dropdown to keep the per-account row from wrapping into clutter. RTL panels are unaffected — the share divider uses inline-* logical props. --------- Co-authored-by: Sanaei --- .../src/pages/inbounds/InboundInfoModal.vue | 146 ++++++++++++++---- 1 file changed, 119 insertions(+), 27 deletions(-) diff --git a/frontend/src/pages/inbounds/InboundInfoModal.vue b/frontend/src/pages/inbounds/InboundInfoModal.vue index 99d0855b..4bfef885 100644 --- a/frontend/src/pages/inbounds/InboundInfoModal.vue +++ b/frontend/src/pages/inbounds/InboundInfoModal.vue @@ -19,41 +19,20 @@ import { useDatepicker } from '@/composables/useDatepicker.js'; const { t } = useI18n(); const { datepicker } = useDatepicker(); -// One modal handles every protocol's info / share view because the -// legacy template did the same. The big v-if forks at the top decide -// which sub-block of the body renders: -// • multi-user inbound (VMess/VLess/Trojan/SS-multi/Hysteria) → per- -// client row + share links -// • SS single-user → connection details + share link -// • WireGuard → secret/peers + per-peer config download -// • Mixed/HTTP/Tunnel → connection details only -// -// We display links via QrPanel — each link gets its own QR + copy + -// (for WireGuard configs) download button. - const props = defineProps({ open: { type: Boolean, default: false }, - // Result of inbounds-page checkFallback() so the link-gen sees the - // root inbound's listen/port/security when the dbInbound is a - // domain-socket fallback (`@`). dbInbound: { type: Object, default: null }, - // Index into inbound.clients to focus on for multi-user inbounds. clientIndex: { type: Number, default: 0 }, - // Sidecar config the legacy panel keyed off `app.*`. remarkModel: { type: String, default: '-ieo' }, expireDiff: { type: Number, default: 0 }, trafficDiff: { type: Number, default: 0 }, ipLimitEnable: { type: Boolean, default: false }, tgBotEnable: { type: Boolean, default: false }, - // Address of the node hosting this inbound; '' for local. Wired - // through to share/QR link generation so node-managed inbounds - // produce links that connect to the node, not the central panel. nodeAddress: { type: String, default: '' }, subSettings: { type: Object, default: () => ({ enable: false, subURI: '', subJsonURI: '', subJsonEnable: false }), }, - // Email -> ts (last-online unix-ms) map fetched at the page level. lastOnlineMap: { type: Object, default: () => ({}) }, }); @@ -598,7 +577,8 @@ const showSubscriptionTab = computed(
Gateway
{{ ip }}
+ class="value-tag">{{ + ip }}
DNS
@@ -612,7 +592,8 @@ const showSubscriptionTab = computed(
Auto system routes
{{ cidr }}
+ color="green">{{ + cidr }}
@@ -670,12 +651,101 @@ const showSubscriptionTab = computed( {{ account.pass }} - - + + + + + +
+ + + @@ -897,6 +967,7 @@ const showSubscriptionTab = computed( white-space: normal; word-break: break-all; display: inline-block; + margin-right: 0; } .value-block { @@ -927,6 +998,27 @@ const showSubscriptionTab = computed( flex-shrink: 0; } +.share-buttons, +.share-mobile { + margin-inline-start: 4px; + padding-inline-start: 8px; + border-inline-start: 1px solid rgba(128, 128, 128, 0.25); +} + +.share-mobile { + display: none; +} + +@media (max-width: 600px) { + .share-desktop { + display: none !important; + } + .share-mobile { + display: inline-flex; + align-items: center; + } +} + .security-line { display: flex; align-items: center; From 758e1ad05047b338765d67e4505f3ba4052c0ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D0=BD=D1=81=D1=82=D0=B0=D0=BD=D1=82=D0=B8?= =?UTF-8?q?=D0=BD?= Date: Tue, 19 May 2026 14:28:05 +0200 Subject: [PATCH 02/11] Make HSTS policy configurable if https is enabled (#4462) * Make HSTS policy configurable if https is enabled * refactor(web): gate HSTS at call site so XUI_SKIP_HSTS doesn't drop the Secure cookie flag isDirectHTTPSConfigured was being reused for both the HSTS middleware and the session cookie's Secure flag (web.go:185). Embedding the env-var check inside it meant setting XUI_SKIP_HSTS=true also stripped Secure from session cookies on a real HTTPS server. Split the concerns: keep isDirectHTTPSConfigured honest (cert/key only) and combine it with the env var at the call site for the HSTS middleware only. --------- Co-authored-by: Konstantin Kayukin Co-authored-by: Sanaei --- config/config.go | 5 +++++ web/web.go | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 31c285d2..59ad671b 100644 --- a/config/config.go +++ b/config/config.go @@ -57,6 +57,11 @@ func IsDebug() bool { return os.Getenv("XUI_DEBUG") == "true" } +// IsSkipHSTS returns true if skipping HSTS mode is enabled via the XUI_SKIP_HSTS environment variable. +func IsSkipHSTS() bool { + return os.Getenv("XUI_SKIP_HSTS") == "true" +} + // GetBinFolderPath returns the path to the binary folder, defaulting to "bin" if not set via XUI_BIN_FOLDER. func GetBinFolderPath() string { binFolderPath := os.Getenv("XUI_BIN_FOLDER") diff --git a/web/web.go b/web/web.go index 35516e4d..e903a016 100644 --- a/web/web.go +++ b/web/web.go @@ -154,7 +154,8 @@ func (s *Server) initRouter() (*gin.Engine, error) { engine := gin.Default() directHTTPS := s.isDirectHTTPSConfigured() - engine.Use(middleware.SecurityHeadersMiddleware(directHTTPS)) + sendHSTS := directHTTPS && !config.IsSkipHSTS() + engine.Use(middleware.SecurityHeadersMiddleware(sendHSTS)) webDomain, err := s.settingService.GetWebDomain() if err != nil { From fd3770c8c954fa6f187ad4e8d2b4dcee9bdb9d97 Mon Sep 17 00:00:00 2001 From: Abdalrahman Date: Tue, 19 May 2026 16:00:15 +0300 Subject: [PATCH 03/11] fix: parse XHTTP extra fields from V2Ray links and v2rayN JSON imports (#4426) - fromVmessLink: parse all XHTTP bidirectional fields (xPaddingBytes, xPaddingObfsMode, session/seq/uplink placements & keys, scMaxEachPostBytes, headers) from VMess share link JSON - fromParamLink: parse same missing fields from the extra JSON param in VLESS/Trojan/SS share links and from URL params - VLESSSettings.fromJson: handle v2rayN-style nested vnext array for address/port/id/flow/encryption; previously only flat format was accepted - StreamSettings.fromJson: accept splithttpSettings as backward-compat alias for xhttpSettings, normalize splithttp network to xhttp Closes #4406 Co-authored-by: Sanaei --- frontend/src/models/outbound.js | 64 +++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/frontend/src/models/outbound.js b/frontend/src/models/outbound.js index 8277590e..fc3dfe39 100644 --- a/frontend/src/models/outbound.js +++ b/frontend/src/models/outbound.js @@ -1138,8 +1138,12 @@ export class StreamSettings extends CommonClass { } static fromJson(json = {}) { + // Xray-core supports both "xhttpSettings" and "splithttpSettings" (backward-compat alias) + const xhttpJson = json.xhttpSettings ?? json.splithttpSettings; + // Normalize "splithttp" network name to "xhttp" for internal consistency + const network = json.network === 'splithttp' ? 'xhttp' : json.network; return new StreamSettings( - json.network, + network, json.security, TlsStreamSettings.fromJson(json.tlsSettings), RealityStreamSettings.fromJson(json.realitySettings), @@ -1148,7 +1152,7 @@ export class StreamSettings extends CommonClass { WsStreamSettings.fromJson(json.wsSettings), GrpcStreamSettings.fromJson(json.grpcSettings), HttpUpgradeStreamSettings.fromJson(json.httpupgradeSettings), - xHTTPStreamSettings.fromJson(json.xhttpSettings), + xHTTPStreamSettings.fromJson(xhttpJson), HysteriaStreamSettings.fromJson(json.hysteriaSettings), FinalMaskStreamSettings.fromJson(json.finalmask), SockoptStreamSettings.fromJson(json.sockopt), @@ -1379,12 +1383,28 @@ export class Outbound extends CommonClass { } else if (network === 'httpupgrade') { stream.httpupgrade = new HttpUpgradeStreamSettings(json.path, json.host); } else if (network === 'xhttp') { - // xHTTPStreamSettings positional args are (path, host, headers, ..., mode); - // passing `json.mode` as the 3rd argument used to land in the `headers` - // slot, dropping the mode on the floor. Build the object and set mode - // explicitly to avoid that. const xh = new xHTTPStreamSettings(json.path, json.host); if (json.mode) xh.mode = json.mode; + if (json.type && !json.mode) xh.mode = json.type; + // Padding / obfuscation — sing-box families use x_padding_bytes, + // while the extra block carries xPaddingBytes. + if (json.x_padding_bytes && !json.xPaddingBytes) json.xPaddingBytes = json.x_padding_bytes; + if (typeof json.xPaddingBytes === 'string' && json.xPaddingBytes) xh.xPaddingBytes = json.xPaddingBytes; + if (json.xPaddingObfsMode === true) { + xh.xPaddingObfsMode = true; + ["xPaddingKey", "xPaddingHeader", "xPaddingPlacement", "xPaddingMethod"].forEach(k => { + if (typeof json[k] === 'string' && json[k]) xh[k] = json[k]; + }); + } + // Bidirectional string fields carried in the extra block + const xFields = ["sessionPlacement", "sessionKey", "seqPlacement", "seqKey", "uplinkDataPlacement", "uplinkDataKey", "scMaxEachPostBytes"]; + xFields.forEach(k => { + if (typeof json[k] === 'string' && json[k]) xh[k] = json[k]; + }); + // Headers — VMess extra emits them as a {name: value} map + if (json.headers && typeof json.headers === 'object' && !Array.isArray(json.headers)) { + xh.headers = Object.entries(json.headers).map(([name, value]) => ({ name, value })); + } stream.xhttp = xh; } @@ -1455,6 +1475,16 @@ export class Outbound extends CommonClass { ["xPaddingKey", "xPaddingHeader", "xPaddingPlacement", "xPaddingMethod"].forEach(k => { if (typeof extra[k] === 'string' && extra[k]) xh[k] = extra[k]; }); + if (!xh.mode && typeof extra.mode === 'string' && extra.mode) xh.mode = extra.mode; + // Bidirectional string fields carried inside the extra block + const xFields = ["sessionPlacement", "sessionKey", "seqPlacement", "seqKey", "uplinkDataPlacement", "uplinkDataKey", "scMaxEachPostBytes"]; + xFields.forEach(k => { + if (typeof extra[k] === 'string' && extra[k]) xh[k] = extra[k]; + }); + // Headers — extra emits them as a {name: value} map + if (extra.headers && typeof extra.headers === 'object' && !Array.isArray(extra.headers)) { + xh.headers = Object.entries(extra.headers).map(([name, value]) => ({ name, value })); + } } catch (_) { /* ignore malformed extra */ } } stream.xhttp = xh; @@ -1997,6 +2027,28 @@ Outbound.VLESSSettings = class extends CommonClass { } static fromJson(json = {}) { + // Handle v2rayN-style nested vnext array (standard Xray JSON format) + if (!ObjectUtil.isArrEmpty(json.vnext)) { + const v = json.vnext[0] || {}; + const u = ObjectUtil.isArrEmpty(v.users) ? {} : v.users[0]; + const saved = json.testseed; + const testseed = (Array.isArray(saved) + && saved.length === 4 + && saved.every(v => Number.isInteger(v) && v > 0)) + ? saved + : []; + return new Outbound.VLESSSettings( + v.address, + v.port, + u.id, + u.flow, + u.encryption, + json.reverse?.tag || '', + ReverseSniffing.fromJson(json.reverse?.sniffing || {}), + json.testpre || 0, + testseed, + ); + } if (ObjectUtil.isEmpty(json.address) || ObjectUtil.isEmpty(json.port)) return new Outbound.VLESSSettings(); const saved = json.testseed; const testseed = (Array.isArray(saved) From d7f47d8b6a0db831f018b18000b81cdae17577dd Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 19 May 2026 15:42:16 +0200 Subject: [PATCH 04/11] fix(xray): allow private-IP destinations via freedom finalRules Xray-core v26.4.17 added a default policy that blocks private IPs in the freedom outbound for vless/vmess/trojan/hysteria/wireguard inbounds, even when the panel's routing rules send traffic to direct (#4420). The legacy ipsBlocked override was deprecated in the same release. Default template now seeds the direct outbound with a finalRules entry that explicitly allows geoip:private, so users who intentionally remove the geoip:private->blocked routing rule actually regain LAN access. Defense in depth is preserved: the routing rule still blocks private IPs by default, so unmodified configs keep the same behavior. OutboundFormModal exposes a Final Rules editor under the Freedom section: per-rule action (allow/block), network, port, IP/CIDR/geoip tags, and an optional blockDelay for block actions. --- frontend/src/pages/xray/OutboundFormModal.vue | 41 +++++++++++++++++++ web/service/config.json | 5 ++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/xray/OutboundFormModal.vue b/frontend/src/pages/xray/OutboundFormModal.vue index aa22a8a0..b8c72aa3 100644 --- a/frontend/src/pages/xray/OutboundFormModal.vue +++ b/frontend/src/pages/xray/OutboundFormModal.vue @@ -328,6 +328,47 @@ function regenerateWgKeys() { + + + + + + + Override Xray's default private-IP block (needed for LAN access through proxy) + + + diff --git a/web/service/config.json b/web/service/config.json index 8e7fb19a..c8b52d05 100644 --- a/web/service/config.json +++ b/web/service/config.json @@ -30,7 +30,10 @@ "outbounds": [{ "protocol": "freedom", "settings": { - "domainStrategy": "AsIs" + "domainStrategy": "AsIs", + "finalRules": [ + { "action": "allow", "ip": ["geoip:private"] } + ] }, "tag": "direct" }, From 3827d7d061a1e2cfbdc479be4cb355c3bb6bb288 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 19 May 2026 16:10:57 +0200 Subject: [PATCH 05/11] fix(clients): seed all clients when settings.clients has string tgId The ClientsTable seeder unmarshaled each settings.clients entry into model.Client and silently `continue`d on error. Older inbounds wrote tgId as an empty string for every client past the first; that fails to unmarshal into int64, so only the first client per inbound landed in the new clients table. Normalize tgId and the other int64/int fields on the raw map before marshal+unmarshal: parseable strings convert, empty/unparseable ones drop so the field falls back to zero. Also log on the residual unmarshal-failure path so the next regression is visible. Recover already-seeded installs by re-syncing each inbound's clients into the relational tables from MigrationRequirements, so running `x-ui migrate` heals partial seeds. --- database/db.go | 34 ++++++++++++++++++++++++++++++++++ web/service/inbound.go | 6 ++++++ 2 files changed, 40 insertions(+) diff --git a/database/db.go b/database/db.go index a06bb5c1..a5e2b66e 100644 --- a/database/db.go +++ b/database/db.go @@ -11,6 +11,7 @@ import ( "os" "path" "slices" + "strconv" "strings" "time" @@ -198,6 +199,36 @@ func runSeeders(isUsersEmpty bool) error { return nil } +// normalizeClientJSONFields coerces loosely-typed numeric fields in a raw +// settings.clients entry so json.Unmarshal into model.Client doesn't fail +// when older rows wrote tgId/limitIp/totalGB/etc. as strings. Empty strings +// drop the key so the field falls back to its zero value. +func normalizeClientJSONFields(obj map[string]any) { + normalizeInt := func(key string) { + raw, exists := obj[key] + if !exists { + return + } + s, ok := raw.(string) + if !ok { + return + } + trimmed := strings.ReplaceAll(strings.TrimSpace(s), " ", "") + if trimmed == "" { + delete(obj, key) + return + } + if n, err := strconv.ParseInt(trimmed, 10, 64); err == nil { + obj[key] = n + } else { + delete(obj, key) + } + } + for _, k := range []string{"tgId", "limitIp", "totalGB", "expiryTime", "reset", "created_at", "updated_at"} { + normalizeInt(k) + } +} + func seedClientsFromInboundJSON() error { var inbounds []model.Inbound if err := db.Find(&inbounds).Error; err != nil { @@ -226,12 +257,15 @@ func seedClientsFromInboundJSON() error { if !ok { continue } + normalizeClientJSONFields(obj) blob, err := json.Marshal(obj) if err != nil { continue } var c model.Client if err := json.Unmarshal(blob, &c); err != nil { + log.Printf("ClientsTable seed: skip client in inbound %d (unmarshal failed): %v; payload=%s", + inbound.Id, err, string(blob)) continue } email := strings.TrimSpace(c.Email) diff --git a/web/service/inbound.go b/web/service/inbound.go index 7fab7c48..07f8d37a 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -2924,6 +2924,12 @@ func (s *InboundService) MigrationRequirements() { } } } + + // Heal clients table for installs where the one-shot seeder + // skipped clients due to a tgId-string unmarshal error. + if syncErr := s.clientService.SyncInbound(tx, inbounds[inbound_index].Id, modelClients); syncErr != nil { + logger.Warning("MigrationRequirements sync clients failed:", syncErr) + } } tx.Save(inbounds) From 5b5ac3f04b9291b66a9fb040f9aafbaff47bdb07 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 19 May 2026 17:02:26 +0200 Subject: [PATCH 06/11] fix(migrate): include hysteria, hysteria2, shadowsocks in client sync The MigrationRequirements protocol filter only covered vmess/vless/trojan, so orphaned clients in hysteria/hysteria2/shadowsocks inbounds were never synced into the relational clients table on startup. --- web/service/inbound.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/service/inbound.go b/web/service/inbound.go index 07f8d37a..0a996952 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -2845,7 +2845,7 @@ func (s *InboundService) MigrationRequirements() { // Fix inbounds based problems var inbounds []*model.Inbound - err = tx.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan"}).Find(&inbounds).Error + err = tx.Model(model.Inbound{}).Where("protocol IN (?)", []string{"vmess", "vless", "trojan", "shadowsocks", "hysteria", "hysteria2"}).Find(&inbounds).Error if err != nil && err != gorm.ErrRecordNotFound { return } From 1b436bb3e0af5e86a2a8e7ca5a49392d2f0f1d11 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 19 May 2026 17:02:34 +0200 Subject: [PATCH 07/11] fix(clients): honor global pageSize and widen size-changer dropdown Read pageSize from defaultSettings and apply it to the clients table so the panel-wide pagination preference is respected. Widen the AntD size-changer trigger and its teleported popup so '100 / page' no longer truncates. --- frontend/src/pages/clients/ClientsPage.vue | 53 +++++++++++++++++----- frontend/src/pages/clients/useClients.js | 3 ++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/frontend/src/pages/clients/ClientsPage.vue b/frontend/src/pages/clients/ClientsPage.vue index e1a03263..7c37d577 100644 --- a/frontend/src/pages/clients/ClientsPage.vue +++ b/frontend/src/pages/clients/ClientsPage.vue @@ -43,6 +43,7 @@ const { tgBotEnable, expireDiff, trafficDiff, + pageSize, create, update, remove, @@ -442,6 +443,10 @@ function expiryColor(row) { const sortState = ref({ column: null, order: null }); const paginationState = ref({ current: 1, pageSize: 20 }); +watch(pageSize, (next) => { + if (next > 0) paginationState.value.pageSize = next; +}, { immediate: true }); + function sortableCol(col, key) { return { ...col, @@ -670,8 +675,9 @@ const columns = computed(() => [ - + From 7fc7c14ac1ee7a8ea7574dad0f1824775a8fccb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 15:59:40 +0200 Subject: [PATCH 10/11] build(deps-dev): bump vite from 8.0.13 to 8.0.14 in /frontend (#4487) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.13 to 8.0.14. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.0.14/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.0.14 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- frontend/package-lock.json | 184 ++++++++++++++++--------------------- frontend/package.json | 2 +- 2 files changed, 78 insertions(+), 108 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index af20a3a0..4a4f129b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -27,7 +27,7 @@ "eslint": "^10.3.0", "eslint-plugin-vue": "^10.9.1", "globals": "^17.6.0", - "vite": "^8.0.11", + "vite": "^8.0.14", "vue-eslint-parser": "^10.4.0" }, "engines": { @@ -610,9 +610,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.130.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz", - "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==", + "version": "0.132.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", + "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", "dev": true, "license": "MIT", "funding": { @@ -620,9 +620,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz", - "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", + "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", "cpu": [ "arm64" ], @@ -637,9 +637,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz", - "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", "cpu": [ "arm64" ], @@ -654,9 +654,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz", - "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", + "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", "cpu": [ "x64" ], @@ -671,9 +671,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz", - "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", + "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", "cpu": [ "x64" ], @@ -688,9 +688,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz", - "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", + "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", "cpu": [ "arm" ], @@ -705,16 +705,13 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz", - "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", + "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -725,16 +722,13 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz", - "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", + "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", "cpu": [ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -745,16 +739,13 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz", - "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", + "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", "cpu": [ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -765,16 +756,13 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz", - "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", + "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", "cpu": [ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -785,16 +773,13 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz", - "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", + "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -805,16 +790,13 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz", - "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", + "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", "cpu": [ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -825,9 +807,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz", - "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", + "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", "cpu": [ "arm64" ], @@ -842,9 +824,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz", - "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", + "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", "cpu": [ "wasm32" ], @@ -861,9 +843,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz", - "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", + "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", "cpu": [ "arm64" ], @@ -878,9 +860,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz", - "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", + "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", "cpu": [ "x64" ], @@ -2202,9 +2184,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2226,9 +2205,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2250,9 +2226,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2274,9 +2247,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2623,9 +2593,9 @@ } }, "node_modules/postcss": { - "version": "8.5.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", - "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -2642,7 +2612,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -2715,13 +2685,13 @@ "license": "MIT" }, "node_modules/rolldown": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz", - "integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz", + "integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.130.0", + "@oxc-project/types": "=0.132.0", "@rolldown/pluginutils": "^1.0.0" }, "bin": { @@ -2731,21 +2701,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.1", - "@rolldown/binding-darwin-arm64": "1.0.1", - "@rolldown/binding-darwin-x64": "1.0.1", - "@rolldown/binding-freebsd-x64": "1.0.1", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.1", - "@rolldown/binding-linux-arm64-gnu": "1.0.1", - "@rolldown/binding-linux-arm64-musl": "1.0.1", - "@rolldown/binding-linux-ppc64-gnu": "1.0.1", - "@rolldown/binding-linux-s390x-gnu": "1.0.1", - "@rolldown/binding-linux-x64-gnu": "1.0.1", - "@rolldown/binding-linux-x64-musl": "1.0.1", - "@rolldown/binding-openharmony-arm64": "1.0.1", - "@rolldown/binding-wasm32-wasi": "1.0.1", - "@rolldown/binding-win32-arm64-msvc": "1.0.1", - "@rolldown/binding-win32-x64-msvc": "1.0.1" + "@rolldown/binding-android-arm64": "1.0.2", + "@rolldown/binding-darwin-arm64": "1.0.2", + "@rolldown/binding-darwin-x64": "1.0.2", + "@rolldown/binding-freebsd-x64": "1.0.2", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", + "@rolldown/binding-linux-arm64-gnu": "1.0.2", + "@rolldown/binding-linux-arm64-musl": "1.0.2", + "@rolldown/binding-linux-ppc64-gnu": "1.0.2", + "@rolldown/binding-linux-s390x-gnu": "1.0.2", + "@rolldown/binding-linux-x64-gnu": "1.0.2", + "@rolldown/binding-linux-x64-musl": "1.0.2", + "@rolldown/binding-openharmony-arm64": "1.0.2", + "@rolldown/binding-wasm32-wasi": "1.0.2", + "@rolldown/binding-win32-arm64-msvc": "1.0.2", + "@rolldown/binding-win32-x64-msvc": "1.0.2" } }, "node_modules/scroll-into-view-if-needed": { @@ -2957,16 +2927,16 @@ "license": "MIT" }, "node_modules/vite": { - "version": "8.0.13", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz", - "integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==", + "version": "8.0.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.14.tgz", + "integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.14", - "rolldown": "1.0.1", + "postcss": "^8.5.15", + "rolldown": "1.0.2", "tinyglobby": "^0.2.16" }, "bin": { diff --git a/frontend/package.json b/frontend/package.json index 6c756e58..6838d821 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,7 +34,7 @@ "eslint": "^10.3.0", "eslint-plugin-vue": "^10.9.1", "globals": "^17.6.0", - "vite": "^8.0.11", + "vite": "^8.0.14", "vue-eslint-parser": "^10.4.0" }, "overrides": { From 6e2816d035a3ad2071411c1890490639f025757d Mon Sep 17 00:00:00 2001 From: "Cheng Ho Ming, Eric" <123erichappy123@gmail.com> Date: Thu, 21 May 2026 22:24:54 +0800 Subject: [PATCH 11/11] fix(frontend): override browser default background color on autofilled login inputs (#4478) --- frontend/src/pages/login/LoginPage.vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frontend/src/pages/login/LoginPage.vue b/frontend/src/pages/login/LoginPage.vue index fab7ba9d..a8840822 100644 --- a/frontend/src/pages/login/LoginPage.vue +++ b/frontend/src/pages/login/LoginPage.vue @@ -469,6 +469,13 @@ function cycleTheme() { font-weight: 500; } +.login-form :deep(input.ant-input:-webkit-autofill) { + -webkit-text-fill-color: var(--color-text) !important; + -webkit-box-shadow: 0 0 0 1000px var(--bg-card) inset !important; + box-shadow: 0 0 0 1000px var(--bg-card) inset !important; + transition: background-color 9999s ease-in-out 0s, color 9999s ease-in-out 0s; +} + .submit-row { margin-bottom: 0; }