|
|
|
@ -10,6 +10,13 @@ if token_util == nil then |
|
|
|
|
return; |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
-- configuration to limit number of outgoing calls |
|
|
|
|
local LIMIT_OUTGOING_CALLS = module:get_option_number("max_number_outgoing_calls", -1); |
|
|
|
|
|
|
|
|
|
-- Header names to use to push extra data extracted from token, if any |
|
|
|
|
local OUT_INITIATOR_USER_ATTR_NAME = "X-outbound-call-initiator-user"; |
|
|
|
|
local OUT_INITIATOR_GROUP_ATTR_NAME = "X-outbound-call-initiator-group"; |
|
|
|
|
|
|
|
|
|
-- filters rayo iq in case of requested from not jwt authenticated sessions |
|
|
|
|
-- or if the session has features in user context and it doesn't mention |
|
|
|
|
-- feature "outbound-call" to be enabled |
|
|
|
@ -39,11 +46,120 @@ module:hook("pre-iq/full", function(event) |
|
|
|
|
(dial.attr.to == 'jitsi_meet_transcribe' and 'transcription' |
|
|
|
|
or 'outbound-call')) |
|
|
|
|
then |
|
|
|
|
module:log("info", |
|
|
|
|
module:log("warn", |
|
|
|
|
"Filtering stanza dial, stanza:%s", tostring(stanza)); |
|
|
|
|
session.send(st.error_reply(stanza, "auth", "forbidden")); |
|
|
|
|
return true; |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
-- now lets check any limits if configured |
|
|
|
|
if LIMIT_OUTGOING_CALLS > 0 |
|
|
|
|
and get_concurrent_outgoing_count( |
|
|
|
|
session.jitsi_meet_context_user["id"], |
|
|
|
|
session.jitsi_meet_context_group) >= LIMIT_OUTGOING_CALLS |
|
|
|
|
then |
|
|
|
|
module:log("warn", |
|
|
|
|
"Filtering stanza dial, stanza:%s, outgoing calls limit reached", tostring(stanza)); |
|
|
|
|
session.send(st.error_reply(stanza, "cancel", "resource-constraint")); |
|
|
|
|
return true; |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
-- now lets insert token information if any |
|
|
|
|
if session and session.jitsi_meet_context_user then |
|
|
|
|
-- First remove any 'header' element if it already |
|
|
|
|
-- exists, so it cannot be spoofed by a client |
|
|
|
|
stanza:maptags( |
|
|
|
|
function(tag) |
|
|
|
|
if tag.name == "header" |
|
|
|
|
and (tag.attr.name == OUT_INITIATOR_USER_ATTR_NAME |
|
|
|
|
or tag.attr.name == OUT_INITIATOR_GROUP_ATTR_NAME) then |
|
|
|
|
return nil |
|
|
|
|
end |
|
|
|
|
return tag |
|
|
|
|
end |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
local dial = stanza:get_child('dial', 'urn:xmpp:rayo:1'); |
|
|
|
|
-- adds initiator user id from token |
|
|
|
|
dial:tag("header", { |
|
|
|
|
xmlns = "urn:xmpp:rayo:1", |
|
|
|
|
name = OUT_INITIATOR_USER_ATTR_NAME, |
|
|
|
|
value = session.jitsi_meet_context_user["id"] }); |
|
|
|
|
dial:up(); |
|
|
|
|
|
|
|
|
|
-- Add the initiator group information if it is present |
|
|
|
|
if session.jitsi_meet_context_group then |
|
|
|
|
dial:tag("header", { |
|
|
|
|
xmlns = "urn:xmpp:rayo:1", |
|
|
|
|
name = OUT_INITIATOR_GROUP_ATTR_NAME, |
|
|
|
|
value = session.jitsi_meet_context_group }); |
|
|
|
|
dial:up(); |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end); |
|
|
|
|
|
|
|
|
|
--- Finds and returns the number of concurrent outgoing calls for a user |
|
|
|
|
-- @param context_user the user id extracted from the token |
|
|
|
|
-- @param context_group the group id extracted from the token |
|
|
|
|
-- @return returns the count of concurrent calls |
|
|
|
|
function get_concurrent_outgoing_count(context_user, context_group) |
|
|
|
|
local count = 0; |
|
|
|
|
for _, host in pairs(hosts) do |
|
|
|
|
local component = host; |
|
|
|
|
if component then |
|
|
|
|
local muc = component.modules.muc |
|
|
|
|
local rooms = nil; |
|
|
|
|
if muc and rawget(muc,"rooms") then |
|
|
|
|
-- We're running 0.9.x or 0.10 (old MUC API) |
|
|
|
|
return muc.rooms; |
|
|
|
|
elseif muc and rawget(muc,"live_rooms") then |
|
|
|
|
-- We're running >=0.11 (new MUC API) |
|
|
|
|
rooms = muc.live_rooms(); |
|
|
|
|
elseif muc and rawget(muc,"each_room") then |
|
|
|
|
-- We're running trunk<0.11 (each_room is later [DEPRECATED]) |
|
|
|
|
rooms = muc.each_room(true); |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
-- now lets iterate over rooms and occupants and search for |
|
|
|
|
-- call initiated by the user |
|
|
|
|
if rooms then |
|
|
|
|
for room in rooms do |
|
|
|
|
for _, occupant in room:each_occupant() do |
|
|
|
|
for _, presence in occupant:each_session() do |
|
|
|
|
|
|
|
|
|
local initiator = presence:get_child('initiator', 'http://jitsi.org/protocol/jigasi'); |
|
|
|
|
|
|
|
|
|
local found_user = false; |
|
|
|
|
local found_group = false; |
|
|
|
|
|
|
|
|
|
if initiator then |
|
|
|
|
initiator:maptags(function (tag) |
|
|
|
|
if tag.name == "header" |
|
|
|
|
and tag.attr.name == OUT_INITIATOR_USER_ATTR_NAME then |
|
|
|
|
found_user = tag.attr.value == context_user; |
|
|
|
|
elseif tag.name == "header" |
|
|
|
|
and tag.attr.name == OUT_INITIATOR_GROUP_ATTR_NAME then |
|
|
|
|
found_group = tag.attr.value == context_group; |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
return tag; |
|
|
|
|
end ); |
|
|
|
|
-- if found a jigasi participant initiated by the concurrent |
|
|
|
|
-- participant, count it |
|
|
|
|
if found_user |
|
|
|
|
and (context_group == nil or found_group) then |
|
|
|
|
count = count + 1; |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
return count; |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|