freedom_finalrules_migration_test.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. package database
  2. import (
  3. "encoding/json"
  4. "testing"
  5. )
  6. func TestRewriteFreedomFinalRulesPrivateEgress(t *testing.T) {
  7. hardened := []any{
  8. map[string]any{"action": "block", "ip": []any{"geoip:private"}},
  9. map[string]any{"action": "allow"},
  10. }
  11. tests := []struct {
  12. name string
  13. raw string
  14. wantChanged bool
  15. wantRules []any
  16. }{
  17. {
  18. name: "allow-only default is hardened",
  19. raw: `{"outbounds":[{"protocol":"freedom","settings":{"domainStrategy":"AsIs","finalRules":[{"action":"allow"}]},"tag":"direct"}]}`,
  20. wantChanged: true,
  21. wantRules: hardened,
  22. },
  23. {
  24. name: "legacy private-only allow is hardened",
  25. raw: `{"outbounds":[{"protocol":"freedom","settings":{"finalRules":[{"action":"allow","ip":["geoip:private"]}]},"tag":"direct"}]}`,
  26. wantChanged: true,
  27. wantRules: hardened,
  28. },
  29. {
  30. name: "customized rules are preserved",
  31. raw: `{"outbounds":[{"protocol":"freedom","settings":{"finalRules":[{"action":"block","ip":["1.2.3.4"]},{"action":"allow"}]},"tag":"direct"}]}`,
  32. wantChanged: false,
  33. },
  34. {
  35. name: "non-freedom outbounds are ignored",
  36. raw: `{"outbounds":[{"protocol":"blackhole","settings":{},"tag":"blocked"}]}`,
  37. wantChanged: false,
  38. },
  39. {
  40. name: "empty config is untouched",
  41. raw: "",
  42. wantChanged: false,
  43. },
  44. }
  45. for _, tc := range tests {
  46. t.Run(tc.name, func(t *testing.T) {
  47. updated, changed, err := rewriteFreedomFinalRulesPrivateEgress(tc.raw)
  48. if err != nil {
  49. t.Fatalf("unexpected error: %v", err)
  50. }
  51. if changed != tc.wantChanged {
  52. t.Fatalf("changed = %v, want %v", changed, tc.wantChanged)
  53. }
  54. if !tc.wantChanged {
  55. if updated != tc.raw {
  56. t.Fatalf("raw config mutated without change flag:\n%s", updated)
  57. }
  58. return
  59. }
  60. var cfg map[string]any
  61. if err := json.Unmarshal([]byte(updated), &cfg); err != nil {
  62. t.Fatalf("updated config is not valid json: %v", err)
  63. }
  64. outbounds := cfg["outbounds"].([]any)
  65. settings := outbounds[0].(map[string]any)["settings"].(map[string]any)
  66. gotRules, _ := json.Marshal(settings["finalRules"])
  67. wantRules, _ := json.Marshal(tc.wantRules)
  68. if string(gotRules) != string(wantRules) {
  69. t.Fatalf("finalRules = %s, want %s", gotRules, wantRules)
  70. }
  71. })
  72. }
  73. }
  74. func TestRewriteFreedomFinalRulesPrivateEgressInvalidJSON(t *testing.T) {
  75. _, changed, err := rewriteFreedomFinalRulesPrivateEgress("{not json")
  76. if err == nil {
  77. t.Fatal("expected a json error for malformed config")
  78. }
  79. if changed {
  80. t.Fatal("malformed config must not report changed")
  81. }
  82. }