Software /
code /
prosody-modules
Comparison
mod_invites/mod_invites.lua @ 3776:80830d97da81
mod_invites: New module providing an API to create/manage invite tokens
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Fri, 27 Dec 2019 10:31:33 +0000 |
child | 4077:f85ea76447dd |
comparison
equal
deleted
inserted
replaced
3775:d60efdb947fd | 3776:80830d97da81 |
---|---|
1 local id = require "util.id"; | |
2 local url = require "socket.url"; | |
3 local jid_node = require "util.jid".node; | |
4 | |
5 local invite_ttl = module:get_option_number("invite_expiry", 86400 * 7); | |
6 | |
7 local token_storage = module:open_store("invite_token", "map"); | |
8 | |
9 local function get_uri(action, jid, token, params) --> string | |
10 return url.build({ | |
11 scheme = "xmpp", | |
12 path = jid, | |
13 query = action..";preauth="..token..(params and (";"..params) or ""), | |
14 }); | |
15 end | |
16 | |
17 local function create_invite(invite_action, invite_jid, allow_registration) | |
18 local token = id.medium(); | |
19 | |
20 local created_at = os.time(); | |
21 local expires = created_at + invite_ttl; | |
22 | |
23 local invite_params = (invite_action == "roster" and allow_registration) and "ibr=y" or nil; | |
24 | |
25 local invite = { | |
26 type = invite_action; | |
27 jid = invite_jid; | |
28 | |
29 token = token; | |
30 allow_registration = allow_registration; | |
31 | |
32 uri = get_uri(invite_action, invite_jid, token, invite_params); | |
33 | |
34 created_at = created_at; | |
35 expires = expires; | |
36 }; | |
37 | |
38 module:fire_event("invite-created", invite); | |
39 | |
40 if allow_registration then | |
41 local ok, err = token_storage:set(nil, token, invite); | |
42 if not ok then | |
43 module:log("warn", "Failed to store account invite: %s", err); | |
44 return nil, "internal-server-error"; | |
45 end | |
46 end | |
47 | |
48 if invite_action == "roster" then | |
49 local username = jid_node(invite_jid); | |
50 local ok, err = token_storage:set(username, token, expires); | |
51 if not ok then | |
52 module:log("warn", "Failed to store subscription invite: %s", err); | |
53 return nil, "internal-server-error"; | |
54 end | |
55 end | |
56 | |
57 return invite; | |
58 end | |
59 | |
60 -- Create invitation to register an account (optionally restricted to the specified username) | |
61 function create_account(account_username) --luacheck: ignore 131/create_account | |
62 local jid = account_username and (account_username.."@"..module.host) or module.host; | |
63 return create_invite("register", jid, true); | |
64 end | |
65 | |
66 -- Create invitation to become a contact of a local user | |
67 function create_contact(username, allow_registration) --luacheck: ignore 131/create_contact | |
68 return create_invite("roster", username.."@"..module.host, allow_registration); | |
69 end | |
70 | |
71 local valid_invite_methods = {}; | |
72 local valid_invite_mt = { __index = valid_invite_methods }; | |
73 | |
74 function valid_invite_methods:use() | |
75 if self.username then | |
76 -- Also remove the contact invite if present, on the | |
77 -- assumption that they now have a mutual subscription | |
78 token_storage:set(self.username, self.token, nil); | |
79 end | |
80 token_storage:set(nil, self.token, nil); | |
81 return true; | |
82 end | |
83 | |
84 -- Get a validated invite (or nil, err). Must call :use() on the | |
85 -- returned invite after it is actually successfully used | |
86 -- For "roster" invites, the username of the local user (who issued | |
87 -- the invite) must be passed. | |
88 -- If no username is passed, but the registration is a roster invite | |
89 -- from a local user, the "inviter" field of the returned invite will | |
90 -- be set to their username. | |
91 function get(token, username) | |
92 if not token then | |
93 return nil, "no-token"; | |
94 end | |
95 | |
96 local valid_until, inviter; | |
97 | |
98 if username then -- token being used for subscription | |
99 -- Fetch from user store (subscription invite) | |
100 valid_until = token_storage:get(username, token); | |
101 else -- token being used for account creation | |
102 -- Fetch from host store (account invite) | |
103 local token_info = token_storage:get(nil, token); | |
104 valid_until = token_info and token_info.expires; | |
105 if token_info.type == "roster" then | |
106 username = jid_node(token_info.jid); | |
107 inviter = username; | |
108 end | |
109 end | |
110 | |
111 if not valid_until then | |
112 module:log("debug", "Got unknown token: %s", token); | |
113 return nil, "token-invalid"; | |
114 elseif os.time() > valid_until then | |
115 module:log("debug", "Got expired token: %s", token); | |
116 return nil, "token-expired"; | |
117 end | |
118 | |
119 return setmetatable({ | |
120 token = token; | |
121 username = username; | |
122 inviter = inviter; | |
123 }, valid_invite_mt); | |
124 end | |
125 | |
126 function use(token) --luacheck: ignore 131/use | |
127 local invite = get(token); | |
128 return invite and invite:use(); | |
129 end |