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 |