Comparison

mod_privilege/mod_privilege.lua @ 1707:64b3d1eb0cfe

mod_privilege: fixed various issues reported by luacheck
author Goffi <goffi@goffi.org>
date Fri, 10 Apr 2015 15:55:44 +0200
parent 1667:c81a981479d4
child 1708:ad7afcf86131
comparison
equal deleted inserted replaced
1670:5f5ff061b316 1707:64b3d1eb0cfe
42 module:log("debug", "Loading privileged entity module "); 42 module:log("debug", "Loading privileged entity module ");
43 43
44 44
45 --> Permissions management <-- 45 --> Permissions management <--
46 46
47 privileges = module:get_option("privileged_entities", {}) 47 local privileges = module:get_option("privileged_entities", {})
48 48
49 function advertise_perm(session, to_jid, perms) 49 local function advertise_perm(session, to_jid, perms)
50 -- send <message/> stanza to advertise permissions 50 -- send <message/> stanza to advertise permissions
51 -- as expained in § 4.2 51 -- as expained in § 4.2
52 local message = st.message({to=to_jid}) 52 local message = st.message({to=to_jid})
53 :tag("privilege", {xmlns=_PRIV_ENT_NS}) 53 :tag("privilege", {xmlns=_PRIV_ENT_NS})
54 54
58 end 58 end
59 end 59 end
60 session.send(message) 60 session.send(message)
61 end 61 end
62 62
63 function set_presence_perm_set(to_jid, perms) 63 local function set_presence_perm_set(to_jid, perms)
64 -- fill the global presence sets according to perms 64 -- fill the global presence sets according to perms
65 if _PRESENCE_MANAGED:contains(perms.presence) then 65 if _PRESENCE_MANAGED:contains(perms.presence) then
66 presence_man_ent:add(to_jid) 66 presence_man_ent:add(to_jid)
67 end 67 end
68 if perms.presence == 'roster' then 68 if perms.presence == 'roster' then
69 presence_roster:add(to_jid) 69 presence_roster:add(to_jid)
70 end 70 end
71 end 71 end
72 72
73 function advertise_presences(session, to_jid, perms) 73 local function advertise_presences(session, to_jid, perms)
74 -- send presence status for already conencted entities 74 -- send presence status for already conencted entities
75 -- as explained in § 7.1 75 -- as explained in § 7.1
76 -- people in roster are probed only for active sessions 76 -- people in roster are probed only for active sessions
77 -- TODO: manage roster load for inactive sessions 77 -- TODO: manage roster load for inactive sessions
78 if not perms.presence then return; end 78 if not perms.presence then return; end
90 90
91 if user_session.roster then 91 if user_session.roster then
92 local bare_jid = jid.bare(user_session.full_jid) 92 local bare_jid = jid.bare(user_session.full_jid)
93 for entity, item in pairs(user_session.roster) do 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 94 if entity~=false and entity~="pending" and (item.subscription=="both" or item.subscription=="to") then
95 _, host = jid.split(entity) 95 local _, host = jid.split(entity)
96 if not hosts[host] then -- we don't probe jid from hosts we manage 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 97 -- using a table with entity as key avoid probing several time the same one
98 to_probe[entity] = bare_jid 98 to_probe[entity] = bare_jid
99 end 99 end
100 end 100 end
102 end 102 end
103 end 103 end
104 end 104 end
105 105
106 -- now we probe peoples for "roster" presence permission 106 -- now we probe peoples for "roster" presence permission
107 for to_jid, from_jid in pairs(to_probe) do 107 for probe_to, probe_from in pairs(to_probe) do
108 module:log("debug", "probing presence for %s (on behalf of %s)", tostring(to_jid), tostring(from_jid)) 108 module:log("debug", "probing presence for %s (on behalf of %s)", tostring(probe_to), tostring(probe_from))
109 local probe = st.presence({from=from_jid, to=to_jid, type="probe"}) 109 local probe = st.presence({from=probe_from, to=probe_to, type="probe"})
110 prosody.core_route_stanza(nil, probe) 110 prosody.core_route_stanza(nil, probe)
111 end 111 end
112 end 112 end
113 113
114 function on_auth(event) 114 local function on_auth(event)
115 -- Check if entity is privileged according to configuration, 115 -- Check if entity is privileged according to configuration,
116 -- and set session.privileges accordingly 116 -- and set session.privileges accordingly
117 117
118 local session = event.session 118 local session = event.session
119 local bare_jid = jid.join(session.username, session.host) 119 local bare_jid = jid.join(session.username, session.host)
136 end 136 end
137 -- extra checks for presence permission 137 -- extra checks for presence permission
138 if ent_priv.permission == 'roster' and not _ROSTER_GET_PERM:contains(session.privileges.roster) then 138 if ent_priv.permission == 'roster' and not _ROSTER_GET_PERM:contains(session.privileges.roster) then
139 module:log("warn", "Can't allow roster presence privilege without roster \"get\" privilege") 139 module:log("warn", "Can't allow roster presence privilege without roster \"get\" privilege")
140 module:log("warn", "Setting presence permission to none") 140 module:log("warn", "Setting presence permission to none")
141 end_priv.permission = nil 141 ent_priv.permission = nil
142 end 142 end
143 143
144 if session.type == "component" then 144 if session.type == "component" then
145 -- we send the message stanza only for component 145 -- we send the message stanza only for component
146 -- it will be sent at first <presence/> for other entities 146 -- it will be sent at first <presence/> for other entities
151 end 151 end
152 152
153 session.privileges = ent_priv 153 session.privileges = ent_priv
154 end 154 end
155 155
156 function on_presence(event) 156 local function on_presence(event)
157 -- Permission are already checked at this point, 157 -- Permission are already checked at this point,
158 -- we only advertise them to the entity 158 -- we only advertise them to the entity
159 local session, stanza = event.origin, event.stanza; 159 local session = event.origin
160 if session.privileges then 160 if session.privileges then
161 advertise_perm(session, session.full_jid, session.privileges) 161 advertise_perm(session, session.full_jid, session.privileges)
162 set_presence_perm_set(session.full_jid, session.privileges) 162 set_presence_perm_set(session.full_jid, session.privileges)
163 advertise_presences(session, session.full_jid, session.privileges) 163 advertise_presences(session, session.full_jid, session.privileges)
164 end 164 end
186 local roster = roster_manager.load_roster(node, host); 186 local roster = roster_manager.load_roster(node, host);
187 187
188 local reply = st.reply(stanza):query("jabber:iq:roster"); 188 local reply = st.reply(stanza):query("jabber:iq:roster");
189 for entity_jid, item in pairs(roster) do 189 for entity_jid, item in pairs(roster) do
190 if entity_jid and entity_jid ~= "pending" then 190 if entity_jid and entity_jid ~= "pending" then
191 local node, host = jid.split(entity_jid); 191 reply:tag("item", {
192 reply:tag("item", { 192 jid = entity_jid,
193 jid = entity_jid, 193 subscription = item.subscription,
194 subscription = item.subscription, 194 ask = item.ask,
195 ask = item.ask, 195 name = item.name,
196 name = item.name, 196 });
197 }); 197 for group in pairs(item.groups) do
198 for group in pairs(item.groups) do 198 reply:tag("group"):text(group):up();
199 reply:tag("group"):text(group):up(); 199 end
200 end 200 reply:up(); -- move out from item
201 reply:up(); -- move out from item
202 end 201 end
203 end 202 end
204 -- end of code adapted from mod_remote_roster 203 -- end of code adapted from mod_remote_roster
205 session.send(reply); 204 session.send(reply);
206 else 205 else
226 if not(user_manager.user_exists(from_node, from_host)) then return; end 225 if not(user_manager.user_exists(from_node, from_host)) then return; end
227 local roster = roster_manager.load_roster(from_node, from_host); 226 local roster = roster_manager.load_roster(from_node, from_host);
228 if not(roster) then return; end 227 if not(roster) then return; end
229 228
230 local query = stanza.tags[1]; 229 local query = stanza.tags[1];
231 for i_, item in ipairs(query.tags) do 230 for _, item in ipairs(query.tags) do
232 if item.name == "item" 231 if item.name == "item"
233 and item.attr.xmlns == "jabber:iq:roster" and item.attr.jid 232 and item.attr.xmlns == "jabber:iq:roster" and item.attr.jid
234 -- Protection against overwriting roster.pending, until we move it 233 -- Protection against overwriting roster.pending, until we move it
235 and item.attr.jid ~= "pending" then 234 and item.attr.jid ~= "pending" then
236 235
237 local item_jid = jid.prep(item.attr.jid); 236 local item_jid = jid.prep(item.attr.jid);
238 local node, host, resource = jid.split(item_jid); 237 local _, host, resource = jid.split(item_jid);
239 if not resource then 238 if not resource then
240 if item_jid ~= stanza.attr.to then -- not self-item_jid 239 if item_jid ~= stanza.attr.to then -- not self-item_jid
241 if item.attr.subscription == "remove" then 240 if item.attr.subscription == "remove" then
242 local r_item = roster[item_jid]; 241 local r_item = roster[item_jid];
243 if r_item then 242 if r_item then
244 local to_bare = node and (node.."@"..host) or host; -- bare jid
245 roster[item_jid] = nil; 243 roster[item_jid] = nil;
246 if roster_manager.save_roster(from_node, from_host, roster) then 244 if roster_manager.save_roster(from_node, from_host, roster) then
247 session.send(st.reply(stanza)); 245 session.send(st.reply(stanza));
248 roster_manager.roster_push(from_node, from_host, item_jid); 246 roster_manager.roster_push(from_node, from_host, item_jid);
249 else 247 else
313 if session.privileges and session.privileges.message=="outgoing" then 311 if session.privileges and session.privileges.message=="outgoing" then
314 if #privilege_elt.tags==1 and privilege_elt.tags[1].name == "forwarded" 312 if #privilege_elt.tags==1 and privilege_elt.tags[1].name == "forwarded"
315 and privilege_elt.tags[1].attr.xmlns==_FORWARDED_NS then 313 and privilege_elt.tags[1].attr.xmlns==_FORWARDED_NS then
316 local message_elt = privilege_elt.tags[1]:get_child('message', 'jabber:client') 314 local message_elt = privilege_elt.tags[1]:get_child('message', 'jabber:client')
317 if message_elt ~= nil then 315 if message_elt ~= nil then
318 local from_node, from_host, from_resource = jid.split(message_elt.attr.from) 316 local _, from_host, from_resource = jid.split(message_elt.attr.from)
319 if from_resource == nil and hosts[from_host] then -- we only accept bare jids from one of the server hosts 317 if from_resource == nil and hosts[from_host] then -- we only accept bare jids from one of the server hosts
320 -- at this point everything should be alright, we can send the message 318 -- at this point everything should be alright, we can send the message
321 prosody.core_route_stanza(nil, message_elt) 319 prosody.core_route_stanza(nil, message_elt)
322 else -- trying to send a message from a forbidden entity 320 else -- trying to send a message from a forbidden entity
323 module:log("warn", "Entity "..tostring(session.full_jid).." try to send a message from "..tostring(message_elt.attr.from)) 321 module:log("warn", "Entity "..tostring(session.full_jid).." try to send a message from "..tostring(message_elt.attr.from))
338 end); 336 end);
339 337
340 338
341 --> presence permission <-- 339 --> presence permission <--
342 340
343 function same_tags(tag1, tag2) 341 local function same_tags(tag1, tag2)
344 -- check if two tags are equivalent 342 -- check if two tags are equivalent
345 343
346 if tag1.name ~= tag2.name then return false; end 344 if tag1.name ~= tag2.name then return false; end
347 345
348 if #tag1 ~= #tag2 then return false; end 346 if #tag1 ~= #tag2 then return false; end
360 end 358 end
361 359
362 return true 360 return true
363 end 361 end
364 362
365 function same_presences(presence1, presence2) 363 local function same_presences(presence1, presence2)
366 -- check that 2 <presence/> stanzas are equivalent (except for "to" attribute) 364 -- check that 2 <presence/> stanzas are equivalent (except for "to" attribute)
367 -- /!\ if the id change but everything else is equivalent, this method return false 365 -- /!\ if the id change but everything else is equivalent, this method return false
368 -- this behaviour may change in the future 366 -- this behaviour may change in the future
369 if presence1.attr.from ~= presence2.attr.from or presence1.attr.id ~= presence2.attr.id 367 if presence1.attr.from ~= presence2.attr.from or presence1.attr.id ~= presence2.attr.id
370 or presence1.attr.type ~= presence2.attr.type then 368 or presence1.attr.type ~= presence2.attr.type then
384 end 382 end
385 383
386 return true 384 return true
387 end 385 end
388 386
389 function forward_presence(presence, to_jid) 387 local function forward_presence(presence, to_jid)
390 presence_fwd = st.clone(presence) 388 local presence_fwd = st.clone(presence)
391 presence_fwd.attr.to = to_jid 389 presence_fwd.attr.to = to_jid
392 module:log("debug", "presence forwarded to "..to_jid..": "..tostring(presence_fwd)) 390 module:log("debug", "presence forwarded to "..to_jid..": "..tostring(presence_fwd))
393 module:send(presence_fwd) 391 module:send(presence_fwd)
394 -- cache used to avoid to send several times the same stanza 392 -- cache used to avoid to send several times the same stanza
395 priv_session.last_presence = presence 393 priv_session.last_presence = presence
396 end 394 end
397 395
398 module:hook("presence/bare", function(event) 396 module:hook("presence/bare", function(event)
399 if presence_man_ent:empty() and presence_roster:empty() then return; end 397 if presence_man_ent:empty() and presence_roster:empty() then return; end
400 398
401 local session, stanza = event.origin, event.stanza; 399 local stanza = event.stanza
402 if stanza.attr.type == nil or stanza.attr.type == "unavailable" then 400 if stanza.attr.type == nil or stanza.attr.type == "unavailable" then
403 if not stanza.attr.to then 401 if not stanza.attr.to then
404 for entity in presence_man_ent:items() do 402 for entity in presence_man_ent:items() do
405 if stanza.attr.from ~= entity then forward_presence(stanza, entity); end 403 if stanza.attr.from ~= entity then forward_presence(stanza, entity); end
406 end 404 end
407 else -- directed presence 405 else -- directed presence
408 -- we ignore directed presences from our own host, as we already have them 406 -- we ignore directed presences from our own host, as we already have them
409 _, from_host = jid.split(stanza.attr.from) 407 local _, from_host = jid.split(stanza.attr.from)
410 if hosts[from_host] then return; end 408 if hosts[from_host] then return; end
411 409
412 -- we don't send several time the same presence, as recommended in §7 #2 410 -- we don't send several time the same presence, as recommended in §7 #2
413 if priv_session.last_presence and same_presences(priv_session.last_presence, stanza) then 411 if priv_session.last_presence and same_presences(priv_session.last_presence, stanza) then
414 return 412 return