Session = mondelefant.new_class() Session.table = 'session' Session.primary_key = { 'ident' } Session:add_reference{ mode = 'm1', to = "Member", this_key = 'member_id', that_key = 'id', ref = 'member', } Session:add_reference{ mode = 'm1', to = "Member", this_key = 'real_member_id', that_key = 'id', ref = 'real_member', } local secret_length = 24 local secret_alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' local secret_purposes = { "oauth", "_other" } for idx, purpose in ipairs(secret_purposes) do secret_purposes[purpose] = idx end local function random_string(length_multiplier) return multirand.string( secret_length * (length_multiplier or 1), secret_alphabet ) end function Session:new() local session = self.prototype.new(self) -- super call session.ident = random_string() session.additional_secret = random_string(#secret_purposes) session:save() return session end function Session.object:set_cookie() request.set_cookie{ name = config.cookie_name, value = self.ident, samesite = "none" } request.set_cookie{ name = config.cookie_name_samesite, value = self.ident } end function Session.object:additional_secret_for(purpose) local use_hash = false local idx = secret_purposes[purpose] if not idx then idx = assert(secret_purposes._other, "No other secrets supported") use_hash = true end local from_pos = secret_length * (idx-1) + 1 local to_pos = from_pos + secret_length - 1 local secret = string.sub(self.additional_secret, from_pos, to_pos) if #secret ~= secret_length then self:destroy() error("Session state invalid") end if use_hash then local moonhash = require "moonhash" -- TODO: auto loader for libraries in WebMCP? secret = moonhash.shake256(secret .. "\0" .. purpose, secret_length, secret_alphabet) end return secret end function Session:by_ident(ident) local selector = self:new_selector() selector:add_where{ 'ident = ?', ident } selector:add_field{ 'authority_uid' } selector:optional_object_mode() return selector:exec() end function Session.object:has_access(level) if level == "member" then if app.session.member_id then return true else return false end elseif level == "everything" then if self:has_access("member") or config.public_access == "everything" then return true else return false end elseif level == "all_pseudonymous" then if self:has_access("everything") or config.public_access == "all_pseudonymous" then return true else return false end elseif level == "authors_pseudonymous" then if self:has_access("all_pseudonymous") or config.public_access == "authors_pseudonymous" then return true else return false end elseif level == "anonymous" then if self:has_access("authors_pseudonymous") or config.public_access == "anonymous" then return true else return false end end error("invalid access level") end