Mercurial > prosody-modules
comparison mod_unified_push/mod_unified_push.lua @ 5149:fa56ed2bacab
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.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sat, 14 Jan 2023 14:31:37 +0000 |
parents | bf42f1401f1c |
children | 2b6c543c4d3a |
comparison
equal
deleted
inserted
replaced
5148:bf42f1401f1c | 5149:fa56ed2bacab |
---|---|
35 if not d then return nil, "invalid base64"; end | 35 if not d then return nil, "invalid base64"; end |
36 if #d ~= 32 then return nil, "incorrect decoded length, expected 32"; end | 36 if #d ~= 32 then return nil, "incorrect decoded length, expected 32"; end |
37 return s; | 37 return s; |
38 end | 38 end |
39 | 39 |
40 -- COMPAT w/0.12 | 40 local push_store = module:open_store(); |
41 local function jwt_sign(data) | 41 |
42 return jwt.sign(unified_push_secret, data); | 42 local backends = { |
43 jwt = { | |
44 sign = function (data) | |
45 return jwt.sign(unified_push_secret, data); | |
46 end; | |
47 | |
48 verify = function (token) | |
49 local ok, result = jwt.verify(unified_push_secret, token); | |
50 | |
51 if not ok then | |
52 return ok, result; | |
53 end | |
54 if result.exp and result.exp < os.time() then | |
55 return nil, "token-expired"; | |
56 end | |
57 return ok, result; | |
58 end; | |
59 }; | |
60 | |
61 storage = { | |
62 sign = function (data) | |
63 local reg_id = id.long(); | |
64 local user, host = jid.split(data.sub); | |
65 if host ~= module.host or not user then | |
66 return; | |
67 end | |
68 push_store:set(reg_id, data); | |
69 return reg_id; | |
70 end; | |
71 verify = function (token) | |
72 local data = push_store:get(token); | |
73 if not data then | |
74 return nil, "item-not-found"; | |
75 elseif data.exp and data.exp < os.time() then | |
76 push_store:set(token, nil); | |
77 return nil, "token-expired"; | |
78 end | |
79 return data; | |
80 end; | |
81 }; | |
82 }; | |
83 | |
84 if pcall(require, "util.paseto") then | |
85 local sign, verify = require "util.paseto".init(unified_push_secret); | |
86 backends.paseto = { sign = sign, verify = verify }; | |
43 end | 87 end |
44 | 88 |
45 -- COMPAT w/0.12: add expiry check | 89 local backend = module:get_option_string("unified_push_backend", backends.paseto and "paseto" or "storage"); |
46 local function jwt_verify(token) | |
47 local ok, result = jwt.verify(unified_push_secret, token); | |
48 | |
49 if not ok then | |
50 return ok, result; | |
51 end | |
52 if result.exp and result.exp < os.time() then | |
53 return nil, "token-expired"; | |
54 end | |
55 return ok, result; | |
56 end | |
57 | 90 |
58 local function register_route(params) | 91 local function register_route(params) |
59 local expiry = os.time() + push_registration_ttl; | 92 local expiry = os.time() + push_registration_ttl; |
93 local token = backends[backend].sign({ | |
94 instance = params.instance; | |
95 application = params.application; | |
96 sub = params.jid; | |
97 exp = expiry; | |
98 }); | |
60 return { | 99 return { |
61 url = module:http_url("push").."/"..urlencode(jwt_sign(unified_push_secret, { | 100 url = module:http_url("push").."/"..urlencode(token); |
62 instance = params.instance; | |
63 application = params.application; | |
64 sub = params.jid; | |
65 exp = expiry; | |
66 })); | |
67 expiry = expiry; | 101 expiry = expiry; |
68 }; | 102 }; |
69 end | 103 end |
70 | 104 |
71 -- Handle incoming registration from XMPP client | 105 -- Handle incoming registration from XMPP client |
103 module:hook("iq-set/host/"..xmlns_up..":register", handle_register); | 137 module:hook("iq-set/host/"..xmlns_up..":register", handle_register); |
104 | 138 |
105 -- Handle incoming POST | 139 -- Handle incoming POST |
106 function handle_push(event, subpath) | 140 function handle_push(event, subpath) |
107 module:log("debug", "Incoming push received!"); | 141 module:log("debug", "Incoming push received!"); |
108 local ok, data = jwt_verify(subpath); | 142 local ok, data = backends[backend].verify(subpath); |
109 if not ok then | 143 if not ok then |
110 module:log("debug", "Received push to unacceptable token (%s)", data); | 144 module:log("debug", "Received push to unacceptable token (%s)", data); |
111 return 404; | 145 return 404; |
112 end | 146 end |
113 local payload = event.request.body; | 147 local payload = event.request.body; |