mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 19:25:05 +03:00
fix(clients): purge depleted clients by their exact usage key
DelDepleted turned the emails of depleted usage rows into client identities through BulkDelete, which trims each email for request bodies. A depleted row keyed by a padded email, which a node's stats could store and which belongs to no client, therefore resolved to the healthy client it resembled and deleted it. Rows whose key carries surrounding white space name no client and are skipped.
This commit is contained in:
@@ -204,3 +204,30 @@ func TestGetClientTrafficByEmailReadsClientsTable(t *testing.T) {
|
|||||||
t.Fatalf("SubId not enriched from clients table, got %q", tr.SubId)
|
t.Fatalf("SubId not enriched from clients table, got %q", tr.SubId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A depleted usage row keyed by a padded email belongs to no client; trimming it on the
|
||||||
|
// way to BulkDelete deleted the healthy client it resembles.
|
||||||
|
func TestDelDepletedIgnoresPaddedUsageRow(t *testing.T) {
|
||||||
|
setupBulkDB(t)
|
||||||
|
svc := &ClientService{}
|
||||||
|
inboundSvc := &InboundService{}
|
||||||
|
|
||||||
|
source := []model.Client{{Email: "alice@x", ID: "11111111-1111-1111-1111-111111111111", SubID: "sa", Enable: true}}
|
||||||
|
ib := mkInbound(t, 21003, model.VLESS, clientsSettings(t, source))
|
||||||
|
if err := svc.SyncInbound(nil, ib.Id, source); err != nil {
|
||||||
|
t.Fatalf("seed linkage: %v", err)
|
||||||
|
}
|
||||||
|
mkTraffic(t, ib.Id, "alice@x", 0, 0, 0, 0, true)
|
||||||
|
mkTraffic(t, ib.Id, "alice@x ", 0, 0, 0, 1, false)
|
||||||
|
|
||||||
|
deleted, _, err := svc.DelDepleted(inboundSvc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("DelDepleted: %v", err)
|
||||||
|
}
|
||||||
|
if deleted != 0 {
|
||||||
|
t.Fatalf("deleted %d clients, want 0", deleted)
|
||||||
|
}
|
||||||
|
if _, err := svc.GetRecordByEmail(nil, "alice@x"); err != nil {
|
||||||
|
t.Fatalf("alice was deleted through a look-alike usage row: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1533,8 +1533,9 @@ func (s *ClientService) DelDepleted(inboundSvc *InboundService) (int, bool, erro
|
|||||||
|
|
||||||
seen := make(map[string]struct{}, len(rows))
|
seen := make(map[string]struct{}, len(rows))
|
||||||
emails := make([]string, 0, len(rows))
|
emails := make([]string, 0, len(rows))
|
||||||
|
// BulkDelete trims each email, so a padded usage row would resolve to the client it resembles.
|
||||||
for _, r := range rows {
|
for _, r := range rows {
|
||||||
if r.Email == "" {
|
if r.Email == "" || r.Email != strings.TrimSpace(r.Email) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := seen[r.Email]; ok {
|
if _, ok := seen[r.Email]; ok {
|
||||||
|
|||||||
Reference in New Issue
Block a user