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