web: Improve hostname validation
[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
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 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 ip4addr(val)
70         if val then
71                 return ip.IPv4(val) and true or false
72         end
73
74         return false
75 end
76
77 function ip4prefix(val)
78         val = tonumber(val)
79         return ( val and val >= 0 and val <= 32 )
80 end
81
82 function ip6addr(val)
83         if val then
84                 return ip.IPv6(val) and true or false
85         end
86
87         return false
88 end
89
90 function ip6prefix(val)
91         val = tonumber(val)
92         return ( val and val >= 0 and val <= 128 )
93 end
94
95 function port(val)
96         val = tonumber(val)
97         return ( val and val >= 1 and val <= 65535 )
98 end
99
100 function portrange(val)
101         local p1, p2 = val:match("^(%d+)%-(%d+)$")
102         if p1 and p2 and port(p1) and port(p2) then
103                 return true
104         else
105                 return port(val)
106         end
107 end
108
109 function macaddr(val)
110         if val and val:match(
111                 "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
112                  "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
113         ) then
114                 local parts = util.split( val, ":" )
115
116                 for i = 1,6 do
117                         parts[i] = tonumber( parts[i], 16 )
118                         if parts[i] < 0 or parts[i] > 255 then
119                                 return false
120                         end
121                 end
122
123                 return true
124         end
125
126         return false
127 end
128
129 function hostname(val)
130         if val and (#val < 25) and val.match(val, "^[a-zA-Z0-9][a-zA-Z0-9%-%.]*[a-zA-Z0-9]$") then
131                 return true
132         end
133         return false
134 end
135
136 function host(val)
137         return hostname(val) or ipaddr(val)
138 end
139
140 function wpakey(val)
141         if #val == 64 then
142                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
143         else
144                 return (#val >= 8) and (#val <= 63)
145         end
146 end
147
148 function wepkey(val)
149         if val:sub(1, 2) == "s:" then
150                 val = val:sub(3)
151         end
152
153         if (#val == 10) or (#val == 26) then
154                 return (val:match("^[a-fA-F0-9]+$") ~= nil)
155         else
156                 return (#val == 5) or (#val == 13)
157         end
158 end
159
160 function string(val)
161         return true             -- Everything qualifies as valid string
162 end
163
164 function directory( val, seen )
165         local s = fs.stat(val)
166         seen = seen or { }
167
168         if s and not seen[s.ino] then
169                 seen[s.ino] = true
170                 if s.type == "dir" then
171                         return true
172                 elseif s.type == "lnk" then
173                         return directory( fs.readlink(val), seen )
174                 end
175         end
176
177         return false
178 end
179
180 function file( val, seen )
181         local s = fs.stat(val)
182         seen = seen or { }
183
184         if s and not seen[s.ino] then
185                 seen[s.ino] = true
186                 if s.type == "reg" then
187                         return true
188                 elseif s.type == "lnk" then
189                         return file( fs.readlink(val), seen )
190                 end
191         end
192
193         return false
194 end
195
196 function device( val, seen )
197         local s = fs.stat(val)
198         seen = seen or { }
199
200         if s and not seen[s.ino] then
201                 seen[s.ino] = true
202                 if s.type == "chr" or s.type == "blk" then
203                         return true
204                 elseif s.type == "lnk" then
205                         return device( fs.readlink(val), seen )
206                 end
207         end
208
209         return false
210 end
211
212 function uciname(val)
213         return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
214 end
215
216 function range(val, min, max)
217         val = tonumber(val)
218         min = tonumber(min)
219         max = tonumber(max)
220
221         if val ~= nil and min ~= nil and max ~= nil then
222                 return ((val >= min) and (val <= max))
223         end
224
225         return false
226 end