Files
jitsi-meet/resources/prosody-plugins/mod_muc_size.lua
damencho a76f9d548b feat: Move to use cjson everywhere.
We were using prosody,util.json and cjson at the same time, but the latter is more performant.
Adds some error handling which were missing with the prosody util json one.
2024-04-05 11:26:51 -05:00

198 lines
6.0 KiB
Lua

-- Prosody IM
-- Copyright (C) 2021-present 8x8, Inc.
--
local jid = require "util.jid";
local it = require "util.iterators";
local json = require 'cjson.safe';
local iterators = require "util.iterators";
local array = require"util.array";
local have_async = pcall(require, "util.async");
if not have_async then
module:log("error", "requires a version of Prosody with util.async");
return;
end
local async_handler_wrapper = module:require "util".async_handler_wrapper;
local tostring = tostring;
local neturl = require "net.url";
local parse = neturl.parseQuery;
-- option to enable/disable room API token verifications
local enableTokenVerification
= module:get_option_boolean("enable_roomsize_token_verification", false);
local token_util = module:require "token/util".new(module);
local get_room_from_jid = module:require "util".get_room_from_jid;
-- no token configuration but required
if token_util == nil and enableTokenVerification then
log("error", "no token configuration but it is required");
return;
end
-- required parameter for custom muc component prefix,
-- defaults to "conference"
local muc_domain_prefix
= module:get_option_string("muc_mapper_domain_prefix", "conference");
--- Verifies room name, domain name with the values in the token
-- @param token the token we received
-- @param room_address the full room address jid
-- @return true if values are ok or false otherwise
function verify_token(token, room_address)
if not enableTokenVerification then
return true;
end
-- if enableTokenVerification is enabled and we do not have token
-- stop here, cause the main virtual host can have guest access enabled
-- (allowEmptyToken = true) and we will allow access to rooms info without
-- a token
if token == nil then
log("warn", "no token provided");
return false;
end
local session = {};
session.auth_token = token;
local verified, reason = token_util:process_and_verify_token(session);
if not verified then
log("warn", "not a valid token %s", tostring(reason));
return false;
end
if not token_util:verify_room(session, room_address) then
log("warn", "Token %s not allowed to join: %s",
tostring(token), tostring(room_address));
return false;
end
return true;
end
--- Handles request for retrieving the room size
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants count,
-- the value is without counting the focus.
function handle_get_room_size(event)
if (not event.request.url.query) then
return { status_code = 400; };
end
local params = parse(event.request.url.query);
local room_name = params["room"];
local domain_name = params["domain"];
local subdomain = params["subdomain"];
local room_address
= jid.join(room_name, muc_domain_prefix.."."..domain_name);
if subdomain and subdomain ~= "" then
room_address = "["..subdomain.."]"..room_address;
end
if not verify_token(params["token"], room_address) then
return { status_code = 403; };
end
local room = get_room_from_jid(room_address);
local participant_count = 0;
log("debug", "Querying room %s", tostring(room_address));
if room then
local occupants = room._occupants;
if occupants then
participant_count = iterators.count(room:each_occupant());
end
log("debug",
"there are %s occupants in room", tostring(participant_count));
else
log("debug", "no such room exists");
return { status_code = 404; };
end
if participant_count > 1 then
participant_count = participant_count - 1;
end
return { status_code = 200; body = [[{"participants":]]..participant_count..[[}]] };
end
--- Handles request for retrieving the room participants details
-- @param event the http event, holds the request query
-- @return GET response, containing a json with participants details
function handle_get_room (event)
if (not event.request.url.query) then
return { status_code = 400; };
end
local params = parse(event.request.url.query);
local room_name = params["room"];
local domain_name = params["domain"];
local subdomain = params["subdomain"];
local room_address
= jid.join(room_name, muc_domain_prefix.."."..domain_name);
if subdomain and subdomain ~= "" then
room_address = "["..subdomain.."]"..room_address;
end
if not verify_token(params["token"], room_address) then
return { status_code = 403; };
end
local room = get_room_from_jid(room_address);
local participant_count = 0;
local occupants_json = array();
log("debug", "Querying room %s", tostring(room_address));
if room then
local occupants = room._occupants;
if occupants then
participant_count = iterators.count(room:each_occupant());
for _, occupant in room:each_occupant() do
-- filter focus as we keep it as hidden participant
if string.sub(occupant.nick,-string.len("/focus"))~="/focus" then
for _, pr in occupant:each_session() do
local nick = pr:get_child_text("nick", "http://jabber.org/protocol/nick") or "";
local email = pr:get_child_text("email") or "";
occupants_json:push({
jid = tostring(occupant.nick),
email = tostring(email),
display_name = tostring(nick)});
end
end
end
end
log("debug",
"there are %s occupants in room", tostring(participant_count));
else
log("debug", "no such room exists");
return { status_code = 404; };
end
if participant_count > 1 then
participant_count = participant_count - 1;
end
return { status_code = 200; body = json.encode(occupants_json); };
end;
function module.load()
module:depends("http");
module:provides("http", {
default_path = "/";
route = {
["GET room-size"] = function (event) return async_handler_wrapper(event,handle_get_room_size) end;
["GET sessions"] = function () return tostring(it.count(it.keys(prosody.full_sessions))); end;
["GET room"] = function (event) return async_handler_wrapper(event,handle_get_room) end;
};
});
end