You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
3.6 KiB
Lua
126 lines
3.6 KiB
Lua
local util = {}
|
|
|
|
local table_is_empty = function(t)
|
|
return next(t) == nil
|
|
end
|
|
|
|
local is_in = function(value, list)
|
|
for _,el in ipairs(list) do
|
|
if value == el then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
util.hash = function(v) -- TODO: maybe use Argon2 [https://luarocks.org/modules/thibaultcha/argon2]
|
|
--xxhash:update(v)
|
|
--return xxhash:digest()
|
|
return v
|
|
end
|
|
|
|
|
|
--[[
|
|
Uses 'schema' to verify:
|
|
Existence of required value in 'req'
|
|
They have proper types
|
|
The DB references actually exist
|
|
]]
|
|
--[[ schema = {
|
|
user_id = {'db_ref', to='user', required=true, load_as='user_record'} -- `load_as` so a DB search doesn't have to be done again after validation
|
|
price = {'number', required=true}
|
|
}
|
|
]]
|
|
util.validate = function(req, schema, db, sessions)
|
|
local errors = {}
|
|
local loaded_records = {}
|
|
for property, rules in pairs(schema) do
|
|
local expected_value_type = rules[1]
|
|
local value = req[property]
|
|
if rules.required == true then
|
|
if value == nil then
|
|
table.insert(errors, "Expected '"..property.."' to be provided.")
|
|
end
|
|
end
|
|
if expected_value_type == 'number' or expected_value_type == 'string' or expected_value_type == 'table' then
|
|
if type(value) ~= expected_value_type then
|
|
table.insert(errors, "Expected '"..property.."' to be a "..expected_value_type..".")
|
|
elseif rules.is_any_of ~= nil then
|
|
if not is_in(value, rules.is_any_of) then
|
|
table.insert(errors, "Expected '"..property.."' to be one of (".. table.concat(rules.is_any_of,',') ..").")
|
|
end
|
|
end
|
|
elseif expected_value_type == 'db_ref' then
|
|
local expected_record_type = rules.to
|
|
local record = db:findOne(function(record) return record.id == value and record.type == expected_record_type end)
|
|
if record == nil then
|
|
table.insert(errors, "Expected '"..property.."' to point to a '"..expected_record_type.."' in the database.")
|
|
else
|
|
loaded_records[rules.load_as] = record
|
|
end
|
|
elseif expected_value_type == 'base64' then
|
|
local _, start_of_base64_string_index = string.find(value, "data:.-/.-;base64,")
|
|
start_of_base64_string_index = start_of_base64_string_index + 1
|
|
local base64_adjusted = string.sub(value, start_of_base64_string_index) -- must remove "data:*/*;base64," from the beginning of the string
|
|
loaded_records[rules.load_as] = base64_adjusted
|
|
elseif expected_value_type == 'session' then
|
|
local session = sessions[value]
|
|
if session == nil then
|
|
table.insert(errors, "No such session.")
|
|
else
|
|
if rules.is_admin == true and db:getrecord(session.user_id).is_admin ~= true then
|
|
table.insert(errors, "Current user is not admin.")
|
|
else
|
|
loaded_records.session = session
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return errors, loaded_records
|
|
end
|
|
|
|
|
|
util.run_every = function(interval_in_s, fn)
|
|
local co = coroutine.create(function()
|
|
local t1 = os.time()
|
|
while true do
|
|
if os.time()-t1 > interval_in_s*1000 then
|
|
fn()
|
|
t1 = os.time()
|
|
end
|
|
coroutine.yield()
|
|
--posix.unistd.sleep(interval_in_s)
|
|
end
|
|
end)
|
|
return co
|
|
end
|
|
|
|
util.setdefaults = function(t, defaults)
|
|
for k,v in pairs(defaults) do
|
|
if t[k] == nil then
|
|
t[k] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
util.merge = function(dest, source)
|
|
for k,v in pairs(source) do
|
|
dest[k] = v
|
|
end
|
|
end
|
|
|
|
util.findOne = function(t, fn)
|
|
for i,v in ipairs(t) do
|
|
if fn(v, i) then return v end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
util.removefromtable = function(t, v)
|
|
local i = 1
|
|
while t[i] ~= v do i = i + 1 end
|
|
table.remove(t, i)
|
|
return i
|
|
end
|
|
|
|
return util |