Commit Graph
52 Commits
Author SHA1 Message Date
Z User 3279d1c963 feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
feat(share): auto skip-cert-verify for panel self-signed certs
Detect certificates issued with Organization=3m-ui (panel generator)
and set skip-cert-verify / insecure=1 on client YAML and share URIs
so AnyTLS/Hy2/Trojan self-signed nodes work without manual toggles.
2026-08-31 06:12:47 +00:00
Z User da5a0f67d1 fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
fix(audit-r1r2): visual config JSON inline, batch name check, monthly reset, credential sync, restore temp, access profile fallback
Round 1+2 exhaustive audit found 6 bugs. All fixed.
HIGH:
- VisualConfig ProxyEntry: Go JSON doesn't support yaml inline. Added
custom UnmarshalJSON/MarshalJSON to capture/emit flat fields.
- BatchCreate: name uniqueness only checked enabled listeners. Removed
filter to match UNIQUE index scope.
- Monthly reset: could fire multiple times per day if DB locked. Now
claims the day in a transaction BEFORE resetting.
- Batch/delete ops: silently ignored notifyCredentialsChanged errors.
Now logs them.
MEDIUM:
- Global AccessProfile: PublicPort/SNI/ClientFingerprint/ALPN loaded
but never used as fallbacks. Now applied when per-listener empty.
- RestoreDatabase: temp file not cleaned on failure. Added defer remove.
go build/vet/test: all PASS. gofmt: clean.
2026-08-30 15:14:36 +00:00
Z User 0754e6a9d6 fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
fix(format-mismatch): TUIC v5 URI UUID key, cluster JWT auth doc, visual port type, access token entropy
Hunt for format-mismatch bugs (like the backup zip vs raw db bug) found
4 issues across the codebase. All fixed.
== Critical 1: TUIC v5 share URI uses Username instead of UUID ==
uri_credentials.go ClientURIsWithCredentials built the users map for
TUIC keyed by credential.Username, but the server-side compiler
(asUsersMapUUID) keys by UUID. Official Mihomo TUIC v5 spec requires
users: {UUID: PASSWORD}. The URI tuic://alice:pass@host failed auth
because the server looked up users['alice'] not users['UUID'].
Fix: split 'tuic' from the 'anytls/hysteria2/mieru' case; use UUID
as key (fallback to Username when UUID empty), matching asUsersMapUUID.
== Critical 2: Cluster APIToken sent as Bearer JWT to remote panel ==
cluster/service.go sends 'Authorization: Bearer <api_token>' but the
remote panel's RequireAuth middleware expects a signed JWT (HS256).
Opaque tokens fail jwt.Parse → 401 on all auth-protected endpoints.
Fix: documented that api_token must be a valid JWT obtained from
POST /api/v1/auth/login on the remote panel. Added comments at both
Bearer header sites. (Full opaque-token auth path requires a separate
middleware on the remote — tracked as future feature.)
== Medium 3: VisualConfig ProxyEntry.Port string → quoted YAML ==
visual.go ProxyEntry.Port was string type, causing yaml.Marshal to
emit port: '8080' (quoted). Mihomo expects port: 8080 (integer).
Changed to interface{} so JSON/YAML can carry int or string.
== Low 4: AccessToken entropy inconsistency ==
router/access_token.go used 24 bytes (192-bit) for token generation,
but node/api.go CreateClientAccess used only 16 bytes (128-bit).
Aligned both to 24 bytes (192-bit, NIST SP 800-63A minimum).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 16 packages all PASS
- gofmt : clean
2026-08-30 13:04:59 +00:00
Z User e445bcd323 fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
fix(audit): P0+P1 — ShadowQUIC defaults, Snell wrappers, SS plugin, VMess encryption, TUIC/Hy2 fields, subscription error leak, frontend forms
Comprehensive re-audit against official Mihomo docs (Meta-Docs-main)
found 3 High + 9 Medium issues. All fixed in this commit.
== P0 High ==
P0-1: ShadowQUIC client defaults violated official docs
converter/client.go unconditionally defaulted quic-versions=[v2],
congestion-controller=bbr, zero-rtt=true. Official defaults are
v1/cubic/false. Removed defaults; fields now pass through only when
present in listener config.
P0-2: Snell listener wrappers not converted to client obfs-opts
Snell+shadow-tls/res-tls/jls-config produced client YAML with only
psk+version. Added applySnellObfsOpts that maps listener wrappers to
client obfs-opts: {mode: shadow-tls/restls/jls, host, password,
version, username, version-hint, restls-script} per proxies/snell.md.
P0-3: SS simple-obfs plugin name mismatch
Emitted plugin: 'simple-obfs' but official docs say plugin: 'obfs'.
Fixed.
== P1 Medium ==
P1-4: VMess encryption field leaked
copyOption(encryption) called for both vmess and vless. Only VLESS
has encryption. Wrapped in if protocol=='vless'.
P1-5: TUIC client missing sni + skip-cert-verify
Added to both v4 (token) and v5 (users) branches.
P1-6: TUIC URI snake_case → kebab-case
congestion_control→congestion-controller, bbr_profile→bbr-profile,
udp_relay_mode→udp-relay-mode, max_udp_relay_packet_size→
max-udp-relay-packet-size.
P1-7: Hysteria2 client missing handshake-timeout + max-idle-time
Added to copyOption list.
P1-8: Subscription endpoint error leak
Replaced err.Error() with generic 'subscription generation failed'
at 4 public endpoints (lines 82/107/122/368). Added server-side
log.Printf for diagnostics.
P1-9: Snell form missing v4/v5
Version dropdown [1,2,3]→[1,2,3,4,5]; initialValue 3→4 (matches
backend autofill default).
P1-10: Sudoku form missing httpmask + custom-table + fallback
Added EnableSection for httpmask (disable/mode/path-root) +
custom-table/custom-tables/fallback Form.Items. Wired through
configToFormValues + formValuesToConfig + FORM_OWNED_KEYS.
P1-11: ShadowQUIC form missing 4 fields
Added max-datagram-frame-size, recv-window-conn, recv-window,
disable-mtu-discovery.
P1-12: Unconditional support-x25519mlkem768
Removed unconditional true; now only set when listener config
explicitly provides it.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean (on modified files)
2026-08-30 10:34:48 +00:00
Z User fad6e612a5 fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
fix(audit): mux-option UI fields, shadowquic/trusttunnel URI, sudoku aliases
Final re-audit against official Mihomo docs (Meta-Docs-main) found 4
remaining issues. All fixed.
== C1 Critical: mux-option frontend writes smux client fields ==
The frontend mux-option form wrote enable/protocol/max-connections/
min-streams/max-streams/statistic/only-tcp (smux client format) into
the listener mux-option block. The backend listener schema only accepts
padding + brutal.{enabled,up,down} per official docs. Saving a listener
with Mux enabled failed validation.
Fix: removed the 7 smux client fields from the frontend form and the
formValuesToConfig serializer. Only padding + brutal remain (matching
the listener schema). The smux fields belong on the proxy client side,
not the listener.
== C2 Critical: shadowquic URI export broken ==
shadowQUICURIs read userMap(cfg) but shadowquic uses array-form
users: [{username, password}] per official docs. The map read always
returned empty → URI export failed with 'requires at least one user'.
Fix: use userRows(cfg) (array form) matching the compiler/autofill.
== C3 Critical: trusttunnel URI export broken ==
Same bug class as C2. trustTunnelURIs read userMap(cfg) but trusttunnel
uses array-form users per official docs.
Fix: use userRows(cfg).
== M Minor: sudoku missing flat compatibility aliases ==
Official sudoku doc lists http-mask-mode and path-root as flat
compatibility aliases for httpmask.{mode, path-root}. The schema only
had disable-http-mask (top-level). Added http-mask-mode and path-root
to the sudoku Fields allowlist.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- npm run build (tsc + vite) : PASS
- gofmt : clean
2026-08-30 08:30:38 +00:00
Z User c817650597 fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
fix(config): P2+P3+P4 audit fixes — client config, schema, m-ui bridge
Comprehensive audit against official Mihomo docs (Meta-Docs-main).
This commit addresses all remaining P2 (Medium) and P3/P4 (Low)
findings, completing the full audit fix campaign.
== P2 Medium (client config gaps) ==
P2-1: VLESS native share URI missing security=tls for non-Reality TLS
share_modules.go BuildShare only set security=reality; plain TLS
had no security param (clients default to none=plaintext).
Added else-if: security=tls when Node.TLS && no Reality.
P2-2: m-ui VLESS URI emitted non-standard security=shadow-tls/res-tls/jls
mui/protocol/vless.go leaked wrapper types into URI. Fixed: map all
TLS wrappers (shadow-tls/res-tls/jls) to security=tls; reality stays
reality; none omitted. Wrapper detail preserved in client YAML.
P2-3: m-ui decodeHy2 dropped alpn — client YAML ALPN always empty
mui/bridge.go Added shared decodeALPN helper (handles []interface{},
[]string, bare string). Wired into decodeHy2/decodeVMess/decodeTrojan/
decodeVLESS. Added ALPN field to domain VLESSSpec/VMessSpec/TrojanSpec.
P2-4: m-ui classicClientProxy (VMess/Trojan) missing ALPN field
mui/protocol/classic_stream.go Added ALPN yaml field + populated
from node.VMess.ALPN / node.Trojan.ALPN.
P2-5: m-ui vlessClientProxy missing ALPN field
mui/protocol/vless.go Added ALPN yaml field + populated from
node.VLESS.ALPN.
P2-6: sing-box TUIC v4 token not handled
converter/singbox.go TUIC case only read uuid+password. Added token
reading ([]interface{}/[]string/string) → sing-box native token field;
falls back to uuid+password for v5.
P2-7: sing-box VLESS missing encryption mapping
converter/singbox.go Added p[encryption] → ob[encryption] when non-empty.
== P3 Low (schema completeness + client gaps) ==
P3-1: ResTLS restls-script not copied to client restls-opts
converter/client.go resTLSClientOptions now copies restls-script.
P3-2: JLS only exports first user — documented as design limitation
(per-credential JLS user matching requires explicit binding table;
single-JLS-user deployments are correct). Added doc-comment.
P3-3: WS ws-headers not in schema — Host header never exportable
Added ws-headers to top-level Fields for vmess/vless/trojan, aligning
with copyTransport which already reads src[ws-headers].
P3-4: VMess tlsmirror-config steps missing name/headers/wait-time field
Added 3 missing steps.* sub-fields to match tls.md 12-field list.
P3-5: VMess users not in NestedFields — documented as design choice
(map-form vs array-form shape difference would break map-form
validation). Added explanatory comment.
P3-6: Hysteria2 URI up/down inconsistent between rows vs map users
uri_builders.go First branch now reads up/down from listener config,
matching second branch.
P3-7: SS mux-option over-broad — removed 7 proxy-side sing-mux fields
(enable, protocol, max-connections, min-streams, max-streams,
statistic, only-tcp) from ALL 7 protocols with mux-option. Kept
padding + brutal.*/brutal-opts.* (listener-documented fields).
P3-8: m-ui bridge only supports 5/12 protocols — documented as follow-up
(requires implementing 7 protocol decoders; large feature).
P3-9: Three-tier fallback inconsistency — documented as follow-up
(design issue requiring output-contract unification).
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : 15 packages all PASS
- gofmt : clean (on all modified files)
2026-08-30 04:13:26 +00:00
Z User a379c33159 fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
fix(config): comprehensive audit vs official docs — client config + schema
Full audit against official Mihomo docs (Meta-Docs-main) found and
fixed 10 bugs across client config generation and schema completeness.
P0 Critical:
- VLESS client YAML missing network field (transport opts ignored)
- TUIC v4 token share broken (read as string, is array)
P1 High:
- SS base64 violates SIP002 (RawStd -> RawURL)
- VMess base64 inconsistency (RawStd -> Std padded)
- Hysteria2 server-only fields (masquerade/ca/ca-str) in client YAML
- sing-box VMess alter_id hardcoded to 0
- sing-box missing TLS insecure + alpn mapping
- VMess per-user alterId dropped when panel creds bound
P2 Medium:
- reality-config schema missing max-time-difference + proxy (vmess/vless/trojan)
- hysteria2 realm-opts schema missing sni
Verification: go build/vet/test all PASS; gofmt clean.
2026-08-30 00:06:00 +00:00
風雪 58f69e3f9d fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
fix(backend): XFF-aware rate limiting, host trust, error sanitization
- M-3: clientIdentifier now trusts X-Forwarded-For (right-most valid
IP) only when the direct RemoteAddr is loopback/private/link-local
(typical same-host reverse proxy). Public exposure still rejects
spoofed XFF, restoring per-client granularity behind nginx/caddy.
- LOW-10: node ExportNodeURI fell back to c.Request.Host (client
controlled) even when publicURL was configured. Now publicURL wins
over client headers when set.
- LOW-11: Replace direct err.Error() in 500/502 responses with generic
messages; real errors logged server-side via log.Printf. Prevents
leakage of DB paths, SQL fragments, remote server responses.
4xx business messages (invalid id, not found) preserved.
2026-08-29 09:39:00 +00:00
風雪 0f234c0efe fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
fix(protocol): restore broken share_modules.go and implement VLESS BuildShare
The previous commit 658ef5c left share_modules.go starting with 'if'
instead of 'package protocol', making the whole module unbuildable.
This restores:
- package declaration and imports
- Trojan / Shadowsocks / Hysteria2 BuildShare methods
- the missing VLESSCompiler.BuildShare (expected by share_reality_test.go)
Also fixes reality public-key encoding in node/uri_builders.go to use
RawURLEncoding (URL-safe) consistently, matching protocol expectations.
Fixes: 658ef5c (build was broken)
2026-08-29 09:38:25 +00:00
風雪 70af9bcb46 test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
test: enforce URL-safe REALITY public key export
2026-08-29 15:00:42 +08:00
風雪 63b5094d83 fix: export REALITY public keys as raw URL-safe base64 2026-08-29 15:00:33 +08:00
風雪 34c155f83f refactor(share): remark fragment encoding aligned with clients 2026-08-29 13:29:50 +08:00
風雪 d66b803ea6 fix(share): standard URIs for VMess/Trojan/Hy2/SS/TUIC (pbk derive, port, user rows) 2026-08-29 13:24:18 +08:00
風雪 a12c4716af fix(share): derive Reality pbk for standard URIs; fix listen port; clarify autofill UI 2026-08-29 13:08:40 +08:00
風雪 c587ca1217 fix(ci): format node/uri.go after import cleanup 2026-08-29 11:29:32 +08:00
風雪 fc7bdcf526 fix(ci): drop unused imports in node/uri.go 2026-08-29 11:28:26 +08:00
風雪 6bbea65368 fix(ci): remove unused imports in node/api.go 2026-08-29 11:17:20 +08:00
風雪 3fc0503960 feat(node): prefer m-ui BuildShares for URI/client YAML export 2026-08-29 00:30:59 +08:00
風雪 708ffd0471 feat(node): ExportNodeURI via typed protocol registry BuildShare 2026-08-29 00:24:26 +08:00
風雪 e0a0afc577 feat(share): ExportNodeURI (uri/qr/client_yaml) + ExportClientYAML 2026-08-29 00:17:49 +08:00
風雪 f353209a42 fix(share): restore URI builders split file + m-ui Access Profile on ClientURIs 2026-08-29 00:16:53 +08:00
風雪 70862f279e fix(share): restore full uri.go (was truncated) 2026-08-29 00:13:30 +08:00
風雪 ff321e2890 fix(share): restore uri.go + Access Profile + packetEncoding () 2026-08-29 00:12:36 +08:00
風雪 dc62de00a3 feat(share): node share (uri/qr/client_yaml) + Access Profile in URIs 2026-08-29 00:10:35 +08:00
風雪 6cc1c500ba fix: URI export short-id array, Reality sni/fp, VLESS encryption=none 2026-08-24 23:36:16 +08:00
風雪 475c1fc172 style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
style: gofmt for CI
2026-08-21 16:40:11 +00:00
風雪 b36df8f029 fix: audit — access-token export uses PublicHost; robust IPv6 URI host 2026-08-20 15:05:21 +00:00
風雪 857f8e7ec5 feat: full IPv6 support for panel, listeners, and share links 2026-08-20 14:44:10 +00:00
風雪 6b3a09a09c update
update
update
update
update
update
update
update
update
update
update
update
2026-08-19 12:49:36 +08:00
風雪 fc00113ea5 fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
fix(vless): pair encryption/decryption correctly for TCP Vision
- Stop copying server decryption into client encryption
- Store both fields; strip encryption (client-only) from server Compile
- Form + capability + schema support encryption for subscription export
- Tests for export and compile stripping
2026-08-18 14:00:26 +00:00
風雪 96153d4531 Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
Add files via upload
2026-08-18 17:14:11 +08:00
風雪 79fc469e11 feat(node): Access Profile public_host overrides URI export host 2026-08-18 16:58:16 +08:00
風雪 7e80804323 fix: expose node-only routes without duplicate CRUD 2026-08-18 13:48:19 +08:00
風雪 664885ce2a fix: expose node-only routes without duplicate CRUD 2026-08-18 13:47:43 +08:00
風雪 a6523cd610 fix(node): trust pre-resolved host in ClientURIs; host helper lives in uri_host.go 2026-08-18 11:13:10 +08:00
風雪 a73961d077 fix(node): public host helper for share URI export 2026-08-18 11:12:24 +08:00
風雪 a40b339352 chore: remove uri_host.go pending unified host helper in uri.go 2026-08-18 11:12:13 +08:00
風雪 66f799dfb3 fix(node): host resolution for URI export (public_url + loopback fallback) 2026-08-18 11:11:24 +08:00
風雪 4d05dcf56f fix(node): resolve share host via public_url / loopback fallback 2026-08-18 11:11:05 +08:00
風雪 6c0a7ac649 fix(node): URI export empty hint; ensure non-nil uris 2026-08-18 11:01:57 +08:00
風雪 f3f6f5bb7a refactor(node): SetRegenerator delegates to listener.Service 2026-08-17 19:49:37 +08:00
風雪 4f33edff9c fix: cascade soft-delete node bindings and rollback on config failure 2026-08-16 21:02:27 +08:00
風雪 27bb96a137 fix: restore full validator.go after incomplete API push 2026-08-16 19:21:23 +08:00
風雪 b18b12dbbd fix: restore validator.go (hysteria2 requires certificate/private-key) 2026-08-16 18:39:41 +08:00
風雪 2fb8b9036f feat: mobile table/modal pages; fix hysteria2 cert requirement 2026-08-16 18:37:11 +08:00
風雪 15f0a1725d Add files via upload 2026-08-16 15:57:53 +08:00
風雪 b3a35da8c7 fix: node_test users[] schema and numeric port assertions 2026-08-16 15:41:43 +08:00
風雪 2ff92869ff fix: numeric port emission in node generator 2026-08-16 15:29:40 +08:00
風雪 cbbe9d7e41 fix: node validator tests for official schema checks 2026-08-16 15:28:16 +08:00
dzx941 6ac6b31a39 update 2026-08-16 11:16:41 +08:00