mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-08-26 04:57:19 +00:00
fix(client): match clients by email for delete/update, not credentials
Delete/update located the client in an inbound's settings JSON by the record's credential (uuid/password/auth). When that credential drifted from the inbound JSON -- e.g. a rotated UUID left behind, or duplicated by a past partial-update bug -- the lookup failed with "Client Not Found In Inbound For ID: <uuid>" and aborted the whole operation, making the client impossible to remove from the panel. Key every delete/update/detach path on email, the client's stable identity. This survives credential drift and heals duplicate-email entries by removing all of them. - Delete/DeleteByEmail/Detach/DetachByEmailMany -> DelInboundClientByEmail - delInboundClients / bulkDelInboundClients: match settings by email - UpdateInboundClient: locate the entry to replace by email (param clientId -> oldEmail); update all callers to pass the email - bulkAdjustInboundClients: match by email - writeBackClientSubID: pass email; drop unused sourceProtocol param - make per-inbound deletion idempotent via ErrClientNotInInbound - remove now-orphaned DelInboundClient, clientKeyForProtocol and getClientPrimaryKey; scale test deletes by email
This commit is contained in:
+5
-19
@@ -1402,25 +1402,11 @@ func (s *InboundService) updateClientTraffics(tx *gorm.DB, oldInbound *model.Inb
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *InboundService) getClientPrimaryKey(protocol model.Protocol, client model.Client) string {
|
||||
switch protocol {
|
||||
case model.Trojan:
|
||||
return client.Password
|
||||
case model.Shadowsocks:
|
||||
return client.Email
|
||||
case model.Hysteria:
|
||||
return client.Auth
|
||||
default:
|
||||
return client.ID
|
||||
}
|
||||
}
|
||||
|
||||
func (s *InboundService) writeBackClientSubID(sourceInboundID int, sourceProtocol model.Protocol, client model.Client, subID string) (bool, error) {
|
||||
func (s *InboundService) writeBackClientSubID(sourceInboundID int, client model.Client, subID string) (bool, error) {
|
||||
client.SubID = subID
|
||||
client.UpdatedAt = time.Now().UnixMilli()
|
||||
clientID := s.getClientPrimaryKey(sourceProtocol, client)
|
||||
if clientID == "" {
|
||||
return false, common.NewError("empty client ID")
|
||||
if client.Email == "" {
|
||||
return false, common.NewError("empty client email")
|
||||
}
|
||||
|
||||
settingsBytes, err := json.Marshal(map[string][]model.Client{
|
||||
@@ -1434,7 +1420,7 @@ func (s *InboundService) writeBackClientSubID(sourceInboundID int, sourceProtoco
|
||||
Id: sourceInboundID,
|
||||
Settings: string(settingsBytes),
|
||||
}
|
||||
return s.clientService.UpdateInboundClient(s, updatePayload, clientID)
|
||||
return s.clientService.UpdateInboundClient(s, updatePayload, client.Email)
|
||||
}
|
||||
|
||||
func (s *InboundService) generateRandomCredential(targetProtocol model.Protocol) string {
|
||||
@@ -1554,7 +1540,7 @@ func (s *InboundService) CopyInboundClients(targetInboundID int, sourceInboundID
|
||||
|
||||
if sourceClient.SubID == "" {
|
||||
newSubID := uuid.NewString()
|
||||
subNeedRestart, subErr := s.writeBackClientSubID(sourceInbound.Id, sourceInbound.Protocol, sourceClient, newSubID)
|
||||
subNeedRestart, subErr := s.writeBackClientSubID(sourceInbound.Id, sourceClient, newSubID)
|
||||
if subErr != nil {
|
||||
result.Errors = append(result.Errors, fmt.Sprintf("%s: failed to write source subId: %v", originalEmail, subErr))
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user