mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 11:15:03 +03:00
fix(database): keep disabled clients disabled in the ClientsTable seeder
The one-time ClientsTable migration builds client records from each inbound's settings with a plain Create, and gorm's default:true on ClientRecord.Enable drops an explicit false from that insert. Every client an operator had disabled before v3.1.0 was therefore stored enabled on an in-place upgrade or a restored backup, and Xray, which now reads that column, let the customer back in. The seeder restates enable=false after Create, as the service paths do since #6478, and a legacy client whose settings carry no switch stays enabled, as releases before 3.1.0 served it.
This commit is contained in:
@@ -3197,6 +3197,11 @@ func seedClientsFromInboundJSON() error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
model.NormalizeLegacyClientFields(obj)
|
model.NormalizeLegacyClientFields(obj)
|
||||||
|
// Releases before 3.1.0 served a client whose JSON carries no
|
||||||
|
// switch; only an explicit false means disabled.
|
||||||
|
if obj["enable"] == nil {
|
||||||
|
obj["enable"] = true
|
||||||
|
}
|
||||||
blob, err := json.Marshal(obj)
|
blob, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
@@ -3218,6 +3223,14 @@ func seedClientsFromInboundJSON() error {
|
|||||||
if err := tx.Create(incoming).Error; err != nil {
|
if err := tx.Create(incoming).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// gorm default:true drops enable=false on Create — restate (#6478).
|
||||||
|
if !c.Enable {
|
||||||
|
if err := tx.Model(&model.ClientRecord{}).Where("id = ?", incoming.Id).
|
||||||
|
UpdateColumn("enable", false).Error; err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
incoming.Enable = false
|
||||||
|
}
|
||||||
byEmail[email] = incoming
|
byEmail[email] = incoming
|
||||||
row = incoming
|
row = incoming
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -220,6 +220,47 @@ func TestSeedClientsFromInboundJSON_IsIdempotentAgainstExistingClients(t *testin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSeedClientsFromInboundJSON_KeepsTheManualSwitch(t *testing.T) {
|
||||||
|
dbDir := t.TempDir()
|
||||||
|
t.Setenv("XUI_DB_FOLDER", dbDir)
|
||||||
|
if err := InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
|
||||||
|
t.Fatalf("InitDB failed: %v", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() { _ = CloseDB() })
|
||||||
|
|
||||||
|
inbound := model.Inbound{
|
||||||
|
UserId: 1,
|
||||||
|
Port: 12345,
|
||||||
|
Protocol: model.VLESS,
|
||||||
|
Settings: `{"clients": [
|
||||||
|
{"id": "ce8d33df-3a64-4f10-8f9b-91c3a8e0c001", "email": "paying", "enable": true},
|
||||||
|
{"id": "ce8d33df-3a64-4f10-8f9b-91c3a8e0c002", "email": "banned", "enable": false},
|
||||||
|
{"id": "ce8d33df-3a64-4f10-8f9b-91c3a8e0c003", "email": "no-switch"}
|
||||||
|
]}`,
|
||||||
|
Tag: "test-inbound",
|
||||||
|
}
|
||||||
|
if err := db.Create(&inbound).Error; err != nil {
|
||||||
|
t.Fatalf("seed inbound: %v", err)
|
||||||
|
}
|
||||||
|
if err := db.Where("seeder_name = ?", "ClientsTable").Delete(&model.HistoryOfSeeders{}).Error; err != nil {
|
||||||
|
t.Fatalf("clear ClientsTable history: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := seedClientsFromInboundJSON(); err != nil {
|
||||||
|
t.Fatalf("seedClientsFromInboundJSON: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for email, want := range map[string]bool{"paying": true, "banned": false, "no-switch": true} {
|
||||||
|
var row model.ClientRecord
|
||||||
|
if err := db.Where("email = ?", email).First(&row).Error; err != nil {
|
||||||
|
t.Fatalf("read client %s: %v", email, err)
|
||||||
|
}
|
||||||
|
if row.Enable != want {
|
||||||
|
t.Errorf("client %s migrated with enable = %v, want %v", email, row.Enable, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNormalizeInboundClientSubId_FillsMissingAndPreservesExisting(t *testing.T) {
|
func TestNormalizeInboundClientSubId_FillsMissingAndPreservesExisting(t *testing.T) {
|
||||||
dbDir := t.TempDir()
|
dbDir := t.TempDir()
|
||||||
t.Setenv("XUI_DB_FOLDER", dbDir)
|
t.Setenv("XUI_DB_FOLDER", dbDir)
|
||||||
|
|||||||
Reference in New Issue
Block a user