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
|
--[[
Copyright (c) 2012-2013 Kaarle Ritvanen
See LICENSE file for license details
--]]
local M = {}
local raise = require('acf.error').raise
local Union = require('acf.model.combination').Union
local fld = require('acf.model.field')
local String = fld.String
local object = require('acf.object')
local class = object.class
local super = object.super
local update = require('acf.util').update
local stringy = require('stringy')
M.IPv4Address = class(String)
function M.IPv4Address:validate(context, value)
super(self, M.IPv4Address):validate(context, value)
local function test(...)
if #{...} ~= 4 then return true end
for _, octet in ipairs{...} do
if tonumber(octet) > 255 then return true end
end
end
if test(value:match('^(%d+)%.(%d+)%.(%d+)%.(%d+)$')) then
raise(context.path, 'Invalid IPv4 address')
end
end
M.IPv6Address = class(String)
function M.IPv6Address:validate(context, value)
super(self, M.IPv6Address):validate(context, value)
local function invalid() raise(context.path, 'Invalid IPv6 address') end
if value == '' then invalid() end
local comps = stringy.split(value, ':')
if #comps < 3 then invalid() end
local function collapse(i, ofs)
if comps[i] > '' then return end
if comps[i + ofs] > '' then invalid() end
table.remove(comps, i)
end
collapse(1, 1)
collapse(#comps, -1)
if #comps > 8 then invalid() end
local short = false
for _, comp in ipairs(comps) do
if comp == '' then
if short then invalid() end
short = true
elseif not comp:match('^%x%x?%x?%x?$') then invalid() end
end
if (
short and #comps == 3 and comps[2] == ''
) or (not short and #comps < 8) then
invalid()
end
end
M.IPAddress = class(Union)
function M.IPAddress:init(params)
super(self, M.IPAddress):init(
update(
params,
{types={M.IPv4Address, M.IPv6Address}, error='Invalid IP address'}
)
)
end
M.Port = class(fld.Integer)
function M.Port:validate(context, value)
super(self, M.Port):validate(context, value)
if value < 0 or value > 65535 then raise(context.path, 'Invalid port') end
end
return M
|