mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-12 23:56:07 +00:00
fix(clients): backfill missing subId on startup and guard create/update
Legacy clients (and any API consumer that POSTs to AddInboundClient
without a subId) ended up with an empty SubID, which breaks the panel's
sub-link generation. Backfill them once at startup and stop the gap at
the write path so new clients can't reintroduce it.
- util/random: add NumLower(n) — 16-char [0-9a-z] generator that matches
the frontend's RandomUtil.randomLowerAndNum convention.
- database/db.go: new InboundClientSubIdFix seeder, modeled on
InboundClientTgIdFix. Loops every inbound, parses settings.clients,
fills empty/missing subId with random.NumLower(16), persists via the
same transaction-wrapped Update("settings", …) path, then records in
HistoryOfSeeders so it runs at most once.
- web/service/client.go: defense-in-depth in AddInboundClient and
UpdateInboundClient — fill subId on the persisted settings map when
the payload omits it (Update prefers the previous value before
generating a fresh one).
- database/db_seed_test: cover empty subId, missing-key subId, and
preserved-existing subId; assert exactly one HistoryOfSeeders row.
This commit is contained in:
@@ -2880,6 +2880,10 @@ func (s *ClientService) AddInboundClient(inboundSvc *InboundService, data *model
|
||||
cm["created_at"] = nowTs
|
||||
}
|
||||
cm["updated_at"] = nowTs
|
||||
existingSub, _ := cm["subId"].(string)
|
||||
if strings.TrimSpace(existingSub) == "" {
|
||||
cm["subId"] = random.NumLower(16)
|
||||
}
|
||||
interfaceClients[i] = cm
|
||||
}
|
||||
}
|
||||
@@ -3118,11 +3122,13 @@ func (s *ClientService) UpdateInboundClient(inboundSvc *InboundService, data *mo
|
||||
}
|
||||
settingsClients := oldSettings["clients"].([]any)
|
||||
var preservedCreated any
|
||||
var preservedSubID string
|
||||
if clientIndex >= 0 && clientIndex < len(settingsClients) {
|
||||
if oldMap, ok := settingsClients[clientIndex].(map[string]any); ok {
|
||||
if v, ok2 := oldMap["created_at"]; ok2 {
|
||||
preservedCreated = v
|
||||
}
|
||||
preservedSubID, _ = oldMap["subId"].(string)
|
||||
}
|
||||
}
|
||||
if len(interfaceClients) > 0 {
|
||||
@@ -3132,6 +3138,14 @@ func (s *ClientService) UpdateInboundClient(inboundSvc *InboundService, data *mo
|
||||
}
|
||||
newMap["created_at"] = preservedCreated
|
||||
newMap["updated_at"] = time.Now().Unix() * 1000
|
||||
newSub, _ := newMap["subId"].(string)
|
||||
if strings.TrimSpace(newSub) == "" {
|
||||
if strings.TrimSpace(preservedSubID) != "" {
|
||||
newMap["subId"] = preservedSubID
|
||||
} else {
|
||||
newMap["subId"] = random.NumLower(16)
|
||||
}
|
||||
}
|
||||
interfaceClients[0] = newMap
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user