libs/web: allow one-character hostnames
[project/luci.git] / libs / web / 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 local tonumber, type = tonumber, type
21
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 uinteger(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 integer(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 ufloat(val)
57         local n = tonumber(val)
58         return ( n ~= nil and n >= 0 )
59 end
60
61 function float(val)
62         return ( tonumber(val) ~= nil )
63 end
64
65 function ipaddr(val)
66         return ip4addr(val) or ip6addr(val)
67 end
68
69 function neg_ipaddr(v)
70         if type(v) == "string" then
71                 v = v:gsub("^%s*!", "")
72         end
73         return v and ipaddr(v)
74 end
75
76 function ip4addr(val)
77         if val then
78                 return ip.IPv4(val) and true or false
79         end
80
81         return false
82 end
83
84 function neg_ip4addr(v)
85         if type(v) == "string" then
86                 v = v:gsub("^%s*!", "")
87         end
88                 return v and ip4addr(v)
89 end
90
91 function ip4prefix(val)
92         val = tonumber(val)
93         return ( val and val >= 0 and val <= 32 )
94 end
95
96 function ip6addr(val)
97         if val then
98                 return ip.IPv6(val) and true or false
99         end
100
101         return false
102 end
103
104 function ip6prefix(val)
105         val = tonumber(val)
106         return ( val and val >= 0 and val <= 128 )
107 end
108
109 function port(val)
110         val = tonumber(val)
111         return ( val and val >= 0 and val <= 65535 )
112 end
113
114 function portrange(val)
115         local p1, p2 = val:match("^(%d+)%-(%d+)$")
116         if p1 and p2 and port(p1) and port(p2) then
117                 return true
118         else
119                 return port(val)
120         end
121 end
122
123 function macaddr(val)
124         if val and val:match(
125                 "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
126                  "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
127         ) then
128                 local parts = util.split( val, ":" )
129
130                 for i = 1,6 do
131                         parts[i] = tonumber( parts[i], 16 )
132                         if parts[i] < 0 or parts[i] > 255 then
133                                 return false
134                         end
135                 end
136
137                 return true
138         end
139
140         return false
141 end
142
143 function hostname(val)
144         if val and (#val < 254) and (
145            val:match("^[a-zA-Z0-9]+$") or
146            val:match("^[a-zA-Z0-9][a-zA-Z0-9%-%.]*[a-zA-Z0-9]$")
147         ) then
148                 return true
149         end
150         return false
151 end
152
153 function host(val)
154         return hostname(val) or ipaddr(val)
155 end
156
157 function wpakey(val)
158         if #val == 64 then
159                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
160         else
161                 return (#val >= 8) and (#val <= 63)
162         end
163 end
164
165 function wepkey(val)
166         if val:sub(1, 2) == "s:" then
167                 val = val:sub(3)
168         end
169
170         if (#val == 10) or (#val == 26) then
171                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
172         else
173                 return (#val == 5) or (#val == 13)
174         end
175 end
176
177 function string(val)
178         return true             -- Everything qualifies as valid string
179 end
180
181 function directory( val, seen )
182         local s = fs.stat(val)
183         seen = seen or { }
184
185         if s and not seen[s.ino] then
186                 seen[s.ino] = true
187                 if s.type == "dir" then
188                         return true
189                 elseif s.type == "lnk" then
190                         return directory( fs.readlink(val), seen )
191                 end
192         end
193
194         return false
195 end
196
197 function file( val, seen )
198         local s = fs.stat(val)
199         seen = seen or { }
200
201         if s and not seen[s.ino] then
202                 seen[s.ino] = true
203                 if s.type == "reg" then
204                         return true
205                 elseif s.type == "lnk" then
206                         return file( fs.readlink(val), seen )
207                 end
208         end
209
210         return false
211 end
212
213 function device( val, seen )
214         local s = fs.stat(val)
215         seen = seen or { }
216
217         if s and not seen[s.ino] then
218                 seen[s.ino] = true
219                 if s.type == "chr" or s.type == "blk" then
220                         return true
221                 elseif s.type == "lnk" then
222                         return device( fs.readlink(val), seen )
223                 end
224         end
225
226         return false
227 end
228
229 function uciname(val)
230         return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
231 end
232
233 function neg_network_ip4addr(val)
234         if type(v) == "string" then
235                 v = v:gsub("^%s*!", "")
236                 return (uciname(v) or ip4addr(v))
237         end     
238 end
239
240 function range(val, min, max)
241         val = tonumber(val)
242         min = tonumber(min)
243         max = tonumber(max)
244
245         if val ~= nil and min ~= nil and max ~= nil then
246                 return ((val >= min) and (val <= max))
247         end
248
249         return false
250 end
251
252 function min(val, min)
253         val = tonumber(val)
254         min = tonumber(min)
255
256         if val ~= nil and min ~= nil then
257                 return (val >= min)
258         end
259
260         return false
261 end
262
263 function max(val, max)
264         val = tonumber(val)
265         max = tonumber(max)
266
267         if val ~= nil and max ~= nil then
268                 return (val <= max)
269         end
270
271         return false
272 end
273
274 function neg(val, what)
275         if what and type(_M[what]) == "function" then
276                 return _M[what](val:gsub("^%s*!%s*", ""))
277         end
278
279         return false
280 end