annotate mod_http_roster_admin/mod_http_roster_admin.lua @ 2670:6e01878103c0

mod_smacks: Ignore user when writing or reading session_cache on prosody 0.9 At least under some circumstances it seems that session.username is nil when a user tries to resume his session in prosody 0.9. The username is not relevant when no limiting is done (limiting the number of entries in the session cache is only possible in prosody 0.10), so this commit removes the usage of the username when accessing the prosody 0.9 session cache.
author tmolitor <thilo@eightysoft.de>
date Thu, 06 Apr 2017 02:12:14 +0200
parents 2bfa7d476092
children 9d8098f4b652
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
1 -- mod_http_roster_admin
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
2 -- Description: Allow user rosters to be sourced from a remote HTTP API
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
3 --
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
4 -- Version: 1.0
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
5 -- Date: 2015-03-06
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
6 -- Author: Matthew Wild <matthew@prosody.im>
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
7 -- License: MPLv2
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
8 --
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
9 -- Requirements:
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
10 -- Prosody config:
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
11 -- storage = { roster = "memory" }
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
12 -- modules_disabled = { "roster" }
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
13 -- Dependencies:
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
14 -- Prosody 0.9
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
15 -- lua-cjson (Debian/Ubuntu/LuaRocks: lua-cjson)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
16
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
17 local http = require "net.http";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
18 local json = require "cjson";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
19 local it = require "util.iterators";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
20 local set = require "util.set";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
21 local rm = require "core.rostermanager";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
22 local st = require "util.stanza";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
23 local array = require "util.array";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
24
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
25 local host = module.host;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
26 local sessions = hosts[host].sessions;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
27
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
28 local roster_url = module:get_option_string("http_roster_url", "http://localhost/%s");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
29
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
30 -- Send a roster push to the named user, with the given roster, for the specified
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
31 -- contact's roster entry. Used to notify clients of changes/removals.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
32 local function roster_push(username, roster, contact_jid)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
33 local stanza = st.iq({type="set"})
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
34 :tag("query", {xmlns = "jabber:iq:roster" });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
35 local item = roster[contact_jid];
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
36 if item then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
37 stanza:tag("item", {jid = contact_jid, subscription = item.subscription, name = item.name, ask = item.ask});
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
38 for group in pairs(item.groups) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
39 stanza:tag("group"):text(group):up();
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
40 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
41 else
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
42 stanza:tag("item", {jid = contact_jid, subscription = "remove"});
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
43 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
44 stanza:up():up(); -- move out from item
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
45 for _, session in pairs(hosts[host].sessions[username].sessions) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
46 if session.interested then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
47 session.send(stanza);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
48 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
49 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
50 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
51
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
52 -- Send latest presence from the named local user to a contact.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
53 local function send_presence(username, contact_jid, available)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
54 module:log("debug", "Sending %savailable presence from %s to contact %s", (available and "" or "un"), username, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
55 for resource, session in pairs(sessions[username].sessions) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
56 local pres;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
57 if available then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
58 pres = st.clone(session.presence);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
59 pres.attr.to = contact_jid;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
60 else
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
61 pres = st.presence({ to = contact_jid, from = session.full_jid, type = "unavailable" });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
62 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
63 module:send(pres);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
64 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
65 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
66
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
67 -- Converts a 'friend' object from the API to a Prosody roster item object
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
68 local function friend_to_roster_item(friend)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
69 return {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
70 name = friend.name;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
71 subscription = "both";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
72 groups = friend.groups or {};
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
73 };
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
74 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
75
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
76 -- Returns a handler function to consume the data returned from
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
77 -- the API, compare it to the user's current roster, and perform
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
78 -- any actions necessary (roster pushes, presence probes) to
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
79 -- synchronize them.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
80 local function updated_friends_handler(username, cb)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
81 return (function (ok, code, friends)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
82 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
83 cb(false, code);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
84 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
85 local user = sessions[username];
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
86 local roster = user.roster;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
87 local old_contacts = set.new(array.collect(it.keys(roster)));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
88 local new_contacts = set.new(array.collect(it.keys(friends)));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
89
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
90 -- These two entries are not real contacts, ignore them
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
91 old_contacts:remove(false);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
92 old_contacts:remove("pending");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
93
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
94 module:log("debug", "New friends list of %s: %s", username, json.encode(friends));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
95
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
96 -- Calculate which contacts have been added/removed since
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
97 -- the last time we fetched the roster
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
98 local added_contacts = new_contacts - old_contacts;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
99 local removed_contacts = old_contacts - new_contacts;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
100
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
101 local added, removed = 0, 0;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
102
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
103 -- Add new contacts and notify connected clients
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
104 for contact_jid in added_contacts do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
105 module:log("debug", "Processing new friend of %s: %s", username, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
106 roster[contact_jid] = friend_to_roster_item(friends[contact_jid]);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
107 roster_push(username, roster, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
108 send_presence(username, contact_jid, true);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
109 added = added + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
110 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
111
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
112 -- Remove contacts and notify connected clients
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
113 for contact_jid in removed_contacts do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
114 module:log("debug", "Processing removed friend of %s: %s", username, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
115 roster[contact_jid] = nil;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
116 roster_push(username, roster, contact_jid);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
117 send_presence(username, contact_jid, false);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
118 removed = removed + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
119 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
120 module:log("debug", "User %s: added %d new contacts, removed %d contacts", username, added, removed);
2631
2bfa7d476092 mod_http_roster_admin: Don't call callback if it's nil
JC Brand <jc@opkode.com>
parents: 2622
diff changeset
121 if cb ~= nil then
2bfa7d476092 mod_http_roster_admin: Don't call callback if it's nil
JC Brand <jc@opkode.com>
parents: 2622
diff changeset
122 cb(true);
2bfa7d476092 mod_http_roster_admin: Don't call callback if it's nil
JC Brand <jc@opkode.com>
parents: 2622
diff changeset
123 end
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
124 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
125 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
126
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
127 -- Fetch the named user's roster from the API, call callback (cb)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
128 -- with status and result (friends list) when received.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
129 function fetch_roster(username, cb)
2210
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
130 local x = {headers = {}};
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
131 x["headers"]["ACCEPT"] = "application/json, text/plain, */*";
2441
68ebc52222dc Log URL called by http_roster_admin
JC Brand <jc@opkode.com>
parents: 2210
diff changeset
132 module:log("debug", "Fetching roster at URL: %s", roster_url:format(username));
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
133 local ok, err = http.request(
2210
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
134 roster_url:format(username),
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
135 x,
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
136 function (roster_data, code)
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
137 if code ~= 200 then
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
138 module:log("error", "Error fetching roster from %s (code %d): %s", roster_url:format(username), code, tostring(roster_data):sub(1, 40):match("^[^\r\n]+"));
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
139 if code ~= 0 then
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
140 cb(nil, code, roster_data);
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
141 end
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
142 return;
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
143 end
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
144 module:log("debug", "Successfully fetched roster for %s", username);
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
145 module:log("debug", "The roster data is %s", roster_data);
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
146 cb(true, code, json.decode(roster_data));
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
147 end
126d79bf079b mod_http_roster_admin: Also log if the status error is 0 (Connection refused)
JC Brand <jcbrand@minddistrict.com>
parents: 2161
diff changeset
148 );
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
149 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
150 module:log("error", "Failed to connect to roster API at %s: %s", roster_url:format(username), err);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
151 cb(false, 0, err);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
152 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
153 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
154
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
155 -- Fetch the named user's roster from the API, synchronize it with
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
156 -- the user's current roster. Notify callback (cb) with true/false
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
157 -- depending on success or failure.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
158 function refresh_roster(username, cb)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
159 local user = sessions[username];
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
160 if not (user and user.roster) then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
161 module:log("debug", "User's (%q) roster updated, but they are not online - ignoring", username);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
162 cb(true);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
163 return;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
164 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
165 fetch_roster(username, updated_friends_handler(username, cb));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
166 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
167
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
168 --- Roster protocol handling ---
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
169
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
170 -- Build a reply to a "roster get" request
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
171 local function build_roster_reply(stanza, roster_data)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
172 local roster = st.reply(stanza)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
173 :tag("query", { xmlns = "jabber:iq:roster" });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
174
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
175 for jid, item in pairs(roster_data) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
176 if jid and jid ~= "pending" then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
177 roster:tag("item", {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
178 jid = jid,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
179 subscription = item.subscription,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
180 ask = item.ask,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
181 name = item.name,
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
182 });
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
183 for group in pairs(item.groups) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
184 roster:tag("group"):text(group):up();
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
185 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
186 roster:up(); -- move out from item
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
187 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
188 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
189 return roster;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
190 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
191
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
192 -- Handle clients requesting their roster (generally at login)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
193 -- This will not work if mod_roster is loaded (in 0.9).
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
194 module:hook("iq-get/self/jabber:iq:roster:query", function(event)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
195 local session, stanza = event.origin, event.stanza;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
196
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
197 session.interested = true; -- resource is interested in roster updates
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
198
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
199 local roster = session.roster;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
200 if roster[false].downloaded then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
201 return session.send(build_roster_reply(stanza, roster));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
202 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
203
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
204 -- It's possible that we can call this more than once for a new roster
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
205 -- Should happen rarely (multiple clients of the same user request the
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
206 -- roster in the time it takes the API to respond). Currently we just
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
207 -- issue multiple requests, as it's harmless apart from the wasted
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
208 -- requests.
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
209 fetch_roster(session.username, function (ok, code, friends)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
210 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
211 session.send(st.error_reply(stanza, "cancel", "internal-server-error"));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
212 session:close("internal-server-error");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
213 return;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
214 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
215
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
216 -- Are we the first callback to handle the downloaded roster?
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
217 local first = roster[false].downloaded == nil;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
218 if first then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
219 -- Fill out new roster
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
220 for jid, friend in pairs(friends) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
221 roster[jid] = friend_to_roster_item(friend);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
222 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
223 end
2617
7c3a1688e385 Purge the roster from RAM when the user logs off.
JC Brand <jc@opkode.com>
parents: 2441
diff changeset
224
7c3a1688e385 Purge the roster from RAM when the user logs off.
JC Brand <jc@opkode.com>
parents: 2441
diff changeset
225 roster[false].downloaded = true;
2161
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
226
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
227 -- Send full roster to client
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
228 session.send(build_roster_reply(stanza, roster));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
229
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
230 if not first then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
231 -- We already had a roster, make sure to handle any changes...
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
232 updated_friends_handler(session.username, nil)(ok, code, friends);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
233 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
234 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
235
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
236 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
237 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
238
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
239 -- Prevent client from making changes to the roster. This will not
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
240 -- work if mod_roster is loaded (in 0.9).
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
241 module:hook("iq-set/self/jabber:iq:roster:query", function(event)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
242 local session, stanza = event.origin, event.stanza;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
243 return session.send(st.error_reply(stanza, "cancel", "service-unavailable"));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
244 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
245
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
246 --- HTTP endpoint to trigger roster refresh ---
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
247
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
248 -- Handles updating for a single user: GET /roster_admin/refresh/USERNAME
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
249 function handle_refresh_single(event, username)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
250 refresh_roster(username, function (ok, code, err)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
251 event.response.headers["Content-Type"] = "application/json";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
252 event.response:send(json.encode({
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
253 status = ok and "ok" or "error";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
254 message = err or "roster update complete";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
255 }));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
256 end);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
257 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
258 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
259
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
260 -- Handles updating for multiple users: POST /roster_admin/refresh
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
261 -- Payload should be a JSON array of usernames, e.g. ["user1", "user2", "user3"]
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
262 function handle_refresh_multi(event)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
263 local users = json.decode(event.request.body);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
264 if not users then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
265 module:log("warn", "Multi-user refresh attempted with missing/invalid payload");
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
266 event.response:send(400);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
267 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
268 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
269
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
270 local count, count_err = 0, 0;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
271
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
272 local function cb(ok)
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
273 count = count + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
274 if not ok then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
275 count_err = count_err + 1;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
276 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
277
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
278 if count == #users then
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
279 event.response.headers["Content-Type"] = "application/json";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
280 event.response:send(json.encode({
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
281 status = "ok";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
282 message = "roster update complete";
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
283 updated = count - count_err;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
284 errors = count_err;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
285 }));
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
286 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
287 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
288
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
289 for _, username in ipairs(users) do
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
290 refresh_roster(username, cb);
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
291 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
292
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
293 return true;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
294 end
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
295
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
296 module:provides("http", {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
297 route = {
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
298 ["POST /refresh"] = handle_refresh_multi;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
299 ["GET /refresh/*"] = handle_refresh_single;
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
300 };
95a9f2d234da Add mod_http_roster_admin
JC Brand <jc@opkode.com>
parents:
diff changeset
301 });