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