Kaynağa Gözat

feat(visitors): Handles locked rooms for visitors. (#13296)

* feat(visitors): Handles locked rooms for visitors.

* squash: Handle locked room password on promotion.

* squash: quotes.

* squash: Renames main_domain to local_domain.

* squash: Renames fmuc_main_domain to main_domain.

Adds required config to point to the main virtual host of the main prosody. There are cases when the first visitor tries to join and there are not main participants as they are in the queue waiting for the vnode connect message and we cannot get dynamically the main domain.

* squash: Fix check for main_domain config.
factor2
Дамян Минков 2 yıl önce
ebeveyn
işleme
e3e5f1fbfa
No account linked to committer's email address

+ 1
- 0
resources/extra-large-conference/prosody.cfg.lua.visitor.template Dosyayı Görüntüle

@@ -55,6 +55,7 @@ external_services = {
55 55
 };
56 56
 
57 57
 muc_mapper_domain_base = 'vX.meet.jitsi';
58
+main_domain = 'jitmeet.example.com';
58 59
 
59 60
 -- https://prosody.im/doc/modules/mod_smacks
60 61
 smacks_max_unacked_stanzas = 5;

+ 111
- 28
resources/prosody-plugins/mod_fmuc.lua Dosyayı Görüntüle

@@ -20,18 +20,28 @@ local get_room_from_jid = util.get_room_from_jid;
20 20
 local get_focus_occupant = util.get_focus_occupant;
21 21
 local internal_room_jid_match_rewrite = util.internal_room_jid_match_rewrite;
22 22
 
23
+-- this is the main virtual host of this vnode
24
+local local_domain = module:get_option_string('muc_mapper_domain_base');
25
+if not local_domain then
26
+    module:log('warn', "No 'muc_mapper_domain_base' option set, disabling fmuc plugin");
27
+    return;
28
+end
29
+
30
+-- this is the main virtual host of the main prosody that this vnode serves
31
+local main_domain = module:get_option_string('main_domain');
32
+if not main_domain then
33
+    module:log('warn', "No 'main_domain' option set, disabling fmuc plugin");
34
+    return;
35
+end
36
+
23 37
 local muc_domain_prefix = module:get_option_string('muc_mapper_domain_prefix', 'conference');
24
-local main_domain = string.gsub(module.host, muc_domain_prefix..'.', '');
25 38
 
26 39
 local NICK_NS = 'http://jabber.org/protocol/nick';
27 40
 
28 41
 -- we send stats for the total number of rooms, total number of participants and total number of visitors
29
-local measure_rooms = module:measure("vnode-rooms", "amount");
30
-local measure_participants = module:measure("vnode-participants", "amount");
31
-local measure_visitors = module:measure("vnode-visitors", "amount");
32
-
33
-local fmuc_main_domain;
42
+local measure_rooms = module:measure('vnode-rooms', 'amount');
43
+local measure_participants = module:measure('vnode-participants', 'amount');
44
+local measure_visitors = module:measure('vnode-visitors', 'amount');
34 45
 
35 46
 local sent_iq_cache = require 'util.cache'.new(200);
36 47
 
@@ -45,12 +55,8 @@ module:hook('muc-occupant-pre-join', function (event)
45 55
     local occupant, session = event.occupant, event.origin;
46 56
     local node, host = jid.split(occupant.bare_jid);
47 57
 
48
-    if host == main_domain then
58
+    if host == local_domain then
49 59
         occupant.role = 'visitor';
50
-    elseif not fmuc_main_domain then
51
-        if node ~= 'focus' then
52
-            fmuc_main_domain = host;
53
-        end
54 60
     end
55 61
 end, 3);
56 62
 
@@ -103,7 +109,7 @@ module:hook('muc-occupant-left', function (event)
103 109
     local room, occupant = event.room, event.occupant;
104 110
     local occupant_domain = jid.host(occupant.bare_jid);
105 111
 
106
-    if occupant_domain == main_domain then
112
+    if occupant_domain == local_domain then
107 113
         local focus_occupant = get_focus_occupant(room);
108 114
         if not focus_occupant then
109 115
             module:log('warn', 'No focus found for %s', room.jid);
@@ -181,11 +187,11 @@ module:hook('muc-broadcast-presence', function (event)
181 187
         sent_iq_cache:set(iq_id, socket.gettime());
182 188
         local promotion_request = st.iq({
183 189
             type = 'set',
184
-            to = 'visitors.'..fmuc_main_domain,
185
-            from = main_domain,
190
+            to = 'visitors.'..main_domain,
191
+            from = local_domain,
186 192
             id = iq_id })
187 193
           :tag('visitors', { xmlns = 'jitsi:visitors',
188
-                             room = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..fmuc_main_domain) })
194
+                             room = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..main_domain) })
189 195
           :tag('promotion-request', { xmlns = 'jitsi:visitors', jid = occupant.jid }):up();
190 196
 
191 197
         local nick_element = occupant:get_presence():get_child('nick', NICK_NS);
@@ -221,8 +227,8 @@ local function stanza_handler(event)
221 227
         return;
222 228
     end
223 229
 
224
-    if stanza.attr.from ~= 'visitors.'..fmuc_main_domain then
225
-        module:log('warn', 'not from visitors component, ignore! %s %s', stanza.attr.from, stanza);
230
+    if stanza.attr.from ~= 'visitors.'..main_domain then
231
+        module:log('warn', 'not from visitors component, ignore! %s', stanza);
226 232
         return true;
227 233
     end
228 234
 
@@ -241,7 +247,7 @@ local function stanza_handler(event)
241 247
 
242 248
     -- respond with successful receiving the iq
243 249
     origin.send(st.iq({
244
-        type = "result";
250
+        type = 'result';
245 251
         from = stanza.attr.to;
246 252
         to = stanza.attr.from;
247 253
         id = stanza.attr.id
@@ -276,12 +282,12 @@ function process_host_module(name, callback)
276 282
         process_host(name);
277 283
     end
278 284
 end
279
-process_host_module(main_domain, function(host_module, host)
285
+process_host_module(local_domain, function(host_module, host)
280 286
     host_module:hook('iq/host', stanza_handler, 10);
281 287
 end);
282 288
 
283 289
 -- only live chat is supported for visitors
284
-module:hook("muc-occupant-groupchat", function(event)
290
+module:hook('muc-occupant-groupchat', function(event)
285 291
     local occupant, room, stanza = event.occupant, event.room, event.stanza;
286 292
     local from = stanza.attr.from;
287 293
     local occupant_host = jid.host(occupant.bare_jid);
@@ -289,7 +295,7 @@ module:hook("muc-occupant-groupchat", function(event)
289 295
     -- if there is no occupant this is a message from main, probably coming from other vnode
290 296
     if occupant then
291 297
         -- we manage nick only for visitors
292
-        if occupant_host ~= fmuc_main_domain then
298
+        if occupant_host ~= main_domain then
293 299
             -- add to message stanza display name for the visitor
294 300
             -- remove existing nick to avoid forgery
295 301
             stanza:remove_children('nick', NICK_NS);
@@ -310,15 +316,15 @@ module:hook("muc-occupant-groupchat", function(event)
310 316
     -- let's send it to main chat and rest of visitors here
311 317
     for _, o in room:each_occupant() do
312 318
         -- filter remote occupants
313
-        if jid.host(o.bare_jid) == main_domain then
319
+        if jid.host(o.bare_jid) == local_domain then
314 320
             room:route_to_occupant(o, stanza)
315 321
         end
316 322
     end
317 323
 
318 324
     -- send to main participants only messages from local occupants (skip from remote vnodes)
319
-    if occupant and occupant_host ~= fmuc_main_domain then
325
+    if occupant and occupant_host ~= main_domain then
320 326
         local main_message = st.clone(stanza);
321
-        main_message.attr.to = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..fmuc_main_domain);
327
+        main_message.attr.to = jid.join(jid.node(room.jid), muc_domain_prefix..'.'..main_domain);
322 328
         module:send(main_message);
323 329
     end
324 330
     stanza.attr.from = from; -- something prosody does internally
@@ -328,20 +334,20 @@ end, 55); -- prosody check for visitor's chat is prio 50, we want to override it
328 334
 
329 335
 module:hook('muc-private-message', function(event)
330 336
     -- private messaging is forbidden
331
-    event.origin.send(st.error_reply(event.stanza, "auth", "forbidden",
332
-            "Private messaging is disabled on visitor nodes"));
337
+    event.origin.send(st.error_reply(event.stanza, 'auth', 'forbidden',
338
+            'Private messaging is disabled on visitor nodes'));
333 339
     return true;
334 340
 end, 10);
335 341
 
336 342
 -- we calculate the stats on the configured interval (60 seconds by default)
337
-module:hook_global("stats-update", function ()
343
+module:hook_global('stats-update', function ()
338 344
     local participants_count, rooms_count, visitors_count = 0, 0, 0;
339 345
 
340 346
     -- iterate over all rooms
341 347
     for room in prosody.hosts[module.host].modules.muc.each_room() do
342 348
         rooms_count = rooms_count + 1;
343 349
         for _, o in room:each_occupant() do
344
-            if jid.host(o.bare_jid) == main_domain then
350
+            if jid.host(o.bare_jid) == local_domain then
345 351
                 visitors_count = visitors_count + 1;
346 352
             else
347 353
                 participants_count = participants_count + 1;
@@ -356,4 +362,80 @@ module:hook_global("stats-update", function ()
356 362
     measure_participants(participants_count);
357 363
 end);
358 364
 
365
+-- we skip it till the main participants are added from the main prosody
366
+module:hook('jicofo-unlock-room', function(e)
367
+    -- we do not block events we fired
368
+    if e.fmuc_fired then
369
+        return;
370
+    end
371
+
372
+    return true;
373
+end);
374
+
375
+-- handles incoming iq connect stanzas
376
+local function iq_from_main_handler(event)
377
+    local origin, stanza = event.origin, event.stanza;
378
+
379
+    if stanza.name ~= 'iq' then
380
+        return;
381
+    end
382
+
383
+    if stanza.attr.type == 'result' and sent_iq_cache:get(stanza.attr.id) then
384
+        sent_iq_cache:set(stanza.attr.id, nil);
385
+        return true;
386
+    end
387
+
388
+    if stanza.attr.type ~= 'set' then
389
+        return;
390
+    end
391
+
392
+    local visitors_iq = event.stanza:get_child('visitors', 'jitsi:visitors');
393
+    if not visitors_iq then
394
+        return;
395
+    end
396
+
397
+    if stanza.attr.from ~= main_domain then
398
+        module:log('warn', 'not from main prosody, ignore! %s', stanza);
399
+        return true;
400
+    end
401
+
402
+    local room_jid = visitors_iq.attr.room;
403
+    local room = get_room_from_jid(room_jid_match_rewrite(room_jid));
404
+
405
+    if not room then
406
+        module:log('warn', 'No room found %s', room_jid);
407
+        return;
408
+    end
409
+
410
+    local node = visitors_iq:get_child('connect');
411
+    local fire_jicofo_unlock = true;
412
+
413
+    if not node then
414
+        node = visitors_iq:get_child('update');
415
+        fire_jicofo_unlock = false;
416
+    end
359 417
 
418
+    if not node then
419
+        return;
420
+    end
421
+
422
+    -- respond with successful receiving the iq
423
+    origin.send(st.iq({
424
+        type = 'result';
425
+        from = stanza.attr.to;
426
+        to = stanza.attr.from;
427
+        id = stanza.attr.id
428
+    }));
429
+
430
+    -- if there is password supplied use it
431
+    -- if this is update it will either set or remove the password
432
+    room:set_password(node.attr.password);
433
+
434
+    if fire_jicofo_unlock then
435
+        -- everything is connected allow participants to join
436
+        module:fire_event('jicofo-unlock-room', { room = room; fmuc_fired = true; });
437
+    end
438
+
439
+    return true;
440
+end
441
+module:hook('iq/host', iq_from_main_handler, 10);

+ 60
- 3
resources/prosody-plugins/mod_visitors.lua Dosyayı Görüntüle

@@ -10,6 +10,7 @@
10 10
 --- NOTE: Make sure all communication between prosodies is using the real jids ([foo]room1@muc.example.com)
11 11
 local st = require 'util.stanza';
12 12
 local jid = require 'util.jid';
13
+local new_id = require 'util.id'.medium;
13 14
 local util = module:require 'util';
14 15
 local presence_check_status = util.presence_check_status;
15 16
 
@@ -36,6 +37,8 @@ local ignore_list = module:get_option_set('visitors_ignore_list', {});
36 37
 -- Advertise the component for discovery via disco#items
37 38
 module:add_identity('component', 'visitors', 'visitors.'..module.host);
38 39
 
40
+local sent_iq_cache = require 'util.cache'.new(200);
41
+
39 42
 -- visitors_nodes = {
40 43
 --  roomjid1 = {
41 44
 --    nodes = {
@@ -47,6 +50,24 @@ module:add_identity('component', 'visitors', 'visitors.'..module.host);
47 50
 --}
48 51
 local visitors_nodes = {};
49 52
 
53
+-- sends connect or update iq
54
+-- @parameter type - Type of iq to send 'connect' or 'update'
55
+local function send_visitors_iq(conference_service, room, type)
56
+    -- send iq informing the vnode that the connect is done and it will allow visitors to join
57
+    local iq_id = new_id();
58
+    sent_iq_cache:set(iq_id, socket.gettime());
59
+    local connect_done = st.iq({
60
+        type = 'set',
61
+        to = conference_service,
62
+        from = module.host,
63
+        id = iq_id })
64
+      :tag('visitors', { xmlns = 'jitsi:visitors',
65
+                         room = jid.join(jid.node(room.jid), conference_service) })
66
+      :tag(type, { xmlns = 'jitsi:visitors', password = room:get_password() or '' }):up();
67
+
68
+      module:send(connect_done);
69
+end
70
+
50 71
 -- an event received from visitors component, which receives iqs from jicofo
51 72
 local function connect_vnode(event)
52 73
     local room, vnode = event.room, event.vnode;
@@ -75,7 +96,15 @@ local function connect_vnode(event)
75 96
             fmuc_pr.attr.to = jid.join(user, conference_service , res);
76 97
             fmuc_pr.attr.from = o.jid;
77 98
             -- add <x>
78
-            fmuc_pr:tag('x', { xmlns = MUC_NS }):up();
99
+            fmuc_pr:tag('x', { xmlns = MUC_NS });
100
+
101
+            -- if there is a password on the main room let's add the password for the vnode join
102
+            -- as we will set the password to the vnode room and we will need it
103
+            local pass = room:get_password();
104
+            if pass and pass ~= '' then
105
+                fmuc_pr:tag('password'):text(pass);
106
+            end
107
+            fmuc_pr:up();
79 108
 
80 109
             module:send(fmuc_pr);
81 110
 
@@ -83,9 +112,26 @@ local function connect_vnode(event)
83 112
         end
84 113
     end
85 114
     visitors_nodes[room.jid].nodes[conference_service] = sent_main_participants;
115
+
116
+    send_visitors_iq(conference_service, room, 'connect');
86 117
 end
87 118
 module:hook('jitsi-connect-vnode', connect_vnode);
88 119
 
120
+-- listens for responses to the iq sent for connecting vnode
121
+local function stanza_handler(event)
122
+    local origin, stanza = event.origin, event.stanza;
123
+
124
+    if stanza.name ~= 'iq' then
125
+        return;
126
+    end
127
+
128
+    if stanza.attr.type == 'result' and sent_iq_cache:get(stanza.attr.id) then
129
+        sent_iq_cache:set(stanza.attr.id, nil);
130
+        return true;
131
+    end
132
+end
133
+module:hook('iq/host', stanza_handler, 10);
134
+
89 135
 -- an event received from visitors component, which receives iqs from jicofo
90 136
 local function disconnect_vnode(event)
91 137
     local room, vnode = event.room, event.vnode;
@@ -211,7 +257,7 @@ process_host_module(main_muc_component_config, function(host_module, host)
211 257
         end
212 258
     end);
213 259
     -- forwards messages from main participants to vnodes
214
-    host_module:hook("muc-occupant-groupchat", function(event)
260
+    host_module:hook('muc-occupant-groupchat', function(event)
215 261
         local room, stanza, occupant = event.room, event.stanza, event.occupant;
216 262
 
217 263
         -- filter sending messages from transcribers/jibris to visitors
@@ -231,7 +277,7 @@ process_host_module(main_muc_component_config, function(host_module, host)
231 277
     end);
232 278
     -- receiving messages from visitor nodes and forward them to local main participants
233 279
     -- and forward them to the rest of visitor nodes
234
-    host_module:hook("muc-occupant-groupchat", function(event)
280
+    host_module:hook('muc-occupant-groupchat', function(event)
235 281
         local occupant, room, stanza = event.occupant, event.room, event.stanza;
236 282
         local to = stanza.attr.to;
237 283
         local from = stanza.attr.from;
@@ -260,4 +306,15 @@ process_host_module(main_muc_component_config, function(host_module, host)
260 306
 
261 307
         return true;
262 308
     end, 55); -- prosody check for unknown participant chat is prio 50, we want to override it
309
+
310
+    host_module:hook('muc-config-submitted/muc#roomconfig_roomsecret', function(event)
311
+        if event.status_codes['104'] then
312
+            local room = event.room;
313
+            -- we need to update all vnodes
314
+            local vnodes = visitors_nodes[room.jid].nodes;
315
+            for conference_service in pairs(vnodes) do
316
+                send_visitors_iq(conference_service, room, 'update');
317
+            end
318
+        end
319
+end, -100); -- we want to run last in order to check is the status code 104
263 320
 end);

+ 14
- 5
resources/prosody-plugins/mod_visitors_component.lua Dosyayı Görüntüle

@@ -8,7 +8,9 @@ local get_room_from_jid = util.get_room_from_jid;
8 8
 local get_focus_occupant = util.get_focus_occupant;
9 9
 local get_room_by_name_and_subdomain = util.get_room_by_name_and_subdomain;
10 10
 local new_id = require 'util.id'.medium;
11
-local um_is_admin = require "core.usermanager".is_admin;
11
+local um_is_admin = require 'core.usermanager'.is_admin;
12
+
13
+local MUC_NS = 'http://jabber.org/protocol/muc';
12 14
 
13 15
 local muc_domain_prefix = module:get_option_string('muc_mapper_domain_prefix', 'conference');
14 16
 local muc_domain_base = module:get_option_string('muc_mapper_domain_base');
@@ -17,7 +19,7 @@ if not muc_domain_base then
17 19
     return;
18 20
 end
19 21
 
20
-local auto_allow_promotion = module:get_option_boolean("auto_allow_visitor_promotion", false);
22
+local auto_allow_promotion = module:get_option_boolean('auto_allow_visitor_promotion', false);
21 23
 
22 24
 local function is_admin(jid)
23 25
     return um_is_admin(jid, module.host);
@@ -33,7 +35,7 @@ local sent_iq_cache = require 'util.cache'.new(200);
33 35
 local function respond_iq_result(origin, stanza)
34 36
     -- respond with successful receiving the iq
35 37
     origin.send(st.iq({
36
-        type = "result";
38
+        type = 'result';
37 39
         from = stanza.attr.to;
38 40
         to = stanza.attr.from;
39 41
         id = stanza.attr.id
@@ -158,7 +160,7 @@ local function stanza_handler(event)
158 160
     return processed;
159 161
 end
160 162
 
161
-module:hook("iq/host", stanza_handler, 10);
163
+module:hook('iq/host', stanza_handler, 10);
162 164
 
163 165
  --process a host module directly if loaded or hooks to wait for its load
164 166
 function process_host_module(name, callback)
@@ -184,6 +186,13 @@ process_host_module(muc_domain_prefix..'.'..muc_domain_base, function(host_modul
184 186
     host_module:hook('muc-occupant-pre-join', function (event)
185 187
         local room, stanza, origin = event.room, event.stanza, event.origin;
186 188
 
189
+        -- visitors were already in the room one way or another they have access
190
+        -- skip password challenge
191
+        local join = stanza:get_child('x', MUC_NS);
192
+        if join and room:get_password() then
193
+            join:tag('password', { xmlns = MUC_NS }):text(room:get_password());
194
+        end
195
+
187 196
         -- we skip any checks when auto-allow is enabled
188 197
         if auto_allow_promotion then
189 198
             return;
@@ -208,7 +217,7 @@ end);
208 217
 
209 218
 -- enable only in case of auto-allow is enabled
210 219
 if auto_allow_promotion then
211
-    prosody.events.add_handler("pre-jitsi-authentication", function(session)
220
+    prosody.events.add_handler('pre-jitsi-authentication', function(session)
212 221
         if not session.customusername or not session.jitsi_web_query_room then
213 222
             return nil;
214 223
         end

Loading…
İptal
Kaydet