"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-5079/resources/prosody-plugins/mod_filter_iq_rayo.lua" (17 Jun 2021, 8026 Bytes) of package /linux/misc/jitsi-meet-5079.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Lua source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 local new_throttle = require "util.throttle".create;
    2 local st = require "util.stanza";
    3 
    4 local token_util = module:require "token/util".new(module);
    5 local room_jid_match_rewrite = module:require "util".room_jid_match_rewrite;
    6 local is_feature_allowed = module:require "util".is_feature_allowed;
    7 
    8 -- no token configuration but required
    9 if token_util == nil then
   10     log("error", "no token configuration but it is required");
   11     return;
   12 end
   13 
   14 -- The maximum number of simultaneous calls,
   15 -- and also the maximum number of new calls per minute that a session is allowed to create.
   16 local limit_outgoing_calls;
   17 local function load_config()
   18     limit_outgoing_calls = module:get_option_number("max_number_outgoing_calls", -1);
   19 end
   20 load_config();
   21 
   22 -- Header names to use to push extra data extracted from token, if any
   23 local OUT_INITIATOR_USER_ATTR_NAME = "X-outbound-call-initiator-user";
   24 local OUT_INITIATOR_GROUP_ATTR_NAME = "X-outbound-call-initiator-group";
   25 local OUTGOING_CALLS_THROTTLE_INTERVAL = 60; -- if max_number_outgoing_calls is enabled it will be
   26                                              -- the max number of outgoing calls a user can try for a minute
   27 
   28 -- filters rayo iq in case of requested from not jwt authenticated sessions
   29 -- or if the session has features in user context and it doesn't mention
   30 -- feature "outbound-call" to be enabled
   31 module:hook("pre-iq/full", function(event)
   32     local stanza = event.stanza;
   33     if stanza.name == "iq" then
   34         local dial = stanza:get_child('dial', 'urn:xmpp:rayo:1');
   35         if dial then
   36             local session = event.origin;
   37             local token = session.auth_token;
   38 
   39             -- find header with attr name 'JvbRoomName' and extract its value
   40             local headerName = 'JvbRoomName';
   41             local roomName;
   42             for _, child in ipairs(dial.tags) do
   43                 if (child.name == 'header'
   44                         and child.attr.name == headerName) then
   45                     roomName = child.attr.value;
   46                     break;
   47                 end
   48             end
   49 
   50             if token == nil
   51                 or roomName == nil
   52                 or not token_util:verify_room(session, room_jid_match_rewrite(roomName))
   53                 or not is_feature_allowed(session,
   54                             (dial.attr.to == 'jitsi_meet_transcribe' and 'transcription'
   55                                 or 'outbound-call'))
   56             then
   57                 module:log("warn",
   58                     "Filtering stanza dial, stanza:%s", tostring(stanza));
   59                 session.send(st.error_reply(stanza, "auth", "forbidden"));
   60                 return true;
   61             end
   62 
   63             -- now lets check any limits if configured
   64             if limit_outgoing_calls > 0 then
   65                 if not session.dial_out_throttle then
   66                     module:log("debug", "Enabling dial-out throttle session=%s.", session);
   67                     session.dial_out_throttle = new_throttle(limit_outgoing_calls, OUTGOING_CALLS_THROTTLE_INTERVAL);
   68                 end
   69 
   70                 if not session.dial_out_throttle:poll(1) -- we first check the throttle so we can mark one incoming dial for the balance
   71                     or get_concurrent_outgoing_count(session.jitsi_meet_context_user["id"], session.jitsi_meet_context_group)
   72                             >= limit_outgoing_calls
   73                 then
   74                     module:log("warn",
   75                         "Filtering stanza dial, stanza:%s, outgoing calls limit reached", tostring(stanza));
   76                     session.send(st.error_reply(stanza, "cancel", "resource-constraint"));
   77                     return true;
   78                 end
   79             end
   80 
   81             -- now lets insert token information if any
   82             if session and session.jitsi_meet_context_user then
   83                 -- First remove any 'header' element if it already
   84                 -- exists, so it cannot be spoofed by a client
   85                 stanza:maptags(
   86                     function(tag)
   87                         if tag.name == "header"
   88                                 and (tag.attr.name == OUT_INITIATOR_USER_ATTR_NAME
   89                                         or tag.attr.name == OUT_INITIATOR_GROUP_ATTR_NAME) then
   90                             return nil
   91                         end
   92                         return tag
   93                     end
   94                 )
   95 
   96                 local dial = stanza:get_child('dial', 'urn:xmpp:rayo:1');
   97                 -- adds initiator user id from token
   98                 dial:tag("header", {
   99                     xmlns = "urn:xmpp:rayo:1",
  100                     name = OUT_INITIATOR_USER_ATTR_NAME,
  101                     value = session.jitsi_meet_context_user["id"] });
  102                 dial:up();
  103 
  104                 -- Add the initiator group information if it is present
  105                 if session.jitsi_meet_context_group then
  106                     dial:tag("header", {
  107                         xmlns = "urn:xmpp:rayo:1",
  108                         name = OUT_INITIATOR_GROUP_ATTR_NAME,
  109                         value = session.jitsi_meet_context_group });
  110                     dial:up();
  111                 end
  112             end
  113         end
  114     end
  115 end);
  116 
  117 --- Finds and returns the number of concurrent outgoing calls for a user
  118 -- @param context_user the user id extracted from the token
  119 -- @param context_group the group id extracted from the token
  120 -- @return returns the count of concurrent calls
  121 function get_concurrent_outgoing_count(context_user, context_group)
  122     local count = 0;
  123     for _, host in pairs(hosts) do
  124         local component = host;
  125         if component then
  126             local muc = component.modules.muc
  127             local rooms = nil;
  128             if muc and rawget(muc,"rooms") then
  129                 -- We're running 0.9.x or 0.10 (old MUC API)
  130                 return muc.rooms;
  131             elseif muc and rawget(muc,"live_rooms") then
  132                 -- We're running >=0.11 (new MUC API)
  133                 rooms = muc.live_rooms();
  134             elseif muc and rawget(muc,"each_room") then
  135                 -- We're running trunk<0.11 (each_room is later [DEPRECATED])
  136                 rooms = muc.each_room(true);
  137             end
  138 
  139             -- now lets iterate over rooms and occupants and search for
  140             -- call initiated by the user
  141             if rooms then
  142                 for room in rooms do
  143                     for _, occupant in room:each_occupant() do
  144                         for _, presence in occupant:each_session() do
  145 
  146                             local initiator = presence:get_child('initiator', 'http://jitsi.org/protocol/jigasi');
  147 
  148                             local found_user = false;
  149                             local found_group = false;
  150 
  151                             if initiator then
  152                                 initiator:maptags(function (tag)
  153                                     if tag.name == "header"
  154                                         and tag.attr.name == OUT_INITIATOR_USER_ATTR_NAME then
  155                                         found_user = tag.attr.value == context_user;
  156                                     elseif tag.name == "header"
  157                                         and tag.attr.name == OUT_INITIATOR_GROUP_ATTR_NAME then
  158                                         found_group = tag.attr.value == context_group;
  159                                     end
  160 
  161                                     return tag;
  162                                 end );
  163                                 -- if found a jigasi participant initiated by the concurrent
  164                                 -- participant, count it
  165                                 if found_user
  166                                     and (context_group == nil or found_group) then
  167                                     count = count + 1;
  168                                 end
  169                             end
  170                         end
  171                     end
  172                 end
  173             end
  174         end
  175     end
  176 
  177     return count;
  178 end
  179 
  180 module:hook_global('config-reloaded', load_config);