File

mod_http_muc_kick/mod_http_muc_kick.lua @ 5472:b80b6947b079

mod_http_oauth2: Always show early errors to user Before having validated the client_id, communicating an error back to the client via redirect would make this an open redirect, so we may just as well skip past that logic, and especially the warning log message.
author Kim Alvefur <zash@zash.se>
date Thu, 18 May 2023 13:43:17 +0200
parent 4652:e524a97730eb
line wrap: on
line source

local jid_split = require "util.jid".prepped_split;
local json = require "util.json";

module:depends("http");

local authorization = assert(
    module:get_option_string("http_muc_kick_authorization_header", nil),
    "http_muc_kick_authorization_header setting is missing, please add it to the Prosody config before using mod_http_muc_kick"
);

local function is_authorized(request)
    return request.headers.authorization == authorization;
end

local function check_muc(jid)
	local muc_node, host = jid_split(jid);

	if not hosts[host] then
		return nil, nil, "No such host: "..host;
	elseif not hosts[host].modules.muc then
		return nil, nil, "Host '"..host.."' is not a MUC service";
	end

	return muc_node, host;
end

local function get_muc(muc_jid)
    local muc_node, host, err = check_muc(muc_jid);
    if not muc_node then
        return nil, host, err;
    end

    local muc = prosody.hosts[host].modules.muc.get_room_from_jid(muc_jid);
    if not muc then
        return nil, host, "No MUC '"..muc_node.."' found for host: "..host;
    end
    
    return muc;
end

local function handle_error(response, status_code, error)
    response.headers.content_type = "application/json";
    response.status_code = status_code;
    response:send(json.encode({error = error}));

    -- return true to keep the connection open, and prevent other handlers from executing.
    -- https://prosody.im/doc/developers/http#return_value
    return true;
end

module:provides("http", {
    route = {
        ["POST"] = function (event)
            local request, response = event.request, event.response;

            if not is_authorized(request) then
                return handle_error(response, 401, "Authorization failed");
            end

            local body = json.decode(request.body or "") or {};
            if not body then
                return handle_error(response, 400, "JSON body not found");
            end

            local nickname, muc_jid, reason = body.nickname, body.muc, body.reason or "";
            if not nickname or not muc_jid then
                return handle_error(response, 400, "Missing nickname and/or MUC");
            end

        	local muc, _, err = get_muc(muc_jid);
            if not muc then
                return handle_error(response, 404, "MUC not found: " .. err);
            end

            local occupant_jid = muc.jid .. "/" .. nickname;

            -- Kick user by giving them the "none" role
            -- https://xmpp.org/extensions/xep-0045.html#kick
            local success, error, condition = muc:set_role(true, occupant_jid, nil, reason);
            if not success then
                return handle_error(response, 400, "Couldn't kick user: ".. error .. ": " .. condition);
            end
            
            -- Kick was successful
        	return 200;
        end;
    };
});