|
@@ -1,22 +1,15 @@
|
1
|
1
|
local bare = require "util.jid".bare;
|
2
|
|
-local generate_uuid = require "util.uuid".generate;
|
|
2
|
+local get_room_from_jid = module:require "util".get_room_from_jid;
|
3
|
3
|
local jid = require "util.jid";
|
4
|
4
|
local neturl = require "net.url";
|
5
|
5
|
local parse = neturl.parseQuery;
|
6
|
|
-local st = require "util.stanza";
|
7
|
|
-local get_room_from_jid = module:require "util".get_room_from_jid;
|
|
6
|
+local poltergeist = module:require "poltergeist";
|
8
|
7
|
local wrap_async_run = module:require "util".wrap_async_run;
|
9
|
|
-local update_presence_identity = module:require "util".update_presence_identity;
|
10
|
|
-local timer = require "util.timer";
|
11
|
|
-local MUC_NS = "http://jabber.org/protocol/muc";
|
12
|
|
-local expired_status = "expired";
|
13
|
8
|
|
14
|
9
|
-- Options
|
15
|
10
|
local poltergeist_component
|
16
|
11
|
= module:get_option_string("poltergeist_component", module.host);
|
17
|
|
-local poltergeist_timeout
|
18
|
|
- = module:get_option_string("poltergeist_leave_timeout", 30);
|
|
12
|
+
|
19
|
13
|
-- this basically strips the domain from the conference.domain address
|
20
|
14
|
local parentHostName = string.gmatch(tostring(module.host), "%w+.(%w.+)")();
|
21
|
15
|
if parentHostName == nil then
|
|
@@ -37,12 +30,6 @@ local token_util = module:require "token/util".new(parentCtx);
|
37
|
30
|
local disableTokenVerification
|
38
|
31
|
= module:get_option_boolean("disable_polergeist_token_verification", false);
|
39
|
32
|
|
40
|
|
-local poltergeists = {};
|
41
|
|
-local poltergeists_pr_ignore = {};
|
42
|
|
-
|
43
|
33
|
-- poltergaist management functions
|
44
|
34
|
|
45
|
35
|
-- Returns the room if available, work and in multidomain mode
|
|
@@ -60,54 +47,6 @@ function get_room(room_name, group)
|
60
|
47
|
return get_room_from_jid(room_address);
|
61
|
48
|
end
|
62
|
49
|
|
63
|
|
-function store_username(room, user_id, username)
|
64
|
|
- local room_name = jid.node(room.jid);
|
65
|
|
-
|
66
|
|
- -- we store in poltergeist user ids for room names
|
67
|
|
- if (not poltergeists[room_name]) then
|
68
|
|
- poltergeists[room_name] = {};
|
69
|
|
- end
|
70
|
|
- poltergeists[room_name][user_id] = username;
|
71
|
|
- log("debug", "stored in session: %s", username);
|
72
|
|
-end
|
73
|
|
-
|
74
|
|
-function get_username(room, user_id)
|
75
|
|
- local room_name = jid.node(room.jid);
|
76
|
|
-
|
77
|
|
- if (not poltergeists[room_name]) then
|
78
|
|
- return nil;
|
79
|
|
- end
|
80
|
|
-
|
81
|
|
- return poltergeists[room_name][user_id];
|
82
|
|
-end
|
83
|
|
-
|
84
|
|
-function remove_username(room, nick)
|
85
|
|
- local room_name = jid.node(room.jid);
|
86
|
|
- if (poltergeists[room_name]) then
|
87
|
|
- local user_id_to_remove;
|
88
|
|
- for name,username in pairs(poltergeists[room_name]) do
|
89
|
|
- if (string.sub(username, 0, 8) == nick) then
|
90
|
|
- user_id_to_remove = name;
|
91
|
|
- end
|
92
|
|
- end
|
93
|
|
- if (user_id_to_remove) then
|
94
|
|
- poltergeists[room_name][user_id_to_remove] = nil;
|
95
|
|
- end
|
96
|
|
- end
|
97
|
|
-end
|
98
|
|
-
|
99
|
50
|
--- Verifies room name, domain name with the values in the token
|
100
|
51
|
-- @param token the token we received
|
101
|
52
|
-- @param room_name the room name
|
|
@@ -151,6 +90,8 @@ function verify_token(token, room_name, group, session)
|
151
|
90
|
return true;
|
152
|
91
|
end
|
153
|
92
|
|
|
93
|
+-- Event handlers
|
|
94
|
+
|
154
|
95
|
-- if we found that a session for a user with id has a poltergiest already
|
155
|
96
|
-- created, retrieve its jid and return it to the authentication
|
156
|
97
|
-- so we can reuse it and we that real user will replace the poltergiest
|
|
@@ -165,8 +106,10 @@ prosody.events.add_handler("pre-jitsi-authentication", function(session)
|
165
|
106
|
return nil;
|
166
|
107
|
end
|
167
|
108
|
|
168
|
|
- local username
|
169
|
|
- = get_username(room, session.jitsi_meet_context_user["id"]);
|
|
109
|
+ local username = poltergeist.get_username(
|
|
110
|
+ room,
|
|
111
|
+ session.jitsi_meet_context_user["id"]
|
|
112
|
+ );
|
170
|
113
|
|
171
|
114
|
if (not username) then
|
172
|
115
|
return nil;
|
|
@@ -178,12 +121,12 @@ prosody.events.add_handler("pre-jitsi-authentication", function(session)
|
178
|
121
|
-- lets remove him before the real participant joins
|
179
|
122
|
-- when we see the unavailable presence to go out the server
|
180
|
123
|
-- we will mark it with ignore tag
|
181
|
|
- local nick = string.sub(username, 0, 8);
|
182
|
|
- if (have_poltergeist_occupant(room, nick)) then
|
|
124
|
+ local nick = poltergeist.create_nick(username);
|
|
125
|
+ if (poltergeist.occupies(room, nick)) then
|
|
126
|
+ module:log("info", "swapping poltergeist for user: %s/%s", room, nick)
|
183
|
127
|
-- notify that user connected using the poltergeist
|
184
|
|
- update_poltergeist_occupant_status(
|
185
|
|
- room, nick, "connected");
|
186
|
|
- remove_poltergeist_occupant(room, nick, true);
|
|
128
|
+ poltergeist.update(room, nick, "connected");
|
|
129
|
+ poltergeist.remove(room, nick, true);
|
187
|
130
|
end
|
188
|
131
|
|
189
|
132
|
return username;
|
|
@@ -192,134 +135,10 @@ prosody.events.add_handler("pre-jitsi-authentication", function(session)
|
192
|
135
|
return nil;
|
193
|
136
|
end);
|
194
|
137
|
|
195
|
|
-function remove_poltergeist_occupant(room, nick, ignore)
|
196
|
|
- log("debug", "remove_poltergeist_occupant %s", nick);
|
197
|
|
-
|
198
|
|
- local current_presence = get_presence(room, nick);
|
199
|
|
- if (not current_presence) then
|
200
|
|
- module:log("info", "attempted to remove a poltergeist with no presence")
|
201
|
|
- return;
|
202
|
|
- end
|
203
|
|
-
|
204
|
|
- local leave_presence = st.clone(current_presence)
|
205
|
|
- leave_presence.attr.to = room.jid.."/"..nick;
|
206
|
|
- leave_presence.attr.from = poltergeist_component.."/"..nick;
|
207
|
|
- leave_presence.attr.type = "unavailable";
|
208
|
|
-
|
209
|
|
- if (ignore) then
|
210
|
|
- poltergeists_pr_ignore[room.jid.."/"..nick] = true;
|
211
|
|
- end
|
212
|
|
-
|
213
|
|
- room:handle_normal_presence(
|
214
|
|
- prosody.hosts[poltergeist_component], leave_presence);
|
215
|
|
- remove_username(room, nick);
|
216
|
|
-end
|
217
|
|
-
|
218
|
|
-function update_poltergeist_occupant_status(room, nick, status, call_details)
|
219
|
|
- local update_presence = get_presence(room, nick);
|
220
|
|
-
|
221
|
|
- if (not update_presence) then
|
222
|
|
- -- TODO: determine if we should provide an error and how that would be
|
223
|
|
- -- handled for bosh and http api.
|
224
|
|
- module:log("info", "update issued for a non-existing poltergeist")
|
225
|
|
- return;
|
226
|
|
- end
|
227
|
|
-
|
228
|
|
- -- update occupant presence with appropriate to and from
|
229
|
|
- -- so we can send it again
|
230
|
|
- update_presence = st.clone(update_presence);
|
231
|
|
- update_presence.attr.to = room.jid.."/"..nick;
|
232
|
|
- update_presence.attr.from = poltergeist_component.."/"..nick;
|
233
|
|
-
|
234
|
|
- update_presence = update_presence_tags(update_presence, status, call_details)
|
235
|
|
-
|
236
|
|
- room:handle_normal_presence(
|
237
|
|
- prosody.hosts[poltergeist_component], update_presence);
|
238
|
|
-end
|
239
|
|
-
|
240
|
|
-function update_presence_tags(presence_stanza, status, call_details)
|
241
|
|
- local call_cancel = false;
|
242
|
|
- local call_id = nil;
|
243
|
|
-
|
244
|
|
- -- Extract optional call flow signal information.
|
245
|
|
- if call_details then
|
246
|
|
- call_id = call_details["id"];
|
247
|
|
-
|
248
|
|
- if call_details["cancel"] then
|
249
|
|
- call_cancel = call_details["cancel"];
|
250
|
|
- end
|
251
|
|
- end
|
252
|
|
-
|
253
|
|
- presence_stanza:maptags(function (tag)
|
254
|
|
- if tag.name == "status" then
|
255
|
|
- if call_cancel then
|
256
|
|
- -- If call cancel is set then the status should not be changed.
|
257
|
|
- return tag
|
258
|
|
- end
|
259
|
|
- return st.stanza("status"):text(status);
|
260
|
|
- elseif tag.name == "call_id" then
|
261
|
|
- if call_id then
|
262
|
|
- return st.stanza("call_id"):text(call_id);
|
263
|
|
- else
|
264
|
|
- -- If no call id is provided the re-use the existing id.
|
265
|
|
- return tag;
|
266
|
|
- end
|
267
|
|
- elseif tag.name == "call_cancel" then
|
268
|
|
- if call_cancel then
|
269
|
|
- return st.stanza("call_cancel"):text("true");
|
270
|
|
- else
|
271
|
|
- return st.stanza("call_cancel"):text("false");
|
272
|
|
- end
|
273
|
|
- end
|
274
|
|
- return tag;
|
275
|
|
- end);
|
276
|
|
-
|
277
|
|
- return presence_stanza
|
278
|
|
-end
|
279
|
|
-
|
280
|
|
-function have_poltergeist_occupant(room, nick)
|
281
|
|
- -- Find out if we have a poltergeist occupant in the room for this JID
|
282
|
|
- return not not room:get_occupant_jid(poltergeist_component.."/"..nick);
|
283
|
|
-end
|
284
|
|
-
|
285
|
|
-function get_presence(room, nick)
|
286
|
|
- local occupant_jid
|
287
|
|
- = room:get_occupant_jid(poltergeist_component.."/"..nick);
|
288
|
|
- if (occupant_jid) then
|
289
|
|
- return room:get_occupant_by_nick(occupant_jid):get_presence();
|
290
|
|
- end
|
291
|
|
-
|
292
|
|
- return nil;
|
293
|
|
-end
|
294
|
|
-
|
295
|
|
-
|
296
|
138
|
--- Note: mod_muc and some of its sub-modules add event handlers between 0 and -100,
|
297
|
139
|
--- e.g. to check for banned users, etc.. Hence adding these handlers at priority -100.
|
298
|
140
|
module:hook("muc-decline", function (event)
|
299
|
|
- remove_poltergeist_occupant(event.room, bare(event.stanza.attr.from), false);
|
|
141
|
+ poltergeist.remove(event.room, bare(event.stanza.attr.from), false);
|
300
|
142
|
end, -100);
|
301
|
143
|
-- before sending the presence for a poltergeist leaving add ignore tag
|
302
|
144
|
-- as poltergeist is leaving just before the real user joins and in the client
|
|
@@ -328,21 +147,21 @@ end, -100);
|
328
|
147
|
module:hook("muc-broadcast-presence", function (event)
|
329
|
148
|
if (bare(event.occupant.jid) == poltergeist_component) then
|
330
|
149
|
if(event.stanza.attr.type == "unavailable"
|
331
|
|
- and poltergeists_pr_ignore[event.occupant.nick]) then
|
|
150
|
+ and poltergeist.should_ignore(event.occupant.nick)) then
|
332
|
151
|
event.stanza:tag(
|
333
|
152
|
"ignore", { xmlns = "http://jitsi.org/jitmeet/" }):up();
|
334
|
|
- poltergeists_pr_ignore[event.occupant.nick] = nil;
|
|
153
|
+ poltergeist.reset_ignored(event.occupant.nick);
|
335
|
154
|
end
|
336
|
155
|
end
|
337
|
156
|
end, -100);
|
338
|
157
|
|
339
|
158
|
-- cleanup room table after room is destroyed
|
340
|
|
-module:hook("muc-room-destroyed",function(event)
|
341
|
|
- local room_name = jid.node(event.room.jid);
|
342
|
|
- if (poltergeists[room_name]) then
|
343
|
|
- poltergeists[room_name] = nil;
|
344
|
|
- end
|
345
|
|
-end);
|
|
159
|
+module:hook(
|
|
160
|
+ "muc-room-destroyed",
|
|
161
|
+ function(event)
|
|
162
|
+ poltergeist.remove_room(event.room);
|
|
163
|
+ end
|
|
164
|
+);
|
346
|
165
|
|
347
|
166
|
--- Handles request for creating/managing poltergeists
|
348
|
167
|
-- @param event the http event, holds the request query
|
|
@@ -375,115 +194,29 @@ function handle_create_poltergeist (event)
|
375
|
194
|
|
376
|
195
|
-- If the poltergiest is already in the conference then it will
|
377
|
196
|
-- be in our username store and another can't be added.
|
378
|
|
- local username = get_username(room, user_id);
|
379
|
|
- if (username ~= nil
|
380
|
|
- and have_poltergeist_occupant(room, string.sub(username, 0, 8))) then
|
381
|
|
- log("warn", "poltergeist for username:%s already in the room:%s",
|
382
|
|
- username, room_name);
|
|
197
|
+ local username = poltergeist.get_username(room, user_id);
|
|
198
|
+ if (username ~=nil and
|
|
199
|
+ poltergeist.occupies(room, poltergeist.create_nick(username))) then
|
|
200
|
+ log("warn",
|
|
201
|
+ "poltergeist for username:%s already in the room:%s",
|
|
202
|
+ username,
|
|
203
|
+ room_name
|
|
204
|
+ );
|
383
|
205
|
return 202;
|
384
|
206
|
end
|
385
|
|
- username = generate_uuid();
|
|
207
|
+
|
386
|
208
|
local context = {
|
387
|
209
|
user = {
|
388
|
|
- id = user_id;
|
|
210
|
+ id = user_id;
|
389
|
211
|
};
|
390
|
212
|
group = group;
|
391
|
213
|
creator_user = session.jitsi_meet_context_user;
|
392
|
214
|
creator_group = session.jitsi_meet_context_group;
|
393
|
215
|
};
|
394
|
|
-
|
395
|
|
- local nick = string.sub(username, 0, 8)
|
396
|
|
- local presence_stanza = original_presence(
|
397
|
|
- poltergeist_component,
|
398
|
|
- room,
|
399
|
|
- nick,
|
400
|
|
- name,
|
401
|
|
- avatar,
|
402
|
|
- username,
|
403
|
|
- context,
|
404
|
|
- status
|
405
|
|
- )
|
406
|
|
- store_username(room, user_id, username);
|
407
|
|
-
|
408
|
|
- room:handle_first_presence(
|
409
|
|
- prosody.hosts[poltergeist_component],
|
410
|
|
- presence_stanza
|
411
|
|
- );
|
412
|
|
-
|
413
|
|
- -- the timeout before removing so participants can see the status update
|
414
|
|
- local removeTimeout = 5;
|
415
|
|
- local timeout = poltergeist_timeout - removeTimeout;
|
416
|
|
-
|
417
|
|
- timer.add_task(timeout,
|
418
|
|
- function ()
|
419
|
|
- update_poltergeist_occupant_status(
|
420
|
|
- room, nick, expired_status);
|
421
|
|
- -- and remove it after some time so participant can see
|
422
|
|
- -- the update
|
423
|
|
- timer.add_task(removeTimeout,
|
424
|
|
- function ()
|
425
|
|
- if (have_poltergeist_occupant(room, nick)) then
|
426
|
|
- remove_poltergeist_occupant(room, nick, false);
|
427
|
|
- end
|
428
|
|
- end);
|
429
|
|
- end);
|
430
|
|
-
|
|
216
|
+ poltergeist.add_to_muc(room, user_id, name, avatar, context, status)
|
431
|
217
|
return 200;
|
432
|
218
|
end
|
433
|
219
|
|
434
|
|
-function original_presence(
|
435
|
|
- component, room, nick, name, avatar, username, context, status)
|
436
|
|
- local p = st.presence({
|
437
|
|
- to = room.jid.."/"..nick,
|
438
|
|
- from = component.."/"..nick,
|
439
|
|
- }):tag("x", { xmlns = MUC_NS }):up();
|
440
|
|
-
|
441
|
|
- p:tag("bot", { type = "poltergeist" }):up();
|
442
|
|
- p:tag("call_cancel"):text(nil):up();
|
443
|
|
- p:tag("call_id"):text(username):up();
|
444
|
|
-
|
445
|
|
- if status then
|
446
|
|
- p:tag("status"):text(status):up();
|
447
|
|
- else
|
448
|
|
- p:tag("status"):text(nil):up();
|
449
|
|
- end
|
450
|
|
-
|
451
|
|
- if (name) then
|
452
|
|
- p:tag(
|
453
|
|
- "nick",
|
454
|
|
- { xmlns = "http://jabber.org/protocol/nick" }):text(name):up();
|
455
|
|
- end
|
456
|
|
-
|
457
|
|
- if (avatar) then
|
458
|
|
- p:tag("avatar-url"):text(avatar):up();
|
459
|
|
- end
|
460
|
|
-
|
461
|
|
- -- If the room has a password set, let the poltergeist enter using it
|
462
|
|
- local room_password = room:get_password();
|
463
|
|
- if room_password then
|
464
|
|
- local join = p:get_child("x", MUC_NS);
|
465
|
|
- join:tag("password", { xmlns = MUC_NS }):text(room_password);
|
466
|
|
- end
|
467
|
|
-
|
468
|
|
- update_presence_identity(
|
469
|
|
- p,
|
470
|
|
- context.user,
|
471
|
|
- context.group,
|
472
|
|
- context.creator_user,
|
473
|
|
- context.creator_group
|
474
|
|
- );
|
475
|
|
- return p
|
476
|
|
-end
|
477
|
|
-
|
478
|
220
|
--- Handles request for updating poltergeists status
|
479
|
221
|
-- @param event the http event, holds the request query
|
480
|
222
|
-- @return GET response, containing a json with response details
|
|
@@ -514,22 +247,22 @@ function handle_update_poltergeist (event)
|
514
|
247
|
return 404;
|
515
|
248
|
end
|
516
|
249
|
|
517
|
|
- local username = get_username(room, user_id);
|
|
250
|
+ local username = poltergeist.get_username(room, user_id);
|
518
|
251
|
if (not username) then
|
519
|
252
|
return 404;
|
520
|
253
|
end
|
521
|
254
|
|
522
|
|
- local call_details = {
|
523
|
|
- ["cancel"] = call_cancel;
|
524
|
|
- ["id"] = call_id;
|
525
|
|
- };
|
|
255
|
+ local call_details = {
|
|
256
|
+ ["cancel"] = call_cancel;
|
|
257
|
+ ["id"] = call_id;
|
|
258
|
+ };
|
526
|
259
|
|
527
|
|
- local nick = string.sub(username, 0, 8);
|
528
|
|
- if (not have_poltergeist_occupant(room, nick)) then
|
|
260
|
+ local nick = poltergeist.create_nick(username);
|
|
261
|
+ if (not poltergeist.occupies(room, nick)) then
|
529
|
262
|
return 404;
|
530
|
263
|
end
|
531
|
264
|
|
532
|
|
- update_poltergeist_occupant_status(room, nick, status, call_details);
|
|
265
|
+ poltergeist.update(room, nick, status, call_details);
|
533
|
266
|
return 200;
|
534
|
267
|
end
|
535
|
268
|
|
|
@@ -556,17 +289,17 @@ function handle_remove_poltergeist (event)
|
556
|
289
|
return 404;
|
557
|
290
|
end
|
558
|
291
|
|
559
|
|
- local username = get_username(room, user_id);
|
|
292
|
+ local username = poltergeist.get_username(room, user_id);
|
560
|
293
|
if (not username) then
|
561
|
294
|
return 404;
|
562
|
295
|
end
|
563
|
296
|
|
564
|
|
- local nick = string.sub(username, 0, 8);
|
565
|
|
- if (not have_poltergeist_occupant(room, nick)) then
|
|
297
|
+ local nick = poltergeist.create_nick(username);
|
|
298
|
+ if (not poltergeist.occupies(room, nick)) then
|
566
|
299
|
return 404;
|
567
|
300
|
end
|
568
|
301
|
|
569
|
|
- remove_poltergeist_occupant(room, nick, false);
|
|
302
|
+ poltergeist.remove(room, nick, false);
|
570
|
303
|
return 200;
|
571
|
304
|
end
|
572
|
305
|
|