libs/cbi: drop UVL, introduce server side datatype validation
[project/luci.git] / libs / cbi / luasrc / cbi / datatypes.lua
1 --[[
2
3 LuCI - Configuration Bind Interface - Datatype Tests
4 (c) 2010 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10         http://www.apache.org/licenses/LICENSE-2.0
11
12 $Id$
13
14 ]]--
15
16 local fs = require "nixio.fs"
17 local ip = require "luci.ip"
18 local math = require "math"
19 local util = require "luci.util"
20
21 local tonumber = tonumber
22
23 module "luci.cbi.datatypes"
24
25
26 function bool( val )
27         if val == "1" or val == "yes" or val == "on" or val == "true" then
28                 return true
29         elseif val == "0" or val == "no" or val == "off" or val == "false" then
30                 return true
31         elseif val == "" or val == nil then
32                 return true
33         end
34
35         return false
36 end
37
38 function uint( val )
39         local n = tonumber(val)
40         if n ~= nil and math.floor(n) == n and n >= 0 then
41                 return true
42         end
43
44         return false
45 end
46
47 function int( val )
48         local n = tonumber(val)
49         if n ~= nil and math.floor(n) == n then
50                 return true
51         end
52
53         return false
54 end
55
56 function float( val )
57         return ( tonumber(val) ~= nil )
58 end
59
60 function ipaddr( val )
61         return ip4addr(val) or ip6addr(val)
62 end
63
64 function ip4addr( val )
65         if val then
66                 return ip.IPv4(val) and true or false
67         end
68
69         return false
70 end
71
72 function ip4prefix( val )
73         val = tonumber(val)
74         return ( val and val >= 0 and val <= 32 )
75 end
76
77 function ip6addr( val )
78         if val then
79                 return ip.IPv6(val) and true or false
80         end
81
82         return false
83 end
84
85 function ip6prefix( val )
86         val = tonumber(val)
87         return ( val and val >= 0 and val <= 128 )
88 end
89
90 function port( val )
91         val = tonumber(val)
92         return ( val and val >= 1 and val <= 65535 )
93 end
94
95 function portrange( val )
96         local p1, p2 = val:match("^(%d+)%-(%d+)$")
97         if p1 and p2 and port(p1) and port(p2) then
98                 return true
99         else
100                 return port(val)
101         end
102 end
103
104 function macaddr( val )
105         if val and val:match(
106                 "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
107                  "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
108         ) then
109                 local parts = util.split( val, ":" )
110
111                 for i = 1,6 do
112                         parts[i] = tonumber( parts[i], 16 )
113                         if parts[i] < 0 or parts[i] > 255 then
114                                 return false
115                         end
116                 end
117
118                 return true
119         end
120
121         return false
122 end
123
124 function hostname( val )
125         if val and val:match("[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*") then
126                 return true     -- XXX: ToDo: need better solution
127         end
128
129         return false
130 end
131
132 function host( val )
133         return hostname(val) or ipaddr(val)
134 end
135
136 function string( val )
137         return true             -- Everything qualifies as valid string
138 end
139
140 function directory( val, seen )
141         local s = fs.stat( val )
142         seen = seen or { }
143
144         if s and not seen[s.ino] then
145                 seen[s.ino] = true
146                 if s.type == "dir" then
147                         return true
148                 elseif s.type == "lnk" then
149                         return directory( fs.readlink(val), seen )
150                 end
151         end
152
153         return false
154 end
155
156 function file( val, seen )
157         local s = fs.stat( val )
158         seen = seen or { }
159
160         if s and not seen[s.ino] then
161                 seen[s.ino] = true
162                 if s.type == "reg" then
163                         return true
164                 elseif s.type == "lnk" then
165                         return file( fs.readlink(val), seen )
166                 end
167         end
168
169         return false
170 end
171
172 function device( val, seen )
173         local s = fs.stat( val )
174         seen = seen or { }
175
176         if s and not seen[s.ino] then
177                 seen[s.ino] = true
178                 if s.type == "chr" or s.type == "blk" then
179                         return true
180                 elseif s.type == "lnk" then
181                         return device( fs.readlink(val), seen )
182                 end
183         end
184
185         return false
186 end