Mercurial > prosody-modules
comparison mod_privilege/mod_privilege.lua @ 1667:c81a981479d4
mod_privilege: implemented probing of rosters items (for existing sessions only) on connection + use a globally shared table for priv_session (and fixed last_presence)
| author | Goffi <goffi@goffi.org> |
|---|---|
| date | Wed, 08 Apr 2015 13:04:04 +0200 |
| parents | 0b1b4b7d5fe0 |
| children | 64b3d1eb0cfe |
comparison
equal
deleted
inserted
replaced
| 1666:0b1b4b7d5fe0 | 1667:c81a981479d4 |
|---|---|
| 1 -- XEP-0356 (Privileged Entity) | 1 -- XEP-0356 (Privileged Entity) |
| 2 -- Copyright (C) 2015 Jérôme Poisson | 2 -- Copyright (C) 2015 Jérôme Poisson |
| 3 -- | 3 -- |
| 4 -- This module is MIT/X11 licensed. Please see the | 4 -- This module is MIT/X11 licensed. Please see the |
| 5 -- COPYING file in the source package for more information. | 5 -- COPYING file in the source package for more information. |
| 6 -- | 6 -- |
| 7 -- Some parts come from mod_remote_roster (module by Waqas Hussain and Kim Alvefur, see https://code.google.com/p/prosody-modules/) | 7 -- Some parts come from mod_remote_roster (module by Waqas Hussain and Kim Alvefur, see https://code.google.com/p/prosody-modules/) |
| 8 | 8 |
| 9 -- TODO: manage external <presence/> (for "roster" presence permission) when the account with the roster is offline | |
| 9 | 10 |
| 10 local jid = require("util/jid") | 11 local jid = require("util/jid") |
| 11 local set = require("util/set") | 12 local set = require("util/set") |
| 12 local st = require("util/stanza") | 13 local st = require("util/stanza") |
| 13 local roster_manager = require("core/rostermanager") | 14 local roster_manager = require("core/rostermanager") |
| 14 local user_manager = require("core/usermanager") | 15 local user_manager = require("core/usermanager") |
| 15 local hosts = prosody.hosts | 16 local hosts = prosody.hosts |
| 16 local full_sessions = prosody.full_sessions; | 17 local full_sessions = prosody.full_sessions; |
| 18 | |
| 19 local priv_session = module:shared("/*/privilege/session") | |
| 20 | |
| 17 -- the folowing sets are used to forward presence stanza | 21 -- the folowing sets are used to forward presence stanza |
| 18 if not prosody._privilege_presence_man_ent then | 22 if not priv_session.presence_man_ent then |
| 19 prosody._privilege_presence_man_ent = set.new() | 23 priv_session.presence_man_ent = set.new() |
| 20 end | 24 end |
| 21 local presence_man_ent = prosody._privilege_presence_man_ent | 25 local presence_man_ent = priv_session.presence_man_ent |
| 22 if not prosody._privilege_presence_roster then | 26 if not priv_session.presence_roster then |
| 23 prosody._privilege_presence_roster = set.new() | 27 priv_session.presence_roster = set.new() |
| 24 end | 28 end |
| 25 local presence_roster = prosody._privilege_presence_roster | 29 local presence_roster = priv_session.presence_roster |
| 26 | 30 |
| 27 local _ALLOWED_ROSTER = set.new({'none', 'get', 'set', 'both'}) | 31 local _ALLOWED_ROSTER = set.new({'none', 'get', 'set', 'both'}) |
| 28 local _ROSTER_GET_PERM = set.new({'get', 'both'}) | 32 local _ROSTER_GET_PERM = set.new({'get', 'both'}) |
| 29 local _ROSTER_SET_PERM = set.new({'set', 'both'}) | 33 local _ROSTER_SET_PERM = set.new({'set', 'both'}) |
| 30 local _ALLOWED_MESSAGE = set.new({'none', 'outgoing'}) | 34 local _ALLOWED_MESSAGE = set.new({'none', 'outgoing'}) |
| 32 local _PRESENCE_MANAGED = set.new({'managed_entity', 'roster'}) | 36 local _PRESENCE_MANAGED = set.new({'managed_entity', 'roster'}) |
| 33 local _TO_CHECK = {roster=_ALLOWED_ROSTER, message=_ALLOWED_MESSAGE, presence=_ALLOWED_PRESENCE} | 37 local _TO_CHECK = {roster=_ALLOWED_ROSTER, message=_ALLOWED_MESSAGE, presence=_ALLOWED_PRESENCE} |
| 34 local _PRIV_ENT_NS = 'urn:xmpp:privilege:1' | 38 local _PRIV_ENT_NS = 'urn:xmpp:privilege:1' |
| 35 local _FORWARDED_NS = 'urn:xmpp:forward:0' | 39 local _FORWARDED_NS = 'urn:xmpp:forward:0' |
| 36 | 40 |
| 37 local last_presence = nil -- cache used to avoid to send several times the same stanza (see § 7 #2) | |
| 38 | |
| 39 | 41 |
| 40 module:log("debug", "Loading privileged entity module "); | 42 module:log("debug", "Loading privileged entity module "); |
| 41 | 43 |
| 42 | 44 |
| 43 --> Permissions management <-- | 45 --> Permissions management <-- |
| 69 end | 71 end |
| 70 | 72 |
| 71 function advertise_presences(session, to_jid, perms) | 73 function advertise_presences(session, to_jid, perms) |
| 72 -- send presence status for already conencted entities | 74 -- send presence status for already conencted entities |
| 73 -- as explained in § 7.1 | 75 -- as explained in § 7.1 |
| 76 -- people in roster are probed only for active sessions | |
| 77 -- TODO: manage roster load for inactive sessions | |
| 78 if not perms.presence then return; end | |
| 79 local to_probe = {} | |
| 74 for _, user_session in pairs(full_sessions) do | 80 for _, user_session in pairs(full_sessions) do |
| 75 if user_session.presence then | 81 if user_session.presence and _PRESENCE_MANAGED:contains(perms.presence) then |
| 76 if _PRESENCE_MANAGED:contains(perms.presence) then | 82 local presence = st.clone(user_session.presence) |
| 77 local presence = st.clone(user_session.presence) | 83 presence.attr.to = to_jid |
| 78 presence.attr.to = to_jid | 84 module:log("debug", "sending current presence for "..tostring(user_session.full_jid)) |
| 79 module:log("debug", "sending current presence for "..tostring(user_session.full_jid)) | 85 session.send(presence) |
| 80 session.send(presence) | 86 end |
| 81 end | 87 if perms.presence == "roster" then |
| 82 end | 88 -- we reset the cache to avoid to miss a presence that just changed |
| 89 priv_session.last_presence = nil | |
| 90 | |
| 91 if user_session.roster then | |
| 92 local bare_jid = jid.bare(user_session.full_jid) | |
| 93 for entity, item in pairs(user_session.roster) do | |
| 94 if entity~=false and entity~="pending" and (item.subscription=="both" or item.subscription=="to") then | |
| 95 _, host = jid.split(entity) | |
| 96 if not hosts[host] then -- we don't probe jid from hosts we manage | |
| 97 -- using a table with entity as key avoid probing several time the same one | |
| 98 to_probe[entity] = bare_jid | |
| 99 end | |
| 100 end | |
| 101 end | |
| 102 end | |
| 103 end | |
| 104 end | |
| 105 | |
| 106 -- now we probe peoples for "roster" presence permission | |
| 107 for to_jid, from_jid in pairs(to_probe) do | |
| 108 module:log("debug", "probing presence for %s (on behalf of %s)", tostring(to_jid), tostring(from_jid)) | |
| 109 local probe = st.presence({from=from_jid, to=to_jid, type="probe"}) | |
| 110 prosody.core_route_stanza(nil, probe) | |
| 83 end | 111 end |
| 84 end | 112 end |
| 85 | 113 |
| 86 function on_auth(event) | 114 function on_auth(event) |
| 87 -- Check if entity is privileged according to configuration, | 115 -- Check if entity is privileged according to configuration, |
| 361 function forward_presence(presence, to_jid) | 389 function forward_presence(presence, to_jid) |
| 362 presence_fwd = st.clone(presence) | 390 presence_fwd = st.clone(presence) |
| 363 presence_fwd.attr.to = to_jid | 391 presence_fwd.attr.to = to_jid |
| 364 module:log("debug", "presence forwarded to "..to_jid..": "..tostring(presence_fwd)) | 392 module:log("debug", "presence forwarded to "..to_jid..": "..tostring(presence_fwd)) |
| 365 module:send(presence_fwd) | 393 module:send(presence_fwd) |
| 366 last_presence = presence -- we keep the presence in cache | 394 -- cache used to avoid to send several times the same stanza |
| 395 priv_session.last_presence = presence | |
| 367 end | 396 end |
| 368 | 397 |
| 369 module:hook("presence/bare", function(event) | 398 module:hook("presence/bare", function(event) |
| 370 if presence_man_ent:empty() and presence_roster:empty() then return; end | 399 if presence_man_ent:empty() and presence_roster:empty() then return; end |
| 371 | 400 |
| 379 -- we ignore directed presences from our own host, as we already have them | 408 -- we ignore directed presences from our own host, as we already have them |
| 380 _, from_host = jid.split(stanza.attr.from) | 409 _, from_host = jid.split(stanza.attr.from) |
| 381 if hosts[from_host] then return; end | 410 if hosts[from_host] then return; end |
| 382 | 411 |
| 383 -- we don't send several time the same presence, as recommended in §7 #2 | 412 -- we don't send several time the same presence, as recommended in §7 #2 |
| 384 if last_presence and same_presences(last_presence, stanza) then | 413 if priv_session.last_presence and same_presences(priv_session.last_presence, stanza) then |
| 385 return | 414 return |
| 386 end | 415 end |
| 387 | 416 |
| 388 for entity in presence_roster:items() do | 417 for entity in presence_roster:items() do |
| 389 if stanza.attr.from ~= entity then forward_presence(stanza, entity); end | 418 if stanza.attr.from ~= entity then forward_presence(stanza, entity); end |
| 390 end | 419 end |
| 391 end | 420 end |
