1
0

xdns_finalmask_migration_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package database
  2. import (
  3. "encoding/json"
  4. "testing"
  5. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  6. )
  7. const legacyXdnsFinalmask = `{"udp":[{"type":"xdns","settings":{"domains":["t.example.com"]}}]}`
  8. // assertXdnsUpgraded fails unless the finalmask's xdns domains are objects, the only
  9. // shape xray-core 26.9.30 parses.
  10. func assertXdnsUpgraded(t *testing.T, where string, finalmask any) {
  11. t.Helper()
  12. fm, _ := finalmask.(map[string]any)
  13. udp, _ := fm["udp"].([]any)
  14. if len(udp) != 1 {
  15. t.Fatalf("%s: udp masks = %v, want one", where, fm["udp"])
  16. }
  17. mask, _ := udp[0].(map[string]any)
  18. settings, _ := mask["settings"].(map[string]any)
  19. domains, _ := settings["domains"].([]any)
  20. if len(domains) != 1 {
  21. t.Fatalf("%s: domains = %v, want one entry", where, settings["domains"])
  22. }
  23. domain, ok := domains[0].(map[string]any)
  24. if !ok || domain["name"] != "t.example.com" {
  25. t.Fatalf("%s: domain = %#v, want an object named t.example.com", where, domains[0])
  26. }
  27. }
  28. func TestXdnsFinalmaskSeederUpgradesEveryStoredMask(t *testing.T) {
  29. initMigrateDB(t)
  30. ib := seedInboundWithStream(t, "xdns-in", 5353,
  31. `{"network":"kcp","security":"none","finalmask":`+legacyXdnsFinalmask+`}`)
  32. host := &model.Host{InboundId: ib.Id, Remark: "h", Address: "cdn.example.com", Port: 53, FinalMask: legacyXdnsFinalmask}
  33. if err := GetDB().Create(host).Error; err != nil {
  34. t.Fatalf("create host: %v", err)
  35. }
  36. seedTemplate(t, `{"outbounds":[{"protocol":"vless","tag":"dns-tunnel","settings":{},"streamSettings":{"network":"kcp","finalmask":`+legacyXdnsFinalmask+`}}]}`)
  37. if err := GetDB().Create(&model.Setting{Key: "subJsonFinalMask", Value: legacyXdnsFinalmask}).Error; err != nil {
  38. t.Fatalf("seed subJsonFinalMask: %v", err)
  39. }
  40. sub := &model.OutboundSubscription{
  41. Remark: "donor", Url: "https://donor.example.com/sub",
  42. LastFetchedOutbounds: `[{"protocol":"vless","tag":"sub-1","settings":{},"streamSettings":{"network":"kcp","finalmask":` + legacyXdnsFinalmask + `}}]`,
  43. }
  44. if err := GetDB().Create(sub).Error; err != nil {
  45. t.Fatalf("create outbound subscription: %v", err)
  46. }
  47. if err := GetDB().Where("seeder_name = ?", "XdnsFinalmaskObjectsFix").
  48. Delete(&model.HistoryOfSeeders{}).Error; err != nil {
  49. t.Fatalf("clear seeder history: %v", err)
  50. }
  51. if err := runSeeders(false); err != nil {
  52. t.Fatalf("runSeeders: %v", err)
  53. }
  54. var stored model.Inbound
  55. if err := GetDB().First(&stored, ib.Id).Error; err != nil {
  56. t.Fatalf("reload inbound: %v", err)
  57. }
  58. var stream map[string]any
  59. if err := json.Unmarshal([]byte(stored.StreamSettings), &stream); err != nil {
  60. t.Fatalf("inbound stream is not JSON: %v", err)
  61. }
  62. assertXdnsUpgraded(t, "inbound stream", stream["finalmask"])
  63. var storedHost model.Host
  64. if err := GetDB().First(&storedHost, host.Id).Error; err != nil {
  65. t.Fatalf("reload host: %v", err)
  66. }
  67. var hostMask any
  68. if err := json.Unmarshal([]byte(storedHost.FinalMask), &hostMask); err != nil {
  69. t.Fatalf("host finalMask is not JSON: %v", err)
  70. }
  71. assertXdnsUpgraded(t, "host finalMask", hostMask)
  72. var template struct {
  73. Outbounds []struct {
  74. StreamSettings struct {
  75. Finalmask any `json:"finalmask"`
  76. } `json:"streamSettings"`
  77. } `json:"outbounds"`
  78. }
  79. if err := json.Unmarshal([]byte(storedTemplate(t)), &template); err != nil || len(template.Outbounds) != 1 {
  80. t.Fatalf("stored template unreadable (%v)", err)
  81. }
  82. assertXdnsUpgraded(t, "template outbound", template.Outbounds[0].StreamSettings.Finalmask)
  83. var subMask model.Setting
  84. if err := GetDB().Where("key = ?", "subJsonFinalMask").First(&subMask).Error; err != nil {
  85. t.Fatalf("reload subJsonFinalMask: %v", err)
  86. }
  87. var subFinalmask any
  88. if err := json.Unmarshal([]byte(subMask.Value), &subFinalmask); err != nil {
  89. t.Fatalf("subJsonFinalMask is not JSON: %v", err)
  90. }
  91. assertXdnsUpgraded(t, "subJsonFinalMask", subFinalmask)
  92. var storedSub model.OutboundSubscription
  93. if err := GetDB().First(&storedSub, sub.Id).Error; err != nil {
  94. t.Fatalf("reload outbound subscription: %v", err)
  95. }
  96. var cached []struct {
  97. StreamSettings struct {
  98. Finalmask any `json:"finalmask"`
  99. } `json:"streamSettings"`
  100. }
  101. if err := json.Unmarshal([]byte(storedSub.LastFetchedOutbounds), &cached); err != nil || len(cached) != 1 {
  102. t.Fatalf("cached subscription outbounds unreadable (%v)", err)
  103. }
  104. assertXdnsUpgraded(t, "cached subscription outbound", cached[0].StreamSettings.Finalmask)
  105. }