mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 11:15:03 +03:00
fix(database): replace the stored session secret once on upgrade
The session cookie key is generated once and kept forever. Keys stored by older releases came from a weaker generator, and a stored value cannot be told apart from a current one, so drop it once through a seeder and let GetSecret store a fresh crypto/rand key on the next start. Admins log in again once after upgrading; fresh installs record the seeder up front.
This commit is contained in:
@@ -107,6 +107,56 @@ func TestEnsureFirstUserCreatesOneWorkingCredential(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Old releases drew the cookie-signing secret from a clock-seeded math/rand, and a
|
||||
// stored value cannot tell its generator, so an upgrade must replace it exactly once.
|
||||
func TestSessionSecretRotatesOnceOnUpgrade(t *testing.T) {
|
||||
dbPath := filepath.Join(t.TempDir(), "x-ui.db")
|
||||
if err := InitDB(dbPath); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = CloseDB() })
|
||||
reopen := func() []string {
|
||||
t.Helper()
|
||||
if err := CloseDB(); err != nil {
|
||||
t.Fatalf("CloseDB: %v", err)
|
||||
}
|
||||
if err := InitDB(dbPath); err != nil {
|
||||
t.Fatalf("reopen InitDB: %v", err)
|
||||
}
|
||||
var secrets []string
|
||||
if err := db.Model(&model.Setting{}).Where("key = ?", "secret").Pluck("value", &secrets).Error; err != nil {
|
||||
t.Fatalf("read secret: %v", err)
|
||||
}
|
||||
return secrets
|
||||
}
|
||||
storeSecret := func(value string) {
|
||||
t.Helper()
|
||||
if err := db.Where("key = ?", "secret").Delete(&model.Setting{}).Error; err != nil {
|
||||
t.Fatalf("clear secret: %v", err)
|
||||
}
|
||||
if err := db.Create(&model.Setting{Key: "secret", Value: value}).Error; err != nil {
|
||||
t.Fatalf("store secret: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
storeSecret("kept-on-a-fresh-install")
|
||||
if got := reopen(); len(got) != 1 || got[0] != "kept-on-a-fresh-install" {
|
||||
t.Fatalf("fresh install secret = %q after restart, want it kept", got)
|
||||
}
|
||||
|
||||
storeSecret("rfBd56ti2SMtYvSgD5xAV0YU99zampta")
|
||||
if err := db.Where("seeder_name = ?", "SessionSecretRotation").Delete(&model.HistoryOfSeeders{}).Error; err != nil {
|
||||
t.Fatalf("clear seeder history: %v", err)
|
||||
}
|
||||
if got := reopen(); len(got) != 0 {
|
||||
t.Fatalf("secret = %q after upgrade, want the pre-upgrade secret dropped", got)
|
||||
}
|
||||
storeSecret("drawn-after-upgrade")
|
||||
if got := reopen(); len(got) != 1 || got[0] != "drawn-after-upgrade" {
|
||||
t.Fatalf("secret = %q, want the rotated secret kept so restarts do not log everyone out", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedClientsFromInboundJSON_IsIdempotentAgainstExistingClients(t *testing.T) {
|
||||
dbDir := t.TempDir()
|
||||
t.Setenv("XUI_DB_FOLDER", dbDir)
|
||||
|
||||
Reference in New Issue
Block a user