Merge pull request #1788 from jitsi/module-poltergeist
module-poltergeist
This commit is contained in:
commit
0c446026d6
|
@ -23,8 +23,12 @@ module:hook("bosh-session", function(event)
|
|||
local query = request.url.query;
|
||||
|
||||
if query ~= nil then
|
||||
session.auth_token = query and formdecode(query).token or nil;
|
||||
end
|
||||
local params = formdecode(query);
|
||||
session.auth_token = query and params.token or nil;
|
||||
|
||||
-- The room name from the bosh query
|
||||
session.jitsi_bosh_query_room = params.room;
|
||||
end
|
||||
end);
|
||||
|
||||
function provider.test_password(username, password)
|
||||
|
@ -54,7 +58,18 @@ end
|
|||
function provider.get_sasl_handler(session)
|
||||
|
||||
local function get_username_from_token(self, message)
|
||||
return token_util:process_and_verify_token(session);
|
||||
local res = token_util:process_and_verify_token(session);
|
||||
|
||||
local customUsername
|
||||
= prosody.events.fire_event("pre-jitsi-authentication", session);
|
||||
|
||||
if (customUsername) then
|
||||
self.username = customUsername;
|
||||
else
|
||||
self.username = message;
|
||||
end
|
||||
|
||||
return res;
|
||||
end
|
||||
|
||||
return new_sasl(host, { anonymous = get_username_from_token });
|
||||
|
@ -69,8 +84,6 @@ local function anonymous(self, message)
|
|||
-- This calls the handler created in 'provider.get_sasl_handler(session)'
|
||||
local result, err, msg = self.profile.anonymous(self, username, self.realm);
|
||||
|
||||
self.username = username;
|
||||
|
||||
if result == true then
|
||||
return "success";
|
||||
else
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
local bare = require "util.jid".bare;
|
||||
local generate_uuid = require "util.uuid".generate;
|
||||
local jid = require "util.jid";
|
||||
local neturl = require "net.url";
|
||||
local parse = neturl.parseQuery;
|
||||
local st = require "util.stanza";
|
||||
local get_room_from_jid = module:require "util".get_room_from_jid;
|
||||
|
||||
-- Options
|
||||
local poltergeist_component
|
||||
= module:get_option_string("poltergeist_component", module.host);
|
||||
|
||||
-- table to store all poltergeists we create
|
||||
local poltergeists = {};
|
||||
|
||||
-- poltergaist management functions
|
||||
|
||||
-- Returns the room if available, work and in multidomain mode
|
||||
-- @param room_name the name of the room
|
||||
-- @param group name of the group (optional)
|
||||
-- @return returns room if found or nil
|
||||
function get_room(room_name, group)
|
||||
local room_address = jid.join(room_name, module:get_host());
|
||||
-- if there is a group we are in multidomain mode
|
||||
if group and group ~= "" then
|
||||
room_address = "["..group.."]"..room_address;
|
||||
end
|
||||
|
||||
return get_room_from_jid(room_address);
|
||||
end
|
||||
|
||||
-- Stores the username in the table where we store poltergeist usernames
|
||||
-- based on their room names
|
||||
-- @param room the room instance
|
||||
-- @param user_id the user id
|
||||
-- @param username the username to store
|
||||
function store_username(room, user_id, username)
|
||||
local room_name = jid.node(room.jid);
|
||||
|
||||
-- we store in poltergeist user ids for room names
|
||||
if (not poltergeists[room_name]) then
|
||||
poltergeists[room_name] = {};
|
||||
end
|
||||
poltergeists[room_name][user_id] = username;
|
||||
log("debug", "stored in session: %s", username);
|
||||
end
|
||||
|
||||
-- Retrieve the username for a user
|
||||
-- @param room the room instance
|
||||
-- @param user_id the user id
|
||||
-- @return returns the stored username for user or nil
|
||||
function get_username(room, user_id)
|
||||
local room_name = jid.node(room.jid);
|
||||
|
||||
if (not poltergeists[room_name]) then
|
||||
return nil;
|
||||
end
|
||||
|
||||
return poltergeists[room_name][user_id];
|
||||
end
|
||||
|
||||
-- if we found that a session for a user with id has a poltergiest already
|
||||
-- created, retrieve its jid and return it to the authentication
|
||||
-- so we can reuse it and we that real user will replace the poltergiest
|
||||
prosody.events.add_handler("pre-jitsi-authentication", function(session)
|
||||
|
||||
if (session.jitsi_meet_context_user) then
|
||||
local room = get_room(
|
||||
session.jitsi_bosh_query_room,
|
||||
session.jitsi_meet_context_group);
|
||||
|
||||
if (not room) then
|
||||
return nil;
|
||||
end
|
||||
|
||||
local username
|
||||
= get_username(room, session.jitsi_meet_context_user["id"]);
|
||||
|
||||
if (not username) then
|
||||
return nil;
|
||||
end
|
||||
|
||||
log("debug", "Found predefined username %s", username);
|
||||
|
||||
-- let's find the room and if the poltergeist occupant is there
|
||||
-- lets remove him before the real participant joins
|
||||
-- when we see the unavailable presence to go out the server
|
||||
-- we will mark it with ignore tag
|
||||
local nick = string.sub(username, 0, 8);
|
||||
if (have_poltergeist_occupant(room, nick)) then
|
||||
remove_poltergeist_occupant(room, nick);
|
||||
end
|
||||
|
||||
return username;
|
||||
end
|
||||
|
||||
return nil;
|
||||
end);
|
||||
|
||||
-- Creates poltergeist occupant
|
||||
-- @param room the room instance where we create the occupant
|
||||
-- @param nick the nick to use for the new occupant
|
||||
-- @param name the display name fot the occupant (optional)
|
||||
-- @param avatar the avatar to use for the new occupant (optional)
|
||||
function create_poltergeist_occupant(room, nick, name, avatar)
|
||||
log("debug", "create_poltergeist_occupant %s:", nick);
|
||||
-- Join poltergeist occupant to room, with the invited JID as their nick
|
||||
local join_presence = st.presence({
|
||||
to = room.jid.."/"..nick,
|
||||
from = poltergeist_component.."/"..nick
|
||||
}):tag("x", { xmlns = "http://jabber.org/protocol/muc" }):up();
|
||||
|
||||
if (name) then
|
||||
join_presence:tag(
|
||||
"nick",
|
||||
{ xmlns = "http://jabber.org/protocol/nick" }):text(name):up();
|
||||
end
|
||||
if (avatar) then
|
||||
join_presence:tag("avatar-url"):text(avatar):up();
|
||||
end
|
||||
|
||||
room:handle_first_presence(
|
||||
prosody.hosts[poltergeist_component], join_presence);
|
||||
end
|
||||
|
||||
-- Removes poltergeist occupant
|
||||
-- @param room the room instance where to remove the occupant
|
||||
-- @param nick the nick of the occupant to remove
|
||||
function remove_poltergeist_occupant(room, nick)
|
||||
log("debug", "remove_poltergeist_occupant %s", nick);
|
||||
local leave_presence = st.presence({
|
||||
to = room.jid.."/"..nick,
|
||||
from = poltergeist_component.."/"..nick,
|
||||
type = "unavailable" });
|
||||
room:handle_normal_presence(
|
||||
prosody.hosts[poltergeist_component], leave_presence);
|
||||
end
|
||||
|
||||
-- Checks for existance of a poltergeist occupant
|
||||
-- @param room the room instance where to check for occupant
|
||||
-- @param nick the nick of the occupant
|
||||
-- @return true if occupant is found, false otherwise
|
||||
function have_poltergeist_occupant(room, nick)
|
||||
-- Find out if we have a poltergeist occupant in the room for this JID
|
||||
return not not room:get_occupant_jid(poltergeist_component.."/"..nick);
|
||||
end
|
||||
|
||||
-- Event handlers
|
||||
|
||||
--- Note: mod_muc and some of its sub-modules add event handlers between 0 and -100,
|
||||
--- e.g. to check for banned users, etc.. Hence adding these handlers at priority -100.
|
||||
module:hook("muc-decline", function (event)
|
||||
remove_poltergeist_occupant(event.room, bare(event.stanza.attr.from));
|
||||
end, -100);
|
||||
-- before sending the presence for a poltergeist leaving add ignore tag
|
||||
-- as poltergeist is leaving just before the real user joins and in the client
|
||||
-- we ignore this presence to avoid leaving/joining experience and the real
|
||||
-- user will reuse all currently created UI components for the same nick
|
||||
module:hook("muc-broadcast-presence", function (event)
|
||||
if (bare(event.occupant.jid) == poltergeist_component) then
|
||||
if(event.stanza.attr.type == "unavailable") then
|
||||
event.stanza:tag(
|
||||
"ignore", { xmlns = "http://jitsi.org/jitmeet/" }):up();
|
||||
end
|
||||
end
|
||||
end, -100);
|
||||
|
||||
--- Handles request for creating/managing poltergeists
|
||||
-- @param event the http event, holds the request query
|
||||
-- @return GET response, containing a json with response details
|
||||
function handle_create_poltergeist (event)
|
||||
local params = parse(event.request.url.query);
|
||||
local user_id = params["user"];
|
||||
local room_name = params["room"];
|
||||
local group = params["group"];
|
||||
local name = params["name"];
|
||||
local avatar = params["avatar"];
|
||||
|
||||
local room = get_room(room_name, group);
|
||||
if (not room) then
|
||||
log("error", "no room found %s", room_address);
|
||||
return 404;
|
||||
end
|
||||
|
||||
local username = generate_uuid();
|
||||
store_username(room, user_id, username)
|
||||
|
||||
create_poltergeist_occupant(room, string.sub(username,0,8), name, avatar);
|
||||
|
||||
return 200;
|
||||
end
|
||||
|
||||
--- Handles request for updating poltergeists status
|
||||
-- @param event the http event, holds the request query
|
||||
-- @return GET response, containing a json with response details
|
||||
function handle_update_poltergeist (event)
|
||||
local params = parse(event.request.url.query);
|
||||
local user_id = params["user"];
|
||||
local room_name = params["room"];
|
||||
local group = params["group"];
|
||||
local status = params["status"];
|
||||
|
||||
local room = get_room(room_name, group);
|
||||
if (not room) then
|
||||
log("error", "no room found %s", room_address);
|
||||
return 404;
|
||||
end
|
||||
|
||||
local username = get_username(room, user_id);
|
||||
if (not username) then
|
||||
return 404;
|
||||
end
|
||||
|
||||
local nick = string.sub(username, 0, 8);
|
||||
if (have_poltergeist_occupant(room, nick)) then
|
||||
local update_presence = st.presence({
|
||||
to = room.jid.."/"..nick,
|
||||
from = poltergeist_component.."/"..nick
|
||||
}):tag("status"):text(status):up();
|
||||
|
||||
room:handle_normal_presence(
|
||||
prosody.hosts[poltergeist_component], update_presence);
|
||||
|
||||
return 200;
|
||||
else
|
||||
return 404;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
log("info", "Loading poltergeist service");
|
||||
module:depends("http");
|
||||
module:provides("http", {
|
||||
default_path = "/";
|
||||
name = "poltergeist";
|
||||
route = {
|
||||
["GET /poltergeist/create"] = handle_create_poltergeist;
|
||||
["GET /poltergeist/update"] = handle_update_poltergeist;
|
||||
};
|
||||
});
|
|
@ -19,6 +19,7 @@ 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
|
||||
|
@ -31,26 +32,6 @@ end
|
|||
local muc_domain_prefix
|
||||
= module:get_option_string("muc_mapper_domain_prefix", "conference");
|
||||
|
||||
--- Finds and returns room by its jid
|
||||
-- @param room_jid the room jid to search in the muc component
|
||||
-- @return returns room if found or nil
|
||||
function get_room_from_jid(room_jid)
|
||||
local _, host = jid.split(room_jid);
|
||||
local component = hosts[host];
|
||||
if component then
|
||||
local muc = component.modules.muc
|
||||
if muc and rawget(muc,"rooms") then
|
||||
-- We're running 0.9.x or 0.10 (old MUC API)
|
||||
return muc.rooms[room_jid];
|
||||
elseif muc and rawget(muc,"get_room_from_jid") then
|
||||
-- We're running >0.10 (new MUC API)
|
||||
return muc.get_room_from_jid(room_jid);
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- 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
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
local st = require "util.stanza";
|
||||
|
||||
-- A component which we use to receive all stanzas for the created poltergeists
|
||||
-- replays with error if an iq is sent
|
||||
function no_action()
|
||||
return true;
|
||||
end
|
||||
|
||||
function error_reply(event)
|
||||
module:send(st.error_reply(event.stanza, "cancel", "service-unavailable"));
|
||||
return true;
|
||||
end
|
||||
|
||||
module:hook("presence/host", no_action);
|
||||
module:hook("message/host", no_action);
|
||||
module:hook("presence/full", no_action);
|
||||
module:hook("message/full", no_action);
|
||||
|
||||
module:hook("iq/host", error_reply);
|
||||
module:hook("iq/full", error_reply);
|
||||
module:hook("iq/bare", error_reply);
|
|
@ -0,0 +1,25 @@
|
|||
local jid = require "util.jid";
|
||||
|
||||
--- Finds and returns room by its jid
|
||||
-- @param room_jid the room jid to search in the muc component
|
||||
-- @return returns room if found or nil
|
||||
function get_room_from_jid(room_jid)
|
||||
local _, host = jid.split(room_jid);
|
||||
local component = hosts[host];
|
||||
if component then
|
||||
local muc = component.modules.muc
|
||||
if muc and rawget(muc,"rooms") then
|
||||
-- We're running 0.9.x or 0.10 (old MUC API)
|
||||
return muc.rooms[room_jid];
|
||||
elseif muc and rawget(muc,"get_room_from_jid") then
|
||||
-- We're running >0.10 (new MUC API)
|
||||
return muc.get_room_from_jid(room_jid);
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
get_room_from_jid = get_room_from_jid;
|
||||
};
|
Loading…
Reference in New Issue