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 |
