fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent

Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
fix(tuic-v5): merge panel UUIDs into inbound; keep sub auth consistent
Root cause vs user config/sub:
- Inbound had autofill UUID only (8398d58a…)
- Subscription exported panel admin UUID/password (6c96e7d2…)
- Client auth could never match
- asUsersMapUUID: union Config users + bound panel UUID→password
- Export tuic-v5: prefer panel credentials when bound (not autofill-only)
- TUIC client: skip-cert-verify for panel self-signed (config or certstore)
This commit is contained in:
kazeyukiro committed 2026-09-17 00:25:00 +08:00
1 parent 05bf9a270e
commit dbc3a25507
2 files changed
+44 -24

No files matched your search

+13 -4
View File
@@ -136,10 +136,10 @@ func listenerToProxies(l models.Listener, server string, credentials []user.Cred
credentials = cfgCreds
}
case "tuic-v5":
// Config users map wins; otherwise keep panel-bound credentials.
if tuicConfigHasUsers(opts) && len(cfgCreds) > 0 {
credentials = cfgCreds
} else if len(credentials) == 0 {
// Panel-bound UUID/password is what the subscription user authenticates
// with. Config autofill UUID is only a fallback when unbound.
// (Inbound compile merges both via asUsersMapUUID.)
if len(credentials) == 0 {
credentials = cfgCreds
}
case "tuic":
@@ -387,6 +387,15 @@ func listenerToProxies(l models.Listener, server string, credentials []user.Cred
p["name-cert-verify"] = v
}
ensureTUICClientDefaults(p, opts)
if p["skip-cert-verify"] == nil {
if certutil.ShouldSkipCertVerify(opts) {
p["skip-cert-verify"] = true
} else if c, _, ok := certstore.Load(l.ID); ok && certutil.IsPanelSelfSignedPEM(c) {
p["skip-cert-verify"] = true
} else if cert, _ := opts["certificate"].(string); certutil.IsPanelSelfSignedPEM(cert) {
p["skip-cert-verify"] = true
}
}
if p["sni"] == nil && p["servername"] == nil && server != "" {
p["sni"] = server
}
+31 -20
View File
@@ -265,33 +265,44 @@ func asUsersMap(cfg map[string]interface{}, fromCreds []UserCred, hasCredState b
// Mihomo listener schema expects that shape (TUIC v5: users is a map keyed by UUID).
// Falls back to Username when UUID is empty (legacy panel users without UUID).
func asUsersMapUUID(cfg map[string]interface{}, fromCreds []UserCred, hasCredState bool) map[string]interface{} {
if len(fromCreds) > 0 {
out := make(map[string]interface{}, len(fromCreds))
for _, c := range fromCreds {
key := c.UUID
if key == "" {
key = c.Username
}
if key == "" {
key = "default"
}
out[key] = c.Password
}
return out
}
// Union: Config autofill UUID(s) + every bound panel user.
// Subscription exports panel UUID/password; inbound must accept the same
// keys or TUIC v5 auth fails (config-only random UUID ≠ panel UUID).
out := map[string]interface{}{}
if raw, ok := cfg["users"]; ok {
switch users := raw.(type) {
case map[string]interface{}:
return users
case map[interface{}]interface{}:
out := make(map[string]interface{}, len(users))
for k, v := range users {
out[fmt.Sprint(k)] = fmt.Sprint(v)
if s := strings.TrimSpace(fmt.Sprint(v)); s != "" {
out[k] = s
}
}
case map[interface{}]interface{}:
for k, v := range users {
if s := strings.TrimSpace(fmt.Sprint(v)); s != "" {
out[fmt.Sprint(k)] = s
}
}
return out
}
}
return nil
for _, c := range fromCreds {
key := strings.TrimSpace(c.UUID)
if key == "" {
key = strings.TrimSpace(c.Username)
}
if key == "" {
continue
}
pass := strings.TrimSpace(c.Password)
if pass == "" {
continue
}
out[key] = pass
}
if len(out) == 0 {
return nil
}
return out
}
func normalizeUsersValue(value interface{}) []map[string]interface{} {