浏览代码

Remove the "focus" external component, use client_proxy instead. (#8381)

* feat: Add mod_client_proxy and mod_roster_command.

Taken from prosody-modules 4317:456b9f608f with the
mod_roster_command patch applied.

* feat: Use mod_client_proxy to proxy to jicofo.
master
bgrozev 4 年前
父节点
当前提交
b6f7f8fba7
没有帐户链接到提交者的电子邮件

+ 15
- 0
debian/jitsi-meet-prosody.postinst 查看文件

@@ -142,6 +142,21 @@ case "$1" in
142 142
             echo -e "    admins = { \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\", \"jvb@auth.$JVB_HOSTNAME\" }" >> $PROSODY_HOST_CONFIG
143 143
         fi
144 144
 
145
+        # Convert the old focus component config to the new one.
146
+        # Old:
147
+        # Component "focus.jitmeet.example.com"
148
+        #     component_secret = "focusSecret"
149
+        # New:
150
+        # Component "focus.jitmeet.example.com" "client_proxy"
151
+        #    target_address = "focus@auth.jitmeet.example.com"
152
+        if grep -q "Component \"focus.$JVB_HOSTNAME\"" $PROSODY_HOST_CONFIG && ! grep "Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"" $PROSODY_HOST_CONFIG ;then
153
+            sed -i -e "s/Component \"focus.$JVB_HOSTNAME\"/Component \"focus.$JVB_HOSTNAME\" \"client_proxy\"\n    target_address = \"$JICOFO_AUTH_USER@auth.$JVB_HOSTNAME\"/" $PROSODY_HOST_CONFIG
154
+            PROSODY_CONFIG_PRESENT="false"
155
+        fi
156
+
157
+        # Make sure the focus@auth user's roster includes the proxy component (this is idempotent)
158
+        prosodyctl mod_roster_command subscribe focus.$JVB_HOSTNAME $JICOFO_AUTH_USER@auth.$JVB_HOSTNAME
159
+
145 160
         if [ ! -f /var/lib/prosody/$JVB_HOSTNAME.crt ]; then
146 161
             # prosodyctl takes care for the permissions
147 162
             # echo for using all default values

+ 3
- 2
doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example 查看文件

@@ -77,8 +77,9 @@ Component "internal.auth.jitmeet.example.com" "muc"
77 77
 VirtualHost "auth.jitmeet.example.com"
78 78
     authentication = "internal_plain"
79 79
 
80
-Component "focus.jitmeet.example.com"
81
-    component_secret = "focusSecret"
80
+-- Proxy to jicofo's user JID, so that it doesn't have to register as a component.
81
+Component "focus.jitmeet.example.com" "client_proxy"
82
+    target_address = "focusUser@auth.jitmeet.example.com"
82 83
 
83 84
 Component "speakerstats.jitmeet.example.com" "speakerstats_component"
84 85
     muc_component = "conference.jitmeet.example.com"

+ 202
- 0
resources/prosody-plugins/mod_client_proxy.lua 查看文件

@@ -0,0 +1,202 @@
1
+if module:get_host_type() ~= "component" then
2
+	error("proxy_component should be loaded as component", 0);
3
+end
4
+
5
+local jid_split = require "util.jid".split;
6
+local jid_bare = require "util.jid".bare;
7
+local jid_prep = require "util.jid".prep;
8
+local st = require "util.stanza";
9
+local array = require "util.array";
10
+
11
+local target_address = module:get_option_string("target_address");
12
+
13
+sessions = array{};
14
+local sessions = sessions;
15
+
16
+local function handle_target_presence(stanza)
17
+	local type = stanza.attr.type;
18
+	module:log("debug", "received presence from destination: %s", type)
19
+	local _, _, resource = jid_split(stanza.attr.from);
20
+	if type == "error" then
21
+		-- drop all known sessions
22
+		for k in pairs(sessions) do
23
+			sessions[k] = nil
24
+		end
25
+		module:log(
26
+			"debug",
27
+			"received error presence, dropping all target sessions",
28
+			resource
29
+		)
30
+	elseif type == "unavailable" then
31
+		for k in pairs(sessions) do
32
+			if sessions[k] == resource then
33
+				sessions[k] = nil
34
+				module:log(
35
+					"debug",
36
+					"dropped target session: %s",
37
+					resource
38
+				)
39
+				break
40
+			end
41
+		end
42
+	elseif not type then
43
+		-- available
44
+		local found = false;
45
+		for k in pairs(sessions) do
46
+			if sessions[k] == resource then
47
+				found = true;
48
+				break
49
+			end
50
+		end
51
+		if not found then
52
+			module:log(
53
+				"debug",
54
+				"registered new target session: %s",
55
+				resource
56
+			)
57
+			sessions:push(resource)
58
+		end
59
+	end
60
+end
61
+
62
+local function handle_from_target(stanza)
63
+	local type = stanza.attr.type
64
+	module:log(
65
+		"debug",
66
+		"non-presence stanza from target: name = %s, type = %s",
67
+		stanza.name,
68
+		type
69
+	)
70
+	if stanza.name == "iq" then
71
+		if type == "error" or type == "result" then
72
+			-- de-NAT message
73
+			local _, _, denatted_to_unprepped = jid_split(stanza.attr.to);
74
+			local denatted_to = jid_prep(denatted_to_unprepped);
75
+			if not denatted_to then
76
+				module:log(
77
+					"debug",
78
+					"cannot de-NAT stanza, invalid to: %s",
79
+					denatted_to_unprepped
80
+				)
81
+				return
82
+			end
83
+			local denatted_from = module:get_host();
84
+
85
+			module:log(
86
+				"debug",
87
+				"de-NAT-ed stanza: from: %s -> %s, to: %s -> %s",
88
+				stanza.attr.from,
89
+				denatted_from,
90
+				stanza.attr.to,
91
+				denatted_to
92
+			)
93
+
94
+			stanza.attr.from = denatted_from
95
+			stanza.attr.to = denatted_to
96
+
97
+			module:send(stanza)
98
+		else
99
+			-- FIXME: we don’t support NATing outbund requests atm.
100
+			module:send(st.error_reply(stanza, "cancel", "feature-not-implemented"))
101
+		end
102
+	elseif stanza.name == "message" then
103
+		-- not implemented yet, we need a way to ensure that routing doesn’t
104
+		-- break
105
+		module:send(st.error_reply(stanza, "cancel", "feature-not-implemented"))
106
+	end
107
+end
108
+
109
+local function handle_to_target(stanza)
110
+	local type = stanza.attr.type;
111
+	module:log(
112
+		"debug",
113
+		"stanza to target: name = %s, type = %s",
114
+		stanza.name, type
115
+	)
116
+	if stanza.name == "presence" then
117
+		if type ~= "error" then
118
+			module:send(st.error_reply(stanza, "cancel", "bad-request"))
119
+			return
120
+		end
121
+	elseif stanza.name == "iq" then
122
+		if type == "get" or type == "set" then
123
+			if #sessions == 0 then
124
+				-- no sessions available to send to
125
+				module:log("debug", "no sessions to send to!")
126
+				module:send(st.error_reply(stanza, "cancel", "service-unavailable"))
127
+				return
128
+			end
129
+
130
+			-- find a target session
131
+			local target_session = sessions:random()
132
+			local target = target_address .. "/" .. target_session
133
+
134
+			-- encode sender JID in resource
135
+			local natted_from = module:get_host() .. "/" .. stanza.attr.from;
136
+
137
+			module:log(
138
+				"debug",
139
+				"NAT-ed stanza: from: %s -> %s, to: %s -> %s",
140
+				stanza.attr.from,
141
+				natted_from,
142
+				stanza.attr.to,
143
+				target
144
+			)
145
+
146
+			stanza.attr.from = natted_from
147
+			stanza.attr.to = target
148
+
149
+			module:send(stanza)
150
+		end
151
+		-- FIXME: handle and forward result/error correctly
152
+	elseif stanza.name == "message" then
153
+		-- not implemented yet, we need a way to ensure that routing doesn’t
154
+		-- break
155
+		module:send(st.error_reply(stanza, "cancel", "feature-not-implemented"))
156
+	end
157
+end
158
+
159
+local function stanza_handler(event)
160
+	local origin, stanza = event.origin, event.stanza
161
+	module:log("debug", "received stanza from %s session", origin.type)
162
+
163
+	local bare_from = jid_bare(stanza.attr.from);
164
+	local _, _, to = jid_split(stanza.attr.to);
165
+	if bare_from == target_address then
166
+		-- from our target, to whom?
167
+		if not to then
168
+			-- directly to component
169
+			if stanza.name == "presence" then
170
+				handle_target_presence(stanza)
171
+			else
172
+				module:send(st.error_reply(stanza, "cancel", "bad-request"))
173
+				return true
174
+			end
175
+		else
176
+			-- to someone else
177
+			handle_from_target(stanza)
178
+		end
179
+	else
180
+		handle_to_target(stanza)
181
+	end
182
+	return true
183
+end
184
+
185
+module:hook("iq/bare", stanza_handler, -1);
186
+module:hook("message/bare", stanza_handler, -1);
187
+module:hook("presence/bare", stanza_handler, -1);
188
+module:hook("iq/full", stanza_handler, -1);
189
+module:hook("message/full", stanza_handler, -1);
190
+module:hook("presence/full", stanza_handler, -1);
191
+module:hook("iq/host", stanza_handler, -1);
192
+module:hook("message/host", stanza_handler, -1);
193
+module:hook("presence/host", stanza_handler, -1);
194
+
195
+module:log("debug", "loaded proxy on %s", module:get_host())
196
+
197
+subscription_request = st.presence({
198
+	type = "subscribe",
199
+	to = target_address,
200
+	from = module:get_host()}
201
+)
202
+module:send(subscription_request)

+ 165
- 0
resources/prosody-plugins/mod_roster_command.lua 查看文件

@@ -0,0 +1,165 @@
1
+-----------------------------------------------------------
2
+-- mod_roster_command: Manage rosters through prosodyctl
3
+-- version 0.02
4
+-----------------------------------------------------------
5
+-- Copyright (C) 2011 Matthew Wild
6
+-- Copyright (C) 2011 Adam Nielsen
7
+--
8
+-- This project is MIT/X11 licensed. Please see the
9
+-- COPYING file in the source package for more information.
10
+-----------------------------------------------------------
11
+
12
+if module.host ~= "*" then
13
+	module:log("error", "Do not load this module in Prosody, for correct usage see: https://modules.prosody.im/mod_roster_command.html");
14
+	return;
15
+end
16
+
17
+
18
+-- Workaround for lack of util.startup...
19
+local prosody = _G.prosody;
20
+local hosts = prosody.hosts;
21
+prosody.bare_sessions = prosody.bare_sessions or {};
22
+_G.bare_sessions = _G.bare_sessions or prosody.bare_sessions;
23
+
24
+local usermanager = require "core.usermanager";
25
+local rostermanager = require "core.rostermanager";
26
+local storagemanager = require "core.storagemanager";
27
+local jid = require "util.jid";
28
+local warn = require"util.prosodyctl".show_warning;
29
+
30
+-- Make a *one-way* subscription. User will see when contact is online,
31
+-- contact will not see when user is online.
32
+function subscribe(user_jid, contact_jid)
33
+	local user_username, user_host = jid.split(user_jid);
34
+	local contact_username, contact_host = jid.split(contact_jid);
35
+	if not hosts[user_host] then
36
+		warn("The host '%s' is not configured for this server.", user_host);
37
+		return;
38
+	end
39
+	if hosts[user_host].users.name == "null" then
40
+		storagemanager.initialize_host(user_host);
41
+		usermanager.initialize_host(user_host);
42
+	end
43
+	-- Update user's roster to say subscription request is pending. Bare hosts (e.g. components) don't have rosters.
44
+    if user_username ~= nil then
45
+	    rostermanager.set_contact_pending_out(user_username, user_host, contact_jid);
46
+    end
47
+	if hosts[contact_host] then
48
+		if contact_host ~= user_host and hosts[contact_host].users.name == "null" then
49
+			storagemanager.initialize_host(contact_host);
50
+			usermanager.initialize_host(contact_host);
51
+		end
52
+		-- Update contact's roster to say subscription request is pending...
53
+		rostermanager.set_contact_pending_in(contact_username, contact_host, user_jid);
54
+		-- Update contact's roster to say subscription request approved...
55
+		rostermanager.subscribed(contact_username, contact_host, user_jid);
56
+		-- Update user's roster to say subscription request approved. Bare hosts (e.g. components) don't have rosters.
57
+        if user_username ~= nil then
58
+		    rostermanager.process_inbound_subscription_approval(user_username, user_host, contact_jid);
59
+        end
60
+	end
61
+end
62
+
63
+-- Make a mutual subscription between jid1 and jid2. Each JID will see
64
+-- when the other one is online.
65
+function subscribe_both(jid1, jid2)
66
+	subscribe(jid1, jid2);
67
+	subscribe(jid2, jid1);
68
+end
69
+
70
+-- Unsubscribes user from contact (not contact from user, if subscribed).
71
+function unsubscribe(user_jid, contact_jid)
72
+	local user_username, user_host = jid.split(user_jid);
73
+	local contact_username, contact_host = jid.split(contact_jid);
74
+	if not hosts[user_host] then
75
+		warn("The host '%s' is not configured for this server.", user_host);
76
+		return;
77
+	end
78
+	if hosts[user_host].users.name == "null" then
79
+		storagemanager.initialize_host(user_host);
80
+		usermanager.initialize_host(user_host);
81
+	end
82
+	-- Update user's roster to say subscription is cancelled...
83
+	rostermanager.unsubscribe(user_username, user_host, contact_jid);
84
+	if hosts[contact_host] then
85
+		if contact_host ~= user_host and hosts[contact_host].users.name == "null" then
86
+			storagemanager.initialize_host(contact_host);
87
+			usermanager.initialize_host(contact_host);
88
+		end
89
+		-- Update contact's roster to say subscription is cancelled...
90
+		rostermanager.unsubscribed(contact_username, contact_host, user_jid);
91
+	end
92
+end
93
+
94
+-- Cancel any subscription in either direction.
95
+function unsubscribe_both(jid1, jid2)
96
+	unsubscribe(jid1, jid2);
97
+	unsubscribe(jid2, jid1);
98
+end
99
+
100
+-- Set the name shown and group used in the contact list
101
+function rename(user_jid, contact_jid, contact_nick, contact_group)
102
+	local user_username, user_host = jid.split(user_jid);
103
+	if not hosts[user_host] then
104
+		warn("The host '%s' is not configured for this server.", user_host);
105
+		return;
106
+	end
107
+	if hosts[user_host].users.name == "null" then
108
+		storagemanager.initialize_host(user_host);
109
+		usermanager.initialize_host(user_host);
110
+	end
111
+
112
+	-- Load user's roster and find the contact
113
+	local roster = rostermanager.load_roster(user_username, user_host);
114
+	local item = roster[contact_jid];
115
+	if item then
116
+		if contact_nick then
117
+			item.name = contact_nick;
118
+		end
119
+		if contact_group then
120
+			item.groups = {}; -- Remove from all current groups
121
+			item.groups[contact_group] = true;
122
+		end
123
+		rostermanager.save_roster(user_username, user_host, roster);
124
+	end
125
+end
126
+
127
+function remove(user_jid, contact_jid)
128
+	unsubscribe_both(user_jid, contact_jid);
129
+	local user_username, user_host = jid.split(user_jid);
130
+	local roster = rostermanager.load_roster(user_username, user_host);
131
+	roster[contact_jid] = nil;
132
+	rostermanager.save_roster(user_username, user_host, roster);
133
+end
134
+
135
+function module.command(arg)
136
+	local command = arg[1];
137
+	if not command then
138
+		warn("Valid subcommands: (un)subscribe(_both) | rename");
139
+		return 0;
140
+	end
141
+	table.remove(arg, 1);
142
+	if command == "subscribe" then
143
+		subscribe(arg[1], arg[2]);
144
+		return 0;
145
+	elseif command == "subscribe_both" then
146
+		subscribe_both(arg[1], arg[2]);
147
+		return 0;
148
+	elseif command == "unsubscribe" then
149
+		unsubscribe(arg[1], arg[2]);
150
+		return 0;
151
+	elseif command == "unsubscribe_both" then
152
+		unsubscribe_both(arg[1], arg[2]);
153
+		return 0;
154
+	elseif command == "remove" then
155
+		remove(arg[1], arg[2]);
156
+		return 0;
157
+	elseif command == "rename" then
158
+		rename(arg[1], arg[2], arg[3], arg[4]);
159
+		return 0;
160
+	else
161
+		warn("Unknown command: %s", command);
162
+		return 1;
163
+	end
164
+	return 0;
165
+end

+ 47
- 0
resources/prosody-plugins/mod_roster_command.patch 查看文件

@@ -0,0 +1,47 @@
1
+# HG changeset patch
2
+# User Boris Grozev <boris@jitsi.org>
3
+# Date 1609874100 21600
4
+#      Tue Jan 05 13:15:00 2021 -0600
5
+# Node ID f646babfc401494ff33f2126ef6c4df541ebf846
6
+# Parent  456b9f608fcf9667cfba1bd7bf9eba2151af50d0
7
+mod_roster_command: Fix subscription when the "user JID" is a bare domain.
8
+
9
+Do not attempt to update the roster when the user is bare domain (e.g. a
10
+component), since they don't have rosters and the attempt results in an error:
11
+
12
+$ prosodyctl mod_roster_command subscribe proxy.example.com contact@example.com
13
+xxxxxxxxxxFailed to execute command: Error: /usr/lib/prosody/core/rostermanager.lua:104: attempt to concatenate local 'username' (a nil value)
14
+stack traceback:
15
+	/usr/lib/prosody/core/rostermanager.lua:104: in function 'load_roster'
16
+	/usr/lib/prosody/core/rostermanager.lua:305: in function 'set_contact_pending_out'
17
+	mod_roster_command.lua:44: in function 'subscribe'
18
+
19
+diff -r 456b9f608fcf -r f646babfc401 mod_roster_command/mod_roster_command.lua
20
+--- a/mod_roster_command/mod_roster_command.lua	Tue Jan 05 13:49:50 2021 +0000
21
++++ b/mod_roster_command/mod_roster_command.lua	Tue Jan 05 13:15:00 2021 -0600
22
+@@ -40,8 +40,10 @@
23
+ 		storagemanager.initialize_host(user_host);
24
+ 		usermanager.initialize_host(user_host);
25
+ 	end
26
+-	-- Update user's roster to say subscription request is pending...
27
+-	rostermanager.set_contact_pending_out(user_username, user_host, contact_jid);
28
++	-- Update user's roster to say subscription request is pending. Bare hosts (e.g. components) don't have rosters.
29
++    if user_username ~= nil then
30
++	    rostermanager.set_contact_pending_out(user_username, user_host, contact_jid);
31
++    end
32
+ 	if hosts[contact_host] then
33
+ 		if contact_host ~= user_host and hosts[contact_host].users.name == "null" then
34
+ 			storagemanager.initialize_host(contact_host);
35
+@@ -51,8 +53,10 @@
36
+ 		rostermanager.set_contact_pending_in(contact_username, contact_host, user_jid);
37
+ 		-- Update contact's roster to say subscription request approved...
38
+ 		rostermanager.subscribed(contact_username, contact_host, user_jid);
39
+-		-- Update user's roster to say subscription request approved...
40
+-		rostermanager.process_inbound_subscription_approval(user_username, user_host, contact_jid);
41
++		-- Update user's roster to say subscription request approved. Bare hosts (e.g. components) don't have rosters.
42
++        if user_username ~= nil then
43
++		    rostermanager.process_inbound_subscription_approval(user_username, user_host, contact_jid);
44
++        end
45
+ 	end
46
+ end
47
+ 

正在加载...
取消
保存