# HG changeset patch # User Matthew Wild # Date 1673706697 0 # Node ID fa56ed2bacabdc799f6cc41d39e838bdfbde1793 # Parent bf42f1401f1c3ce6d82f5161e5e5df0ed803a7e4 mod_unified_push: Add support for multiple token backends, including stoage Now that we have ACLs by default, it is no longer necessary to be completely stateless. On 0.12, using storage has benefits over JWT, because it does not expose client JIDs to the push apps/services. In trunk, PASETO is stateless and does not expose client JIDs. diff -r bf42f1401f1c -r fa56ed2bacab mod_unified_push/mod_unified_push.lua --- a/mod_unified_push/mod_unified_push.lua Fri Jan 13 16:50:43 2023 +0000 +++ b/mod_unified_push/mod_unified_push.lua Sat Jan 14 14:31:37 2023 +0000 @@ -37,33 +37,67 @@ return s; end --- COMPAT w/0.12 -local function jwt_sign(data) - return jwt.sign(unified_push_secret, data); +local push_store = module:open_store(); + +local backends = { + jwt = { + sign = function (data) + return jwt.sign(unified_push_secret, data); + end; + + verify = function (token) + local ok, result = jwt.verify(unified_push_secret, token); + + if not ok then + return ok, result; + end + if result.exp and result.exp < os.time() then + return nil, "token-expired"; + end + return ok, result; + end; + }; + + storage = { + sign = function (data) + local reg_id = id.long(); + local user, host = jid.split(data.sub); + if host ~= module.host or not user then + return; + end + push_store:set(reg_id, data); + return reg_id; + end; + verify = function (token) + local data = push_store:get(token); + if not data then + return nil, "item-not-found"; + elseif data.exp and data.exp < os.time() then + push_store:set(token, nil); + return nil, "token-expired"; + end + return data; + end; + }; +}; + +if pcall(require, "util.paseto") then + local sign, verify = require "util.paseto".init(unified_push_secret); + backends.paseto = { sign = sign, verify = verify }; end --- COMPAT w/0.12: add expiry check -local function jwt_verify(token) - local ok, result = jwt.verify(unified_push_secret, token); - - if not ok then - return ok, result; - end - if result.exp and result.exp < os.time() then - return nil, "token-expired"; - end - return ok, result; -end +local backend = module:get_option_string("unified_push_backend", backends.paseto and "paseto" or "storage"); local function register_route(params) local expiry = os.time() + push_registration_ttl; + local token = backends[backend].sign({ + instance = params.instance; + application = params.application; + sub = params.jid; + exp = expiry; + }); return { - url = module:http_url("push").."/"..urlencode(jwt_sign(unified_push_secret, { - instance = params.instance; - application = params.application; - sub = params.jid; - exp = expiry; - })); + url = module:http_url("push").."/"..urlencode(token); expiry = expiry; }; end @@ -105,7 +139,7 @@ -- Handle incoming POST function handle_push(event, subpath) module:log("debug", "Incoming push received!"); - local ok, data = jwt_verify(subpath); + local ok, data = backends[backend].verify(subpath); if not ok then module:log("debug", "Received push to unacceptable token (%s)", data); return 404;