diff options
Diffstat (limited to 'acf2/model/net.lua')
-rw-r--r-- | acf2/model/net.lua | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/acf2/model/net.lua b/acf2/model/net.lua new file mode 100644 index 0000000..27ab262 --- /dev/null +++ b/acf2/model/net.lua @@ -0,0 +1,96 @@ +--[[ +Copyright (c) 2012-2013 Kaarle Ritvanen +See LICENSE file for license details +--]] + +local M = {} + +local raise = require('acf2.error').raise +local Union = require('acf2.model.combination').Union + +local fld = require('acf2.model.field') +local String = fld.String + +local object = require('acf2.object') +local class = object.class +local super = object.super + +local update = require('acf2.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 |