Browse Source

Merge pull request #1788 from jitsi/module-poltergeist

module-poltergeist
master
Aaron van Meerten 8 years ago
parent
commit
0c446026d6

+ 18
- 5
resources/prosody-plugins/mod_auth_token.lua View File

@@ -23,8 +23,12 @@ module:hook("bosh-session", function(event)
23 23
 	local query = request.url.query;
24 24
 
25 25
 	if query ~= nil then
26
-		session.auth_token = query and formdecode(query).token or nil;
27
-	end
26
+        local params = formdecode(query);
27
+        session.auth_token = query and params.token or nil;
28
+
29
+        -- The room name from the bosh query
30
+        session.jitsi_bosh_query_room = params.room;
31
+    end
28 32
 end);
29 33
 
30 34
 function provider.test_password(username, password)
@@ -54,7 +58,18 @@ end
54 58
 function provider.get_sasl_handler(session)
55 59
 
56 60
 	local function get_username_from_token(self, message)
57
-        return token_util:process_and_verify_token(session);
61
+        local res = token_util:process_and_verify_token(session);
62
+
63
+        local customUsername
64
+            = prosody.events.fire_event("pre-jitsi-authentication", session);
65
+
66
+        if (customUsername) then
67
+            self.username = customUsername;
68
+        else
69
+            self.username = message;
70
+        end
71
+
72
+        return res;
58 73
 	end
59 74
 
60 75
 	return new_sasl(host, { anonymous = get_username_from_token });
@@ -69,8 +84,6 @@ local function anonymous(self, message)
69 84
 	-- This calls the handler created in 'provider.get_sasl_handler(session)'
70 85
 	local result, err, msg = self.profile.anonymous(self, username, self.realm);
71 86
 
72
-	self.username = username;
73
-
74 87
 	if result == true then
75 88
 		return "success";
76 89
 	else

+ 240
- 0
resources/prosody-plugins/mod_muc_poltergeist.lua View File

@@ -0,0 +1,240 @@
1
+local bare = require "util.jid".bare;
2
+local generate_uuid = require "util.uuid".generate;
3
+local jid = require "util.jid";
4
+local neturl = require "net.url";
5
+local parse = neturl.parseQuery;
6
+local st = require "util.stanza";
7
+local get_room_from_jid = module:require "util".get_room_from_jid;
8
+
9
+-- Options
10
+local poltergeist_component
11
+    = module:get_option_string("poltergeist_component", module.host);
12
+
13
+-- table to store all poltergeists we create
14
+local poltergeists = {};
15
+
16
+-- poltergaist management functions
17
+
18
+-- Returns the room if available, work and in multidomain mode
19
+-- @param room_name the name of the room
20
+-- @param group name of the group (optional)
21
+-- @return returns room if found or nil
22
+function get_room(room_name, group)
23
+    local room_address = jid.join(room_name, module:get_host());
24
+    -- if there is a group we are in multidomain mode
25
+    if group and group ~= "" then
26
+        room_address = "["..group.."]"..room_address;
27
+    end
28
+
29
+    return get_room_from_jid(room_address);
30
+end
31
+
32
+-- Stores the username in the table where we store poltergeist usernames
33
+-- based on their room names
34
+-- @param room the room instance
35
+-- @param user_id the user id
36
+-- @param username the username to store
37
+function store_username(room, user_id, username)
38
+    local room_name = jid.node(room.jid);
39
+
40
+    -- we store in poltergeist user ids for room names
41
+    if (not poltergeists[room_name]) then
42
+        poltergeists[room_name] = {};
43
+    end
44
+    poltergeists[room_name][user_id] = username;
45
+    log("debug", "stored in session: %s", username);
46
+end
47
+
48
+-- Retrieve the username for a user
49
+-- @param room the room instance
50
+-- @param user_id the user id
51
+-- @return returns the stored username for user or nil
52
+function get_username(room, user_id)
53
+    local room_name = jid.node(room.jid);
54
+
55
+    if (not poltergeists[room_name]) then
56
+        return nil;
57
+    end
58
+
59
+    return poltergeists[room_name][user_id];
60
+end
61
+
62
+-- if we found that a session for a user with id has a poltergiest already
63
+-- created, retrieve its jid and return it to the authentication
64
+-- so we can reuse it and we that real user will replace the poltergiest
65
+prosody.events.add_handler("pre-jitsi-authentication", function(session)
66
+
67
+    if (session.jitsi_meet_context_user) then
68
+        local room = get_room(
69
+            session.jitsi_bosh_query_room,
70
+            session.jitsi_meet_context_group);
71
+
72
+        if (not room) then
73
+            return nil;
74
+        end
75
+
76
+        local username
77
+            = get_username(room, session.jitsi_meet_context_user["id"]);
78
+
79
+        if (not username) then
80
+            return nil;
81
+        end
82
+
83
+        log("debug", "Found predefined username %s", username);
84
+
85
+        -- let's find the room and if the poltergeist occupant is there
86
+        -- lets remove him before the real participant joins
87
+        -- when we see the unavailable presence to go out the server
88
+        -- we will mark it with ignore tag
89
+        local nick = string.sub(username, 0, 8);
90
+        if (have_poltergeist_occupant(room, nick)) then
91
+            remove_poltergeist_occupant(room, nick);
92
+        end
93
+
94
+        return username;
95
+    end
96
+
97
+    return nil;
98
+end);
99
+
100
+-- Creates poltergeist occupant
101
+-- @param room the room instance where we create the occupant
102
+-- @param nick the nick to use for the new occupant
103
+-- @param name the display name fot the occupant (optional)
104
+-- @param avatar the avatar to use for the new occupant (optional)
105
+function create_poltergeist_occupant(room, nick, name, avatar)
106
+    log("debug", "create_poltergeist_occupant %s:", nick);
107
+    -- Join poltergeist occupant to room, with the invited JID as their nick
108
+    local join_presence = st.presence({
109
+        to = room.jid.."/"..nick,
110
+        from = poltergeist_component.."/"..nick
111
+    }):tag("x", { xmlns = "http://jabber.org/protocol/muc" }):up();
112
+
113
+    if (name) then
114
+        join_presence:tag(
115
+            "nick",
116
+            { xmlns = "http://jabber.org/protocol/nick" }):text(name):up();
117
+    end
118
+    if (avatar) then
119
+        join_presence:tag("avatar-url"):text(avatar):up();
120
+    end
121
+
122
+    room:handle_first_presence(
123
+        prosody.hosts[poltergeist_component], join_presence);
124
+end
125
+
126
+-- Removes poltergeist occupant
127
+-- @param room the room instance where to remove the occupant
128
+-- @param nick the nick of the occupant to remove
129
+function remove_poltergeist_occupant(room, nick)
130
+    log("debug", "remove_poltergeist_occupant %s", nick);
131
+    local leave_presence = st.presence({
132
+        to = room.jid.."/"..nick,
133
+        from = poltergeist_component.."/"..nick,
134
+        type = "unavailable" });
135
+    room:handle_normal_presence(
136
+        prosody.hosts[poltergeist_component], leave_presence);
137
+end
138
+
139
+-- Checks for existance of a poltergeist occupant
140
+-- @param room the room instance where to check for occupant
141
+-- @param nick the nick of the occupant
142
+-- @return true if occupant is found, false otherwise
143
+function have_poltergeist_occupant(room, nick)
144
+	-- Find out if we have a poltergeist occupant in the room for this JID
145
+	return not not room:get_occupant_jid(poltergeist_component.."/"..nick);
146
+end
147
+
148
+-- Event handlers
149
+
150
+--- Note: mod_muc and some of its sub-modules add event handlers between 0 and -100,
151
+--- e.g. to check for banned users, etc.. Hence adding these handlers at priority -100.
152
+module:hook("muc-decline", function (event)
153
+	remove_poltergeist_occupant(event.room, bare(event.stanza.attr.from));
154
+end, -100);
155
+-- before sending the presence for a poltergeist leaving add ignore tag
156
+-- as poltergeist is leaving just before the real user joins and in the client
157
+-- we ignore this presence to avoid leaving/joining experience and the real
158
+-- user will reuse all currently created UI components for the same nick
159
+module:hook("muc-broadcast-presence", function (event)
160
+    if (bare(event.occupant.jid) == poltergeist_component) then
161
+        if(event.stanza.attr.type == "unavailable") then
162
+            event.stanza:tag(
163
+                "ignore", { xmlns = "http://jitsi.org/jitmeet/" }):up();
164
+        end
165
+    end
166
+end, -100);
167
+
168
+--- Handles request for creating/managing poltergeists
169
+-- @param event the http event, holds the request query
170
+-- @return GET response, containing a json with response details
171
+function handle_create_poltergeist (event)
172
+    local params = parse(event.request.url.query);
173
+    local user_id = params["user"];
174
+    local room_name = params["room"];
175
+    local group = params["group"];
176
+    local name = params["name"];
177
+    local avatar = params["avatar"];
178
+
179
+    local room = get_room(room_name, group);
180
+    if (not room) then
181
+        log("error", "no room found %s", room_address);
182
+        return 404;
183
+    end
184
+
185
+    local username = generate_uuid();
186
+    store_username(room, user_id, username)
187
+
188
+    create_poltergeist_occupant(room, string.sub(username,0,8), name, avatar);
189
+
190
+    return 200;
191
+end
192
+
193
+--- Handles request for updating poltergeists status
194
+-- @param event the http event, holds the request query
195
+-- @return GET response, containing a json with response details
196
+function handle_update_poltergeist (event)
197
+    local params = parse(event.request.url.query);
198
+    local user_id = params["user"];
199
+    local room_name = params["room"];
200
+    local group = params["group"];
201
+    local status = params["status"];
202
+
203
+    local room = get_room(room_name, group);
204
+    if (not room) then
205
+        log("error", "no room found %s", room_address);
206
+        return 404;
207
+    end
208
+
209
+    local username = get_username(room, user_id);
210
+    if (not username) then
211
+        return 404;
212
+    end
213
+
214
+    local nick = string.sub(username, 0, 8);
215
+    if (have_poltergeist_occupant(room, nick)) then
216
+        local update_presence = st.presence({
217
+            to = room.jid.."/"..nick,
218
+            from = poltergeist_component.."/"..nick
219
+        }):tag("status"):text(status):up();
220
+
221
+        room:handle_normal_presence(
222
+            prosody.hosts[poltergeist_component], update_presence);
223
+
224
+        return 200;
225
+    else
226
+        return 404;
227
+    end
228
+end
229
+
230
+
231
+log("info", "Loading poltergeist service");
232
+module:depends("http");
233
+module:provides("http", {
234
+    default_path = "/";
235
+    name = "poltergeist";
236
+    route = {
237
+        ["GET /poltergeist/create"] = handle_create_poltergeist;
238
+        ["GET /poltergeist/update"] = handle_update_poltergeist;
239
+    };
240
+});

+ 1
- 18
resources/prosody-plugins/mod_muc_size.lua View File

@@ -19,6 +19,7 @@ local enableTokenVerification
19 19
     = module:get_option_boolean("enable_roomsize_token_verification", false);
20 20
 
21 21
 local token_util = module:require "token/util".new(module);
22
+local get_room_from_jid = module:require "util".get_room_from_jid;
22 23
 
23 24
 -- no token configuration but required
24 25
 if token_util == nil and enableTokenVerification then
@@ -31,26 +32,6 @@ end
31 32
 local muc_domain_prefix
32 33
     = module:get_option_string("muc_mapper_domain_prefix", "conference");
33 34
 
34
---- Finds and returns room by its jid
35
-function get_room_from_jid(room_jid)
36
-	local _, host = jid.split(room_jid);
37
-	local component = hosts[host];
38
-	if component then
39
-		local muc = component.modules.muc
40
-		if muc and rawget(muc,"rooms") then
41
-			-- We're running 0.9.x or 0.10 (old MUC API)
42
-			return muc.rooms[room_jid];
43
-		elseif muc and rawget(muc,"get_room_from_jid") then
44
-			-- We're running >0.10 (new MUC API)
45
-			return muc.get_room_from_jid(room_jid);
46
-		else
47
-			return
48
-		end
49
-	end
50
-end
51
-
52 35
 --- Verifies room name, domain name with the values in the token
53 36
 -- @param token the token we received
54 37
 -- @param room_address the full room address jid

+ 21
- 0
resources/prosody-plugins/mod_poltergeist_component.lua View File

@@ -0,0 +1,21 @@
1
+local st = require "util.stanza";
2
+
3
+-- A component which we use to receive all stanzas for the created poltergeists
4
+-- replays with error if an iq is sent
5
+function no_action()
6
+	return true;
7
+end
8
+
9
+function error_reply(event)
10
+	module:send(st.error_reply(event.stanza, "cancel", "service-unavailable"));
11
+	return true;
12
+end
13
+
14
+module:hook("presence/host", no_action);
15
+module:hook("message/host", no_action);
16
+module:hook("presence/full", no_action);
17
+module:hook("message/full", no_action);
18
+
19
+module:hook("iq/host", error_reply);
20
+module:hook("iq/full", error_reply);
21
+module:hook("iq/bare", error_reply);

+ 25
- 0
resources/prosody-plugins/util.lib.lua View File

@@ -0,0 +1,25 @@
1
+local jid = require "util.jid";
2
+
3
+--- Finds and returns room by its jid
4
+-- @param room_jid the room jid to search in the muc component
5
+-- @return returns room if found or nil
6
+function get_room_from_jid(room_jid)
7
+    local _, host = jid.split(room_jid);
8
+    local component = hosts[host];
9
+    if component then
10
+        local muc = component.modules.muc
11
+        if muc and rawget(muc,"rooms") then
12
+            -- We're running 0.9.x or 0.10 (old MUC API)
13
+            return muc.rooms[room_jid];
14
+        elseif muc and rawget(muc,"get_room_from_jid") then
15
+            -- We're running >0.10 (new MUC API)
16
+            return muc.get_room_from_jid(room_jid);
17
+        else
18
+            return
19
+        end
20
+    end
21
+end
22
+
23
+return {
24
+    get_room_from_jid = get_room_from_jid;
25
+};

Loading…
Cancel
Save