datatypes.lua 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. -- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
  2. -- Licensed to the public under the Apache License 2.0.
  3. local fs = require "nixio.fs"
  4. local ip = require "luci.ip"
  5. local math = require "math"
  6. local util = require "luci.util"
  7. local tonumber, tostring, type, unpack, select = tonumber, tostring, type, unpack, select
  8. module "luci.cbi.datatypes"
  9. _M['or'] = function(v, ...)
  10. local i
  11. for i = 1, select('#', ...), 2 do
  12. local f = select(i, ...)
  13. local a = select(i+1, ...)
  14. if type(f) ~= "function" then
  15. if f == v then
  16. return true
  17. end
  18. i = i - 1
  19. elseif f(v, unpack(a)) then
  20. return true
  21. end
  22. end
  23. return false
  24. end
  25. _M['and'] = function(v, ...)
  26. local i
  27. for i = 1, select('#', ...), 2 do
  28. local f = select(i, ...)
  29. local a = select(i+1, ...)
  30. if type(f) ~= "function" then
  31. if f ~= v then
  32. return false
  33. end
  34. i = i - 1
  35. elseif not f(v, unpack(a)) then
  36. return false
  37. end
  38. end
  39. return true
  40. end
  41. function neg(v, ...)
  42. return _M['or'](v:gsub("^%s*!%s*", ""), ...)
  43. end
  44. function list(v, subvalidator, subargs)
  45. if type(subvalidator) ~= "function" then
  46. return false
  47. end
  48. local token
  49. for token in v:gmatch("%S+") do
  50. if not subvalidator(token, unpack(subargs)) then
  51. return false
  52. end
  53. end
  54. return true
  55. end
  56. function bool(val)
  57. if val == "1" or val == "yes" or val == "on" or val == "true" then
  58. return true
  59. elseif val == "0" or val == "no" or val == "off" or val == "false" then
  60. return true
  61. elseif val == "" or val == nil then
  62. return true
  63. end
  64. return false
  65. end
  66. function uinteger(val)
  67. local n = tonumber(val)
  68. if n ~= nil and math.floor(n) == n and n >= 0 then
  69. return true
  70. end
  71. return false
  72. end
  73. function integer(val)
  74. local n = tonumber(val)
  75. if n ~= nil and math.floor(n) == n then
  76. return true
  77. end
  78. return false
  79. end
  80. function ufloat(val)
  81. local n = tonumber(val)
  82. return ( n ~= nil and n >= 0 )
  83. end
  84. function float(val)
  85. return ( tonumber(val) ~= nil )
  86. end
  87. function ipaddr(val)
  88. return ip4addr(val) or ip6addr(val)
  89. end
  90. function ip4addr(val)
  91. if val then
  92. return ip.IPv4(val) and true or false
  93. end
  94. return false
  95. end
  96. function ip4prefix(val)
  97. val = tonumber(val)
  98. return ( val and val >= 0 and val <= 32 )
  99. end
  100. function ip6addr(val)
  101. if val then
  102. return ip.IPv6(val) and true or false
  103. end
  104. return false
  105. end
  106. function ip6prefix(val)
  107. val = tonumber(val)
  108. return ( val and val >= 0 and val <= 128 )
  109. end
  110. function port(val)
  111. val = tonumber(val)
  112. return ( val and val >= 0 and val <= 65535 )
  113. end
  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. function macaddr(val)
  123. if val and val:match(
  124. "^[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+:" ..
  125. "[a-fA-F0-9]+:[a-fA-F0-9]+:[a-fA-F0-9]+$"
  126. ) then
  127. local parts = util.split( val, ":" )
  128. for i = 1,6 do
  129. parts[i] = tonumber( parts[i], 16 )
  130. if parts[i] < 0 or parts[i] > 255 then
  131. return false
  132. end
  133. end
  134. return true
  135. end
  136. return false
  137. end
  138. function hostname(val)
  139. if val and (#val < 254) and (
  140. val:match("^[a-zA-Z_]+$") or
  141. (val:match("^[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*[a-zA-Z0-9]$") and
  142. val:match("[^0-9%.]"))
  143. ) then
  144. return true
  145. end
  146. return false
  147. end
  148. function host(val, ipv4only)
  149. return hostname(val) or ((ipv4only == 1) and ip4addr(val)) or ((not (ipv4only == 1)) and ipaddr(val))
  150. end
  151. function network(val)
  152. return uciname(val) or host(val)
  153. end
  154. function hostport(val, ipv4only)
  155. local h, p = val:match("^([^:]+):([^:]+)$")
  156. return not not (h and p and host(h, ipv4only) and port(p))
  157. end
  158. function ip4addrport(val, bracket)
  159. local h, p = val:match("^([^:]+):([^:]+)$")
  160. return (h and p and ip4addr(h) and port(p))
  161. end
  162. function ip4addrport(val)
  163. local h, p = val:match("^([^:]+):([^:]+)$")
  164. return (h and p and ip4addr(h) and port(p))
  165. end
  166. function ipaddrport(val, bracket)
  167. local h, p = val:match("^([^%[%]:]+):([^:]+)$")
  168. if (h and p and ip4addr(h) and port(p)) then
  169. return true
  170. elseif (bracket == 1) then
  171. h, p = val:match("^%[(.+)%]:([^:]+)$")
  172. if (h and p and ip6addr(h) and port(p)) then
  173. return true
  174. end
  175. end
  176. h, p = val:match("^([^%[%]]+):([^:]+)$")
  177. return (h and p and ip6addr(h) and port(p))
  178. end
  179. function wpakey(val)
  180. if #val == 64 then
  181. return (val:match("^[a-fA-F0-9]+$") ~= nil)
  182. else
  183. return (#val >= 8) and (#val <= 63)
  184. end
  185. end
  186. function wepkey(val)
  187. if val:sub(1, 2) == "s:" then
  188. val = val:sub(3)
  189. end
  190. if (#val == 10) or (#val == 26) then
  191. return (val:match("^[a-fA-F0-9]+$") ~= nil)
  192. else
  193. return (#val == 5) or (#val == 13)
  194. end
  195. end
  196. function string(val)
  197. return true -- Everything qualifies as valid string
  198. end
  199. function directory( val, seen )
  200. local s = fs.stat(val)
  201. seen = seen or { }
  202. if s and not seen[s.ino] then
  203. seen[s.ino] = true
  204. if s.type == "dir" then
  205. return true
  206. elseif s.type == "lnk" then
  207. return directory( fs.readlink(val), seen )
  208. end
  209. end
  210. return false
  211. end
  212. function file( val, seen )
  213. local s = fs.stat(val)
  214. seen = seen or { }
  215. if s and not seen[s.ino] then
  216. seen[s.ino] = true
  217. if s.type == "reg" then
  218. return true
  219. elseif s.type == "lnk" then
  220. return file( fs.readlink(val), seen )
  221. end
  222. end
  223. return false
  224. end
  225. function device( val, seen )
  226. local s = fs.stat(val)
  227. seen = seen or { }
  228. if s and not seen[s.ino] then
  229. seen[s.ino] = true
  230. if s.type == "chr" or s.type == "blk" then
  231. return true
  232. elseif s.type == "lnk" then
  233. return device( fs.readlink(val), seen )
  234. end
  235. end
  236. return false
  237. end
  238. function uciname(val)
  239. return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
  240. end
  241. function range(val, min, max)
  242. val = tonumber(val)
  243. min = tonumber(min)
  244. max = tonumber(max)
  245. if val ~= nil and min ~= nil and max ~= nil then
  246. return ((val >= min) and (val <= max))
  247. end
  248. return false
  249. end
  250. function min(val, min)
  251. val = tonumber(val)
  252. min = tonumber(min)
  253. if val ~= nil and min ~= nil then
  254. return (val >= min)
  255. end
  256. return false
  257. end
  258. function max(val, max)
  259. val = tonumber(val)
  260. max = tonumber(max)
  261. if val ~= nil and max ~= nil then
  262. return (val <= max)
  263. end
  264. return false
  265. end
  266. function rangelength(val, min, max)
  267. val = tostring(val)
  268. min = tonumber(min)
  269. max = tonumber(max)
  270. if val ~= nil and min ~= nil and max ~= nil then
  271. return ((#val >= min) and (#val <= max))
  272. end
  273. return false
  274. end
  275. function minlength(val, min)
  276. val = tostring(val)
  277. min = tonumber(min)
  278. if val ~= nil and min ~= nil then
  279. return (#val >= min)
  280. end
  281. return false
  282. end
  283. function maxlength(val, max)
  284. val = tostring(val)
  285. max = tonumber(max)
  286. if val ~= nil and max ~= nil then
  287. return (#val <= max)
  288. end
  289. return false
  290. end
  291. function phonedigit(val)
  292. return (val:match("^[0-9\*#!%.]+$") ~= nil)
  293. end
  294. function timehhmmss(val)
  295. return (val:match("^[0-6][0-9]:[0-6][0-9]:[0-6][0-9]$") ~= nil)
  296. end
  297. function dateyyyymmdd(val)
  298. if val ~= nil then
  299. yearstr, monthstr, daystr = val:match("^(%d%d%d%d)-(%d%d)-(%d%d)$")
  300. if (yearstr == nil) or (monthstr == nil) or (daystr == nil) then
  301. return false;
  302. end
  303. year = tonumber(yearstr)
  304. month = tonumber(monthstr)
  305. day = tonumber(daystr)
  306. if (year == nil) or (month == nil) or (day == nil) then
  307. return false;
  308. end
  309. local days_in_month = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  310. local function is_leap_year(year)
  311. return (year % 4 == 0) and ((year % 100 ~= 0) or (year % 400 == 0))
  312. end
  313. function get_days_in_month(month, year)
  314. if (month == 2) and is_leap_year(year) then
  315. return 29
  316. else
  317. return days_in_month[month]
  318. end
  319. end
  320. if (year < 2015) then
  321. return false
  322. end
  323. if ((month == 0) or (month > 12)) then
  324. return false
  325. end
  326. if ((day == 0) or (day > get_days_in_month(month, year))) then
  327. return false
  328. end
  329. return true
  330. end
  331. return false
  332. end