mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-17 01:56:06 +00:00
fix(mtproto): stop persisting a vestigial inbound-level secret
MTProto is multi-client: mtg's [secrets] config and every share link read only the per-client secrets. The old HealMtprotoSecret regenerated an inbound-level secret on every save, and seedMtprotoSecretsToClients only dropped it for legacy single-secret inbounds, so multi-client inbounds kept a dead secret. That value once leaked into stale links imported into Telegram, which mtg then rejected as "incorrect client random". Replace HealMtprotoSecret with StripMtprotoInboundSecret (removes the key), strip on save in normalizeMtprotoSecret, and add a one-time stripMtprotoInboundSecrets migration that runs after the seeder so a legacy secret is first preserved onto a client before the inbound-level copy is dropped.
This commit is contained in:
@@ -477,6 +477,42 @@ func seedMtprotoSecretsToClients() error {
|
||||
})
|
||||
}
|
||||
|
||||
// stripMtprotoInboundSecrets removes the vestigial inbound-level `secret` from
|
||||
// every mtproto inbound. seedMtprotoSecretsToClients already drops it while
|
||||
// converting legacy single-secret inbounds, but inbounds that already had clients
|
||||
// kept the dead field, and the old HealMtprotoSecret regenerated it on every
|
||||
// save. mtg and every share link read only per-client secrets, so the
|
||||
// inbound-level value is dead data that once leaked into stale, unusable links.
|
||||
// One-time, self-gated on the "StripMtprotoInboundSecrets" seeder row.
|
||||
func stripMtprotoInboundSecrets() error {
|
||||
var history []string
|
||||
if err := db.Model(&model.HistoryOfSeeders{}).Pluck("seeder_name", &history).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if slices.Contains(history, "StripMtprotoInboundSecrets") {
|
||||
return nil
|
||||
}
|
||||
|
||||
var inbounds []model.Inbound
|
||||
if err := db.Where("protocol = ?", string(model.MTProto)).Find(&inbounds).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.Transaction(func(tx *gorm.DB) error {
|
||||
for _, inbound := range inbounds {
|
||||
stripped, ok := model.StripMtprotoInboundSecret(inbound.Settings)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err := tx.Model(&model.Inbound{}).Where("id = ?", inbound.Id).
|
||||
Update("settings", stripped).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Create(&model.HistoryOfSeeders{SeederName: "StripMtprotoInboundSecrets"}).Error
|
||||
})
|
||||
}
|
||||
|
||||
// mtprotoInboundClientEmail derives a stable, unique client email for a migrated
|
||||
// mtproto inbound from its remark.
|
||||
func mtprotoInboundClientEmail(remark string, used map[string]struct{}) string {
|
||||
@@ -925,6 +961,14 @@ func runSeeders(isUsersEmpty bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Self-gated on the "StripMtprotoInboundSecrets" row. Must run after the
|
||||
// seeder above so legacy single-secret inbounds are first converted to a
|
||||
// client (which preserves the secret) before the inbound-level copy is
|
||||
// dropped from every mtproto inbound.
|
||||
if err := stripMtprotoInboundSecrets(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Idempotent, not seeder-gated: bad values can re-enter via a restored
|
||||
// backup, so re-check on every start.
|
||||
return normalizeSettingPaths()
|
||||
|
||||
Reference in New Issue
Block a user