Skip to content

Commit 3b2af3c

Browse files
authored
Merge pull request #31 from zaratedev/ip-address-validation
Add IP address validation whe is tuple
2 parents b812bee + 37917e9 commit 3b2af3c

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

lib/ecto_network/inet.ex

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ defmodule EctoNetwork.INET do
1818
@doc "Handle casting to Postgrex.INET."
1919
def cast(%Postgrex.INET{} = address), do: {:ok, address}
2020

21-
def cast(address) when is_tuple(address),
22-
do: cast(%Postgrex.INET{address: address, netmask: address_netmask(address)})
21+
def cast(address) when is_tuple(address) do
22+
if valid_ip_address?(address) do
23+
cast(%Postgrex.INET{address: address, netmask: address_netmask(address)})
24+
else
25+
:error
26+
end
27+
end
2328

2429
def cast(address) when is_binary(address) do
2530
{address, netmask} =
@@ -119,6 +124,16 @@ defmodule EctoNetwork.INET do
119124
end
120125

121126
defp cast_netmask(_mask, _address), do: :error
127+
128+
defp valid_ip_address?(ip_address) when is_tuple(ip_address) do
129+
case tuple_size(ip_address) do
130+
4 -> Enum.all?(Tuple.to_list(ip_address), &(is_integer(&1) and &1 >= 0 and &1 < 256))
131+
8 -> Enum.all?(Tuple.to_list(ip_address), &(is_integer(&1) and &1 >= 0 and &1 < 65536))
132+
_ -> false
133+
end
134+
end
135+
136+
defp valid_ip_address?(_), do: false
122137
end
123138

124139
defimpl String.Chars, for: Postgrex.INET do

test/ecto_network_test.exs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,14 @@ defmodule EctoNetworkTest do
9999
assert "#{device.ip_address}" == "127.0.0.1"
100100
end
101101

102+
test "rejects an IPv4 tuple with out-of-range values" do
103+
changeset = Device.changeset(%Device{}, %{ip_address: {300, 300, 300, 300}})
104+
{:error, changeset} = TestRepo.insert(changeset)
105+
106+
assert changeset.errors[:ip_address] ==
107+
{"is invalid", [type: EctoNetwork.INET, validation: :cast]}
108+
end
109+
102110
test "accepts ipv6 address as tuple and saves" do
103111
ip_address = {8193, 3512, 0, 0, 0, 65280, 66, 33577}
104112
short_ip_address = "2001:db8::ff00:42:8329"
@@ -109,6 +117,23 @@ defmodule EctoNetworkTest do
109117
assert String.downcase("#{device.ip_address}") == String.downcase(short_ip_address)
110118
end
111119

120+
test "rejects an IPv6 tuple with out-of-range values" do
121+
ip_address = {65536, 0, 0, 0, 0, 0, 0, 0}
122+
changeset = Device.changeset(%Device{}, %{ip_address: ip_address})
123+
{:error, changeset} = TestRepo.insert(changeset)
124+
125+
assert changeset.errors[:ip_address] ==
126+
{"is invalid", [type: EctoNetwork.INET, validation: :cast]}
127+
end
128+
129+
test "rejects tuples with incorrect size" do
130+
changeset = Device.changeset(%Device{}, %{ip_address: {1, 2, 3}})
131+
{:error, changeset} = TestRepo.insert(changeset)
132+
133+
assert changeset.errors[:ip_address] ==
134+
{"is invalid", [type: EctoNetwork.INET, validation: :cast]}
135+
end
136+
112137
test "accepts cidr address as binary and saves" do
113138
changeset = Device.changeset(%Device{}, %{network: "127.0.0.0/24"})
114139
device = TestRepo.insert!(changeset)

0 commit comments

Comments
 (0)