view mod_invite/mod_invite.lua @ 2670:6e01878103c0

mod_smacks: Ignore user when writing or reading session_cache on prosody 0.9 At least under some circumstances it seems that session.username is nil when a user tries to resume his session in prosody 0.9. The username is not relevant when no limiting is done (limiting the number of entries in the session cache is only possible in prosody 0.10), so this commit removes the usage of the username when accessing the prosody 0.9 session cache.
author tmolitor <thilo@eightysoft.de>
date Thu, 06 Apr 2017 02:12:14 +0200
parents c814c667d4d1
children 5911030a1a66
line wrap: on
line source

local adhoc_new = module:require "adhoc".new;
local uuid_new = require "util.uuid".generate;
local jid_split = require "util.jid".split;
local jid_join = require "util.jid".join;
local http_formdecode = require "net.http".formdecode;
local usermanager = require "core.usermanager";
local rostermanager = require "core.rostermanager";
local tohtml = require "util.stanza".xml_escape
local nodeprep = require "util.encodings".stringprep.nodeprep;
local tostring = tostring;

local invite_storage = module:open_store();
local inviter_storage = module:open_store("inviter");

local serve = module:depends"http_files".serve;

module:depends"adhoc";
module:depends"http";

local function apply_template(template, args)
	return
		template:gsub("{{([^}]*)}}", function (k)
			if args[k] then
				return tohtml(args[k])
			else
				return k
			end
		end)
end

function generate_page(event)
	local request, response = event.request, event.response;

	local tokens = invite_storage:get() or {};

	local token = request.path:match("^/invite/([^/]*)$");

	response.headers.content_type = "text/html; charset=utf-8";

	if not token or not tokens[token] then
		local template = assert(module:load_resource("invite/invite_result.html")):read("*a");

		return apply_template(template, { classes = "alert-danger", message = "This invite has expired." })
	end

	local template = assert(module:load_resource("invite/invite.html")):read("*a");

	return apply_template(template, { user = jid_join(tokens[token], module.host), server = module.host, token = token });
end

function subscribe(user1, user2)
	local user1_jid = jid_join(user1, module.host);
	local user2_jid = jid_join(user2, module.host);

	rostermanager.set_contact_pending_out(user2, module.host, user1_jid);
	rostermanager.set_contact_pending_in(user1, module.host, user2_jid);
	rostermanager.subscribed(user1, module.host, user2_jid);
	rostermanager.process_inbound_subscription_approval(user2, module.host, user1_jid);
end

function handle_form(event)
	local request, response = event.request, event.response;
	local form_data = http_formdecode(request.body);
	local user, password, token = form_data["user"], form_data["password"], form_data["token"];
	local tokens = invite_storage:get() or {};

	local template = assert(module:load_resource("invite/invite_result.html")):read("*a");

	response.headers.content_type = "text/html; charset=utf-8";

	if not user or #user == 0 or not password or #password == 0 or not token then
		return apply_template(template, { classes = "alert-warning", message = "Please fill in all fields." })
	end

	if not tokens[token] then
		return apply_template(template, { classes = "alert-danger", message = "This invite has expired." })
	end

	-- Shamelessly copied from mod_register_web.
	local prepped_username = nodeprep(user);

	if not prepped_username or #prepped_username == 0 then
		return apply_template(template, { classes = "alert-warning", message = "This username contains invalid characters." })
	end

	if usermanager.user_exists(prepped_username, module.host) then
		return apply_template(template, { classes = "alert-warning", message = "This username is already in use." })
	end

	local registering = { username = prepped_username , host = module.host, allowed = true }

	module:fire_event("user-registering", registering);

	if not registering.allowed then
		return apply_template(template, { classes = "alert-danger", message = "Registration is not allowed." })
	end

	local ok, err = usermanager.create_user(prepped_username, password, module.host);

	if ok then
		subscribe(prepped_username, tokens[token]);
		subscribe(tokens[token], prepped_username);

		inviter_storage:set(prepped_username, { inviter = tokens[token] });

		rostermanager.roster_push(tokens[token], module.host, jid_join(prepped_username, module.host));

		tokens[token] = nil;

		invite_storage:set(nil, tokens);

		return apply_template(template, { classes = "alert-success",
			message = "Your account has been created! You can now log in using an XMPP client." })
	else
		module:log("debug", "Registration failed: " .. tostring(err));

		return apply_template(template, { classes = "alert-danger", message = "An unknown error has occurred." })
	end
end

module:provides("http", {
	route = {
		["GET /bootstrap.min.css"] = serve(module:get_directory() .. "/invite/bootstrap.min.css");
		["GET /*"] = generate_page;
		POST = handle_form;
	};
});

function invite_command_handler(_, data)
	local uuid = uuid_new();

	local user, host = jid_split(data.from);

	if host ~= module.host then
		return { status = "completed", error = { message = "You are not allowed to invite users to this server." }};
	end

	local tokens = invite_storage:get() or {};

	tokens[uuid] = user;

	invite_storage:set(nil, tokens);

	return { info = module:http_url() .. "/" .. uuid, status = "completed" };
end

local adhoc_invite = adhoc_new("Invite user", "invite", invite_command_handler, "user")

module:add_item("adhoc", adhoc_invite);