Software /
code /
prosody-modules
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 |