File size: 4,832 Bytes
c9c49ab
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
defmodule Plausible.Shields.IPTest do
  use Plausible.DataCase
  import Plausible.Shields

  setup do
    site = insert(:site)
    {:ok, %{site: site}}
  end

  describe "add_ip_rule/2" do
    test "no input", %{site: site} do
      assert {:error, changeset} = add_ip_rule(site, %{})
      assert changeset.errors == [inet: {"can't be blank", [validation: :required]}]
      refute changeset.valid?
    end

    test "unsupported netmask", %{site: site} do
      assert {:error, changeset} = add_ip_rule(site, %{"inet" => "127.0.0.0/24"})
      assert changeset.errors == [inet: {"netmask unsupported", []}]
      refute changeset.valid?
      assert {:ok, _} = add_ip_rule(site, %{"inet" => "127.0.0.0/32"})
    end

    test "incorrect ip", %{site: site} do
      assert {:error, changeset} = add_ip_rule(site, %{"inet" => "999.999.999.999"})

      assert changeset.errors == [
               inet: {"is invalid", [{:type, EctoNetwork.INET}, {:validation, :cast}]}
             ]

      refute changeset.valid?
    end

    test "non-strict IPs", %{site: site} do
      assert {:error, _} = add_ip_rule(site, %{"inet" => "111"})
    end

    test "double insert", %{site: site} do
      assert {:ok, _} = add_ip_rule(site, %{"inet" => "0.0.0.111"})
      assert {:error, changeset} = add_ip_rule(site, %{"inet" => "0.0.0.111"})
      refute changeset.valid?

      assert changeset.errors == [
               inet:
                 {"has already been taken",
                  [
                    {:constraint, :unique},
                    {:constraint_name, "shield_rules_ip_site_id_inet_index"}
                  ]}
             ]
    end

    test "ipv6", %{site: site} do
      assert {:ok, rule} =
               add_ip_rule(site, %{"inet" => "2001:0000:130F:0000:0000:09C0:876A:130B"})

      assert ^rule = Repo.get(Plausible.Shield.IPRule, rule.id)
    end

    test "ipv4", %{site: site} do
      assert {:ok, rule} =
               add_ip_rule(site, %{"inet" => "1.1.1.1"})

      assert ^rule = Repo.get(Plausible.Shield.IPRule, rule.id)
    end

    test "over limit", %{site: site} do
      for i <- 1..maximum_ip_rules() do
        assert {:ok, _} =
                 add_ip_rule(site, %{"inet" => "1.1.1.#{i}"})
      end

      assert count_ip_rules(site) == maximum_ip_rules()

      assert {:error, changeset} =
               add_ip_rule(site, %{"inet" => "1.1.1.31"})

      refute changeset.valid?
      assert changeset.errors == [inet: {"maximum reached", []}]
    end

    test "with added_by", %{site: site} do
      assert {:ok, rule} =
               add_ip_rule(site, %{"inet" => "1.1.1.1"},
                 added_by: build(:user, name: "Joe", email: "joe@example.com")
               )

      assert rule.added_by == "Joe <joe@example.com>"
    end

    test "ignores site_id supplied in params", %{site: site} do
      victim = insert(:site)
      assert {:ok, rule} = add_ip_rule(site, %{"inet" => "1.2.3.4", "site_id" => victim.id})
      assert rule.site_id == site.id
      assert count_ip_rules(victim) == 0
    end
  end

  describe "remove_ip_rule/2" do
    test "is idempontent", %{site: site} do
      {:ok, rule} = add_ip_rule(site, %{"inet" => "127.0.0.1"})
      assert remove_ip_rule(site, rule.id) == :ok
      refute Repo.get(Plausible.Shield.IPRule, rule.id)
      assert remove_ip_rule(site, rule.id) == :ok
    end
  end

  describe "list_ip_rules/1" do
    test "empty", %{site: site} do
      assert(list_ip_rules(site) == [])
    end

    @tag :slow
    test "many", %{site: site} do
      {:ok, r1} = add_ip_rule(site, %{"inet" => "127.0.0.1"})
      :timer.sleep(1000)
      {:ok, r2} = add_ip_rule(site, %{"inet" => "127.0.0.2"})
      assert [^r2, ^r1] = list_ip_rules(site)
    end
  end

  describe "count_ip_rules/1" do
    test "counts", %{site: site} do
      assert count_ip_rules(site) == 0
      {:ok, _} = add_ip_rule(site, %{"inet" => "127.0.0.1"})
      assert count_ip_rules(site) == 1
      {:ok, _} = add_ip_rule(site, %{"inet" => "127.0.0.2"})
      assert count_ip_rules(site) == 2
    end
  end

  describe "IP Rules" do
    test "end to end", %{site: site} do
      site2 = insert(:site)

      assert count_ip_rules(site.id) == 0
      assert list_ip_rules(site.id) == []

      assert {:ok, rule} =
               add_ip_rule(site.id, %{"inet" => "127.0.0.1", "description" => "Localhost"})

      add_ip_rule(site2, %{"inet" => "127.0.0.1", "description" => "Localhost"})

      assert count_ip_rules(site) == 1
      assert [^rule] = list_ip_rules(site)
      assert rule.inet == %Postgrex.INET{address: {127, 0, 0, 1}, netmask: 32}
      assert rule.description == "Localhost"
      assert rule.action == :deny
      refute rule.from_cache?
      assert ip_blocked?(site, "127.0.0.1")
      refute ip_blocked?(site, "127.0.0.2")
    end
  end
end