Comparison

plugins/muc/muc.lib.lua @ 10061:5c71693c8345

Merge 0.11->trunk
author Kim Alvefur <zash@zash.se>
date Mon, 08 Jul 2019 02:44:32 +0200
parent 10048:e5532fbdd163
child 10212:a53126b7fe22
comparison
equal deleted inserted replaced
10060:7a36b7ac309b 10061:5c71693c8345
21 local jid_resource = require "util.jid".resource; 21 local jid_resource = require "util.jid".resource;
22 local resourceprep = require "util.encodings".stringprep.resourceprep; 22 local resourceprep = require "util.encodings".stringprep.resourceprep;
23 local st = require "util.stanza"; 23 local st = require "util.stanza";
24 local base64 = require "util.encodings".base64; 24 local base64 = require "util.encodings".base64;
25 local md5 = require "util.hashes".md5; 25 local md5 = require "util.hashes".md5;
26 local new_id = require "util.id".medium;
26 27
27 local log = module._log; 28 local log = module._log;
28 29
29 local occupant_lib = module:require "muc/occupant" 30 local occupant_lib = module:require "muc/occupant"
30 local muc_util = module:require "muc/util"; 31 local muc_util = module:require "muc/util";
37 function room_mt:__tostring() 38 function room_mt:__tostring()
38 return "MUC room ("..self.jid..")"; 39 return "MUC room ("..self.jid..")";
39 end 40 end
40 41
41 function room_mt.save() 42 function room_mt.save()
42 -- overriden by mod_muc.lua 43 -- overridden by mod_muc.lua
43 end 44 end
44 45
45 function room_mt:get_occupant_jid(real_jid) 46 function room_mt:get_occupant_jid(real_jid)
46 return self._jid_nick[real_jid] 47 return self._jid_nick[real_jid]
47 end 48 end
277 self_x = st.clone(x.self or base_x); 278 self_x = st.clone(x.self or base_x);
278 self:build_item_list(occupant, self_x, false, nick, actor_nick, nil, reason); 279 self:build_item_list(occupant, self_x, false, nick, actor_nick, nil, reason);
279 self_p = st.clone(base_presence):add_child(self_x); 280 self_p = st.clone(base_presence):add_child(self_x);
280 end 281 end
281 282
282 -- General populance 283 -- General populace
283 for occupant_nick, n_occupant in self:each_occupant() do 284 for occupant_nick, n_occupant in self:each_occupant() do
284 if occupant_nick ~= occupant.nick then 285 if occupant_nick ~= occupant.nick then
285 local pr; 286 local pr;
286 if can_see_real_jids(whois, n_occupant) then 287 if can_see_real_jids(whois, n_occupant) then
287 pr = get_full_p(); 288 pr = get_full_p();
388 if is_last_session then 389 if is_last_session then
389 x:tag("status", {code = "333"}); 390 x:tag("status", {code = "333"});
390 end 391 end
391 self:publicise_occupant_status(new_occupant or occupant, x); 392 self:publicise_occupant_status(new_occupant or occupant, x);
392 if is_last_session then 393 if is_last_session then
393 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); 394 module:fire_event("muc-occupant-left", {
395 room = self;
396 nick = occupant.nick;
397 occupant = occupant;
398 });
394 end 399 end
395 return true; 400 return true;
396 end 401 end
397 402
398 -- Give the room creator owner affiliation 403 -- Give the room creator owner affiliation
426 return true; 431 return true;
427 end 432 end
428 end, 1); 433 end, 1);
429 434
430 function room_mt:handle_first_presence(origin, stanza) 435 function room_mt:handle_first_presence(origin, stanza)
431 if not stanza:get_child("x", "http://jabber.org/protocol/muc") then
432 module:log("debug", "Room creation without <x>, possibly desynced");
433
434 origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
435 return true;
436 end
437
438 local real_jid = stanza.attr.from; 436 local real_jid = stanza.attr.from;
439 local dest_jid = stanza.attr.to; 437 local dest_jid = stanza.attr.to;
440 local bare_jid = jid_bare(real_jid); 438 local bare_jid = jid_bare(real_jid);
441 if module:fire_event("muc-room-pre-create", { 439 if module:fire_event("muc-room-pre-create", {
442 room = self; 440 room = self;
502 local muc_x = stanza:get_child("x", "http://jabber.org/protocol/muc"); 500 local muc_x = stanza:get_child("x", "http://jabber.org/protocol/muc");
503 501
504 if orig_occupant == nil and not muc_x and stanza.attr.type == nil then 502 if orig_occupant == nil and not muc_x and stanza.attr.type == nil then
505 module:log("debug", "Attempted join without <x>, possibly desynced"); 503 module:log("debug", "Attempted join without <x>, possibly desynced");
506 origin.send(st.error_reply(stanza, "cancel", "item-not-found", 504 origin.send(st.error_reply(stanza, "cancel", "item-not-found",
507 "You must join the room before sending presence updates")); 505 "You are not currently connected to this chat"));
508 return true; 506 return true;
509 end 507 end
510 508
511 local is_first_dest_session; 509 local is_first_dest_session;
512 local dest_occupant; 510 local dest_occupant;
607 -- self:build_item_list(orig_occupant, x, false, dest_nick); 605 -- self:build_item_list(orig_occupant, x, false, dest_nick);
608 add_item(x, self:get_affiliation(bare_jid), orig_occupant.role, real_jid, dest_nick); 606 add_item(x, self:get_affiliation(bare_jid), orig_occupant.role, real_jid, dest_nick);
609 x:tag("status", {code = "303";}):up(); 607 x:tag("status", {code = "303";}):up();
610 x:tag("status", {code = "110";}):up(); 608 x:tag("status", {code = "110";}):up();
611 self:route_stanza(generated_unavail:add_child(x)); 609 self:route_stanza(generated_unavail:add_child(x));
612 dest_nick = nil; -- set dest_nick to nil; so general populance doesn't see it for whole orig_occupant 610 dest_nick = nil; -- set dest_nick to nil; so general populace doesn't see it for whole orig_occupant
613 end 611 end
614 end 612 end
615 613
616 self:save_occupant(orig_occupant); 614 self:save_occupant(orig_occupant);
617 self:publicise_occupant_status(orig_occupant, orig_x, dest_nick); 615 self:publicise_occupant_status(orig_occupant, orig_x, dest_nick);
872 self:save_occupant(occupant); 870 self:save_occupant(occupant);
873 occupants_updated[occupant] = true; 871 occupants_updated[occupant] = true;
874 end 872 end
875 for occupant in pairs(occupants_updated) do 873 for occupant in pairs(occupants_updated) do
876 self:publicise_occupant_status(occupant, x); 874 self:publicise_occupant_status(occupant, x);
877 module:fire_event("muc-occupant-left", { room = self; nick = occupant.nick; occupant = occupant;}); 875 module:fire_event("muc-occupant-left", {
876 room = self;
877 nick = occupant.nick;
878 occupant = occupant;
879 });
878 end 880 end
879 end 881 end
880 882
881 function room_mt:destroy(newjid, reason, password) 883 function room_mt:destroy(newjid, reason, password)
882 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) 884 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"})
965 local item = stanza.tags[1].tags[1]; 967 local item = stanza.tags[1].tags[1];
966 local _aff = item.attr.affiliation; 968 local _aff = item.attr.affiliation;
967 local _aff_rank = valid_affiliations[_aff or "none"]; 969 local _aff_rank = valid_affiliations[_aff or "none"];
968 local _rol = item.attr.role; 970 local _rol = item.attr.role;
969 if _aff and _aff_rank and not _rol then 971 if _aff and _aff_rank and not _rol then
970 -- You need to be at least an admin, and be requesting info about your affifiliation or lower 972 -- You need to be at least an admin, and be requesting info about your affiliation or lower
971 -- e.g. an admin can't ask for a list of owners 973 -- e.g. an admin can't ask for a list of owners
972 local affiliation_rank = valid_affiliations[affiliation or "none"]; 974 local affiliation_rank = valid_affiliations[affiliation or "none"];
973 if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank) 975 if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank)
974 or (self:get_whois() == "anyone") then 976 or (self:get_whois() == "anyone") then
975 local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin"); 977 local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin");
1042 end 1044 end
1043 1045
1044 function room_mt:handle_groupchat_to_room(origin, stanza) 1046 function room_mt:handle_groupchat_to_room(origin, stanza)
1045 local from = stanza.attr.from; 1047 local from = stanza.attr.from;
1046 local occupant = self:get_occupant_by_real_jid(from); 1048 local occupant = self:get_occupant_by_real_jid(from);
1049 if not stanza.attr.id then
1050 stanza.attr.id = new_id()
1051 end
1047 if module:fire_event("muc-occupant-groupchat", { 1052 if module:fire_event("muc-occupant-groupchat", {
1048 room = self; origin = origin; stanza = stanza; from = from; occupant = occupant; 1053 room = self; origin = origin; stanza = stanza; from = from; occupant = occupant;
1049 }) then return true; end 1054 }) then return true; end
1050 stanza.attr.from = occupant.nick; 1055 stanza.attr.from = occupant.nick;
1051 self:broadcast_message(stanza); 1056 self:broadcast_message(stanza);
1290 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 1295 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213
1291 if occupant.bare_jid == jid or ( 1296 if occupant.bare_jid == jid or (
1292 -- Outcast can be by host. 1297 -- Outcast can be by host.
1293 is_host_only and affiliation == "outcast" and select(2, jid_split(occupant.bare_jid)) == host 1298 is_host_only and affiliation == "outcast" and select(2, jid_split(occupant.bare_jid)) == host
1294 ) then 1299 ) then
1295 -- need to publcize in all cases; as affiliation in <item/> has changed. 1300 -- need to publicize in all cases; as affiliation in <item/> has changed.
1296 occupants_updated[occupant] = occupant.role; 1301 occupants_updated[occupant] = occupant.role;
1297 if occupant.role ~= role and ( 1302 if occupant.role ~= role and (
1298 is_downgrade or 1303 is_downgrade or
1299 valid_roles[occupant.role or "none"] < role_rank -- upgrade 1304 valid_roles[occupant.role or "none"] < role_rank -- upgrade
1300 ) then 1305 ) then
1317 1322
1318 if next(occupants_updated) ~= nil then 1323 if next(occupants_updated) ~= nil then
1319 for occupant, old_role in pairs(occupants_updated) do 1324 for occupant, old_role in pairs(occupants_updated) do
1320 self:publicise_occupant_status(occupant, x, nil, actor, reason); 1325 self:publicise_occupant_status(occupant, x, nil, actor, reason);
1321 if occupant.role == nil then 1326 if occupant.role == nil then
1322 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); 1327 module:fire_event("muc-occupant-left", {
1328 room = self;
1329 nick = occupant.nick;
1330 occupant = occupant;
1331 });
1323 elseif is_semi_anonymous and 1332 elseif is_semi_anonymous and
1324 (old_role == "moderator" and occupant.role ~= "moderator") or 1333 (old_role == "moderator" and occupant.role ~= "moderator") or
1325 (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status 1334 (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status
1326 -- Send everyone else's presences (as jid visibility has changed) 1335 -- Send everyone else's presences (as jid visibility has changed)
1327 for real_jid in occupant:each_session() do 1336 for real_jid in occupant:each_session() do
1369 function room_mt:get_role(nick) 1378 function room_mt:get_role(nick)
1370 local occupant = self:get_occupant_by_nick(nick); 1379 local occupant = self:get_occupant_by_nick(nick);
1371 return occupant and occupant.role or nil; 1380 return occupant and occupant.role or nil;
1372 end 1381 end
1373 1382
1383 function room_mt:may_set_role(actor, occupant, role)
1384 local event = {
1385 room = self,
1386 actor = actor,
1387 occupant = occupant,
1388 role = role,
1389 };
1390
1391 module:fire_event("muc-pre-set-role", event);
1392 if event.allowed ~= nil then
1393 return event.allowed, event.error, event.condition;
1394 end
1395
1396 -- Can't do anything to other owners or admins
1397 local occupant_affiliation = self:get_affiliation(occupant.bare_jid);
1398 if occupant_affiliation == "owner" or occupant_affiliation == "admin" then
1399 return nil, "cancel", "not-allowed";
1400 end
1401
1402 -- If you are trying to give or take moderator role you need to be an owner or admin
1403 if occupant.role == "moderator" or role == "moderator" then
1404 local actor_affiliation = self:get_affiliation(actor);
1405 if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then
1406 return nil, "cancel", "not-allowed";
1407 end
1408 end
1409
1410 -- Need to be in the room and a moderator
1411 local actor_occupant = self:get_occupant_by_real_jid(actor);
1412 if not actor_occupant or actor_occupant.role ~= "moderator" then
1413 return nil, "cancel", "not-allowed";
1414 end
1415
1416 return true;
1417 end
1418
1374 function room_mt:set_role(actor, occupant_jid, role, reason) 1419 function room_mt:set_role(actor, occupant_jid, role, reason)
1375 if not actor then return nil, "modify", "not-acceptable"; end 1420 if not actor then return nil, "modify", "not-acceptable"; end
1376 1421
1377 local occupant = self:get_occupant_by_nick(occupant_jid); 1422 local occupant = self:get_occupant_by_nick(occupant_jid);
1378 if not occupant then return nil, "modify", "item-not-found"; end 1423 if not occupant then return nil, "modify", "item-not-found"; end
1383 role = role ~= "none" and role or nil; -- coerces `role == false` to `nil` 1428 role = role ~= "none" and role or nil; -- coerces `role == false` to `nil`
1384 1429
1385 if actor == true then 1430 if actor == true then
1386 actor = nil -- So we can pass it safely to 'publicise_occupant_status' below 1431 actor = nil -- So we can pass it safely to 'publicise_occupant_status' below
1387 else 1432 else
1388 -- Can't do anything to other owners or admins 1433 local allowed, err, condition = self:may_set_role(actor, occupant, role)
1389 local occupant_affiliation = self:get_affiliation(occupant.bare_jid); 1434 if not allowed then
1390 if occupant_affiliation == "owner" or occupant_affiliation == "admin" then 1435 return allowed, err, condition;
1391 return nil, "cancel", "not-allowed";
1392 end
1393
1394 -- If you are trying to give or take moderator role you need to be an owner or admin
1395 if occupant.role == "moderator" or role == "moderator" then
1396 local actor_affiliation = self:get_affiliation(actor);
1397 if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then
1398 return nil, "cancel", "not-allowed";
1399 end
1400 end
1401
1402 -- Need to be in the room and a moderator
1403 local actor_occupant = self:get_occupant_by_real_jid(actor);
1404 if not actor_occupant or actor_occupant.role ~= "moderator" then
1405 return nil, "cancel", "not-allowed";
1406 end 1436 end
1407 end 1437 end
1408 1438
1409 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}); 1439 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"});
1410 if not role then 1440 if not role then
1412 end 1442 end
1413 occupant.role = role; 1443 occupant.role = role;
1414 self:save_occupant(occupant); 1444 self:save_occupant(occupant);
1415 self:publicise_occupant_status(occupant, x, nil, actor, reason); 1445 self:publicise_occupant_status(occupant, x, nil, actor, reason);
1416 if role == nil then 1446 if role == nil then
1417 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); 1447 module:fire_event("muc-occupant-left", {
1448 room = self;
1449 nick = occupant.nick;
1450 occupant = occupant;
1451 });
1418 end 1452 end
1419 return true; 1453 return true;
1420 end 1454 end
1421 1455
1422 local whois = module:require "muc/whois"; 1456 local whois = module:require "muc/whois";