Mercurial > prosody-modules
comparison mod_invites_api/mod_invites_api.lua @ 4115:165ade4ce97b
mod_invites_api: New module to create new invites over HTTP
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sun, 13 Sep 2020 11:05:19 +0100 |
parents | |
children | 35b678609b79 |
comparison
equal
deleted
inserted
replaced
4114:4656a64e59be | 4115:165ade4ce97b |
---|---|
1 local http_formdecode = require "net.http".formdecode; | |
2 | |
3 local api_key_store; | |
4 local invites; | |
5 -- COMPAT: workaround to avoid executing inside prosodyctl | |
6 if prosody.shutdown then | |
7 module:depends("http"); | |
8 api_key_store = module:open_store("invite_api_keys", "map"); | |
9 invites = module:depends("invites"); | |
10 end | |
11 | |
12 local function get_api_user(request, params) | |
13 local combined_key; | |
14 | |
15 local auth_header = request.headers.authorization; | |
16 | |
17 if not auth_header then | |
18 params = params or http_formdecode(request.url.query); | |
19 combined_key = params.key; | |
20 else | |
21 local auth_type, value = auth_header:match("^(%S+)%s(%S+)$"); | |
22 if auth_type ~= "Bearer" then | |
23 return; | |
24 end | |
25 combined_key = value; | |
26 end | |
27 | |
28 if not combined_key then | |
29 return; | |
30 end | |
31 | |
32 local key_id, key_token = combined_key:match("^([^/]+)/(.+)$"); | |
33 | |
34 if not key_id then | |
35 return; | |
36 end | |
37 | |
38 local api_user = api_key_store:get(nil, key_id); | |
39 | |
40 if not api_user or api_user.token ~= key_token then | |
41 return; | |
42 end | |
43 | |
44 -- TODO: key expiry, rate limiting, etc. | |
45 return api_user; | |
46 end | |
47 | |
48 function handle_request(event) | |
49 local query_params = http_formdecode(event.request.url.query); | |
50 | |
51 local api_user = get_api_user(event.request, query_params); | |
52 | |
53 if not api_user then | |
54 return 403; | |
55 end | |
56 | |
57 local invite = invites.create_account(nil, { source = "api/token/"..api_user.id }); | |
58 if not invite then | |
59 return 500; | |
60 end | |
61 | |
62 event.response.headers.Location = invite.landing_page or invite.uri; | |
63 | |
64 if query_params.redirect then | |
65 return 303; | |
66 end | |
67 return 201; | |
68 end | |
69 | |
70 if invites then | |
71 module:provides("http", { | |
72 route = { | |
73 ["GET"] = handle_request; | |
74 }; | |
75 }); | |
76 end | |
77 | |
78 function module.command(arg) | |
79 if #arg < 2 then | |
80 print("Usage:"); | |
81 print(""); | |
82 print(" prosodyctl mod_"..module.name.." create NAME"); | |
83 print(" prosodyctl mod_"..module.name.." delete KEY_ID"); | |
84 print(" prosodyctl mod_"..module.name.." list"); | |
85 print(""); | |
86 end | |
87 | |
88 local command = table.remove(arg, 1); | |
89 | |
90 local host = table.remove(arg, 1); | |
91 if not prosody.hosts[host] then | |
92 print("Error: please supply a valid host"); | |
93 return 1; | |
94 end | |
95 require "core.storagemanager".initialize_host(host); | |
96 module.host = host; --luacheck: ignore 122/module | |
97 api_key_store = module:open_store("invite_api_keys", "map"); | |
98 | |
99 if command == "create" then | |
100 local id = require "util.id".short(); | |
101 local token = require "util.id".long(); | |
102 api_key_store:set(nil, id, { | |
103 id = id; | |
104 token = token; | |
105 name = arg[1]; | |
106 created_at = os.time(); | |
107 }); | |
108 print(id.."/"..token); | |
109 elseif command == "delete" then | |
110 local id = table.remove(arg, 1); | |
111 if not api_key_store:get(nil, id) then | |
112 print("Error: key not found"); | |
113 return 1; | |
114 end | |
115 api_key_store:set(nil, id, nil); | |
116 elseif command == "list" then | |
117 local api_key_store_kv = module:open_store("invite_api_keys"); | |
118 for key_id, key_info in pairs(api_key_store_kv:get(nil)) do | |
119 print(key_id, key_info.name or "<unknown>"); | |
120 end | |
121 else | |
122 print("Unknown command - "..command); | |
123 end | |
124 end |