瀏覽代碼

multidomain mapper functionality and examples (#4773)

* first pass at mod_muc_domain open source plus example

* doc - prosody config and config.js examples for mapper
master
Aaron van Meerten 5 年之前
父節點
當前提交
be0950c1ec

+ 14
- 0
doc/example-config-files/multidomain/config.js.multidomain.example 查看文件

@@ -0,0 +1,14 @@
1
+var subdomain = "<!--# echo var="subdomain" default="" -->";
2
+if (subdomain) {
3
+    subdomain = subdomain.substr(0,subdomain.length-1).split('.').join('_').toLowerCase() + '.';
4
+}
5
+
6
+var config = {
7
+    hosts: {
8
+        domain: 'jitsi.example.com',
9
+        muc: 'conference.'+subdomain+'jitsi.example.com', // FIXME: use XEP-0030
10
+        focus: 'focus.jitsi.example.com',
11
+    },
12
+    useNicks: false,
13
+    bosh: '//jitsi.example.com/http-bind' // FIXME: use xep-0156 for that
14
+};

+ 67
- 0
doc/example-config-files/multidomain/jitsi.example.com.multidomain.example 查看文件

@@ -0,0 +1,67 @@
1
+server {
2
+    listen 80;
3
+
4
+    server_name jitsi.example.com;
5
+    # set the root
6
+    root /srv/jitsi.example.com;
7
+    # ssi on with javascript for multidomain variables in config.js
8
+    ssi on;
9
+    ssi_types application/x-javascript application/javascript;
10
+    index index.html;
11
+    set $prefix "";
12
+
13
+
14
+    # BOSH
15
+    location /http-bind {
16
+        proxy_pass      http://localhost:5280/http-bind;
17
+        proxy_set_header X-Forwarded-For $remote_addr;
18
+        proxy_set_header Host $http_host;
19
+    }
20
+
21
+    # xmpp websockets
22
+    location /xmpp-websocket {
23
+        proxy_pass http://localhost:5280/xmpp-websocket;
24
+        proxy_http_version 1.1;
25
+        proxy_set_header Upgrade $http_upgrade;
26
+        proxy_set_header Connection "upgrade";
27
+        proxy_set_header Host $host;
28
+        tcp_nodelay on;
29
+    }
30
+
31
+    location ~ ^/([^/?&:'"]+)$ {
32
+        try_files $uri @root_path;
33
+    }
34
+
35
+    location @root_path {
36
+        rewrite ^/(.*)$ / break;
37
+    }
38
+
39
+    location / {
40
+        ssi on;
41
+    }
42
+
43
+    location ~ ^/([^/?&:'"]+)/config.js$
44
+    {
45
+       set $subdomain "$1.";
46
+       set $subdir "$1/";
47
+
48
+       alias /etc/jitsi/meet/{{jitsi_meet_domain_name}}-config.js;
49
+    }
50
+
51
+    #Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
52
+    location ~ ^/([^/?&:'"]+)/(.*)$ {
53
+        set $subdomain "$1.";
54
+        set $subdir "$1/";
55
+        rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
56
+    }
57
+
58
+    # BOSH for subdomains
59
+    location ~ ^/([^/?&:'"]+)/http-bind {
60
+        set $subdomain "$1.";
61
+        set $subdir "$1/";
62
+        set $prefix "$1";
63
+
64
+        rewrite ^/(.*)$ /http-bind;
65
+    }
66
+
67
+}

+ 220
- 0
doc/example-config-files/multidomain/prosody.cfg.multidomain.example 查看文件

@@ -0,0 +1,220 @@
1
+-- Prosody XMPP Server Configuration
2
+--
3
+-- Information on configuring Prosody can be found on our
4
+-- website at http://prosody.im/doc/configure
5
+--
6
+-- Tip: You can check that the syntax of this file is correct
7
+-- when you have finished by running: prosodyctl check config
8
+-- If there are any errors, it will let you know what and where
9
+-- they are, otherwise it will keep quiet.
10
+--
11
+-- Good luck, and happy Jabbering!
12
+
13
+
14
+---------- Server-wide settings ----------
15
+-- Settings in this section apply to the whole server and are the default settings
16
+-- for any virtual hosts
17
+
18
+-- This is a (by default, empty) list of accounts that are admins
19
+-- for the server. Note that you must create the accounts separately
20
+-- (see http://prosody.im/doc/creating_accounts for info)
21
+-- Example: admins = { "user1@example.com", "user2@example.net" }
22
+admins = { }
23
+daemonize = true
24
+cross_domain_bosh = true;
25
+component_ports = { 5347 }
26
+--component_interface = "192.168.0.10"
27
+
28
+-- Enable use of libevent for better performance under high load
29
+-- For more information see: http://prosody.im/doc/libevent
30
+--use_libevent = true
31
+
32
+-- This is the list of modules Prosody will load on startup.
33
+-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
34
+-- Documentation on modules can be found at: http://prosody.im/doc/modules
35
+modules_enabled = {
36
+
37
+	-- Generally required
38
+		"roster"; -- Allow users to have a roster. Recommended ;)
39
+		"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
40
+		"tls"; -- Add support for secure TLS on c2s/s2s connections
41
+		"dialback"; -- s2s dialback support
42
+		"disco"; -- Service discovery
43
+		"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
44
+
45
+	-- Not essential, but recommended
46
+		"private"; -- Private XML storage (for room bookmarks, etc.)
47
+		"vcard"; -- Allow users to set vCards
48
+
49
+	-- These are commented by default as they have a performance impact
50
+		--"privacy"; -- Support privacy lists
51
+		"compression"; -- Stream compression (requires the lua-zlib package installed)
52
+
53
+	-- Nice to have
54
+		"version"; -- Replies to server version requests
55
+		"uptime"; -- Report how long server has been running
56
+		"time"; -- Let others know the time here on this server
57
+		"ping"; -- Replies to XMPP pings with pongs
58
+		"pep"; -- Enables users to publish their mood, activity, playing music and more
59
+		"register"; -- Allow users to register on this server using a client and change passwords
60
+
61
+	-- Admin interfaces
62
+		"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
63
+		--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
64
+
65
+	-- HTTP modules
66
+		"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
67
+		--"http_files"; -- Serve static files from a directory over HTTP
68
+
69
+	-- Other specific functionality
70
+		--"groups"; -- Shared roster support
71
+		--"announce"; -- Send announcement to all online users
72
+		--"welcome"; -- Welcome users who register accounts
73
+		--"watchregistrations"; -- Alert admins of registrations
74
+		--"motd"; -- Send a message to users when they log in
75
+		--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
76
+	-- jitsi
77
+		"smacks";
78
+		"carbons";
79
+		"mam";
80
+		"lastactivity";
81
+		"offline";
82
+		"pubsub";
83
+		"adhoc";
84
+		"websocket";
85
+		"http_altconnect";
86
+    -- include domain mapper as global level module
87
+        "muc_domain_mapper";
88
+}
89
+
90
+-- domain mapper options, must at least have domain base set to use the mapper
91
+muc_mapper_domain_base = "jitsi.example.com";
92
+
93
+-- These modules are auto-loaded, but should you want
94
+-- to disable them then uncomment them here:
95
+modules_disabled = {
96
+	-- "offline"; -- Store offline messages
97
+	-- "c2s"; -- Handle client connections
98
+	-- "s2s"; -- Handle server-to-server connections
99
+}
100
+
101
+-- Disable account creation by default, for security
102
+-- For more information see http://prosody.im/doc/creating_accounts
103
+allow_registration = false
104
+
105
+-- These are the SSL/TLS-related settings. If you don't want
106
+-- to use SSL/TLS, you may comment or remove this
107
+ssl = {
108
+    key = "/etc/prosody/certs/localhost.key";
109
+    certificate = "/etc/prosody/certs/localhost.crt";
110
+}
111
+
112
+-- Force clients to use encrypted connections? This option will
113
+-- prevent clients from authenticating unless they are using encryption.
114
+
115
+-- c2s_require_encryption = true
116
+
117
+-- Force certificate authentication for server-to-server connections?
118
+-- This provides ideal security, but requires servers you communicate
119
+-- with to support encryption AND present valid, trusted certificates.
120
+-- NOTE: Your version of LuaSec must support certificate verification!
121
+-- For more information see http://prosody.im/doc/s2s#security
122
+
123
+-- s2s_secure_auth = false
124
+
125
+-- Many servers don't support encryption or have invalid or self-signed
126
+-- certificates. You can list domains here that will not be required to
127
+-- authenticate using certificates. They will be authenticated using DNS.
128
+
129
+--s2s_insecure_domains = { "gmail.com" }
130
+
131
+-- Even if you leave s2s_secure_auth disabled, you can still require valid
132
+-- certificates for some domains by specifying a list here.
133
+
134
+--s2s_secure_domains = { "jabber.org" }
135
+
136
+-- Required for init scripts and prosodyctl
137
+pidfile = "/var/run/prosody/prosody.pid"
138
+
139
+-- Select the authentication backend to use. The 'internal' providers
140
+-- use Prosody's configured data storage to store the authentication data.
141
+-- To allow Prosody to offer secure authentication mechanisms to clients, the
142
+-- default provider stores passwords in plaintext. If you do not trust your
143
+-- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed
144
+-- for information about using the hashed backend.
145
+
146
+-- authentication = "internal_plain"
147
+authentication = "internal_hashed"
148
+
149
+-- Select the storage backend to use. By default Prosody uses flat files
150
+-- in its configured data directory, but it also supports more backends
151
+-- through modules. An "sql" backend is included by default, but requires
152
+-- additional dependencies. See http://prosody.im/doc/storage for more info.
153
+
154
+--storage = "sql" -- Default is "internal"
155
+
156
+-- For the "sql" backend, you can uncomment *one* of the below to configure:
157
+--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename.
158
+--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
159
+--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
160
+
161
+-- Logging configuration
162
+-- For advanced logging see http://prosody.im/doc/logging
163
+log = {
164
+	info = "/var/log/prosody/prosody.log"; -- Change 'info' to 'debug' for verbose logging
165
+	error = "/var/log/prosody/prosody.err";
166
+	"*syslog";
167
+}
168
+
169
+----------- Virtual hosts -----------
170
+-- You need to add a VirtualHost entry for each domain you wish Prosody to serve.
171
+-- Settings under each VirtualHost entry apply *only* to that host.
172
+
173
+--VirtualHost "localhost"
174
+
175
+VirtualHost "jitsi.example.com"
176
+	-- enabled = false -- Remove this line to enable this host
177
+	authentication = "anonymous"
178
+	-- Assign this host a certificate for TLS, otherwise it would use the one
179
+	-- set in the global section (if any).
180
+	-- Note that old-style SSL on port 5223 only supports one certificate, and will always
181
+	-- use the global one.
182
+	ssl = {
183
+		key = "/var/lib/prosody/jitsi.example.com.key";
184
+		certificate = "/var/lib/prosody/jitsi.example.com.crt";
185
+	}
186
+
187
+	c2s_require_encryption = false
188
+
189
+VirtualHost "auth.jitsi.example.com"
190
+	ssl = {
191
+		key = "/var/lib/prosody/auth.jitsi.example.com.key";
192
+		certificate = "/var/lib/prosody/auth.jitsi.example.com.crt";
193
+	}
194
+	authentication = "internal_plain"
195
+
196
+------ Components ------
197
+-- You can specify components to add hosts that provide special services,
198
+-- like multi-user conferences, and transports.
199
+-- For more information on components, see http://prosody.im/doc/components
200
+
201
+---Set up a MUC (multi-user chat) room server on conference.example.com:
202
+--Component "conference.example.com" "muc"
203
+
204
+-- Set up a SOCKS5 bytestream proxy for server-proxied file transfers:
205
+--Component "proxy.example.com" "proxy65"
206
+
207
+---Set up an external component (default component port is 5347)
208
+--
209
+-- External components allow adding various services, such as gateways/
210
+-- transports to other networks like ICQ, MSN and Yahoo. For more info
211
+-- see: http://prosody.im/doc/components#adding_an_external_component
212
+--
213
+--Component "gateway.example.com"
214
+--	component_secret = "password"
215
+
216
+Component "conference.jitsi.example.com" "muc"
217
+    modules_enabled = { "muc_domain_mapper" }
218
+
219
+Component "jitsi-videobridge.jitsi.example.com"
220
+    component_secret = "IfGaish6"

+ 159
- 0
resources/prosody-plugins/mod_muc_domain_mapper.lua 查看文件

@@ -0,0 +1,159 @@
1
+-- Maps MUC JIDs like room1@muc.foo.example.com to JIDs like [foo]room1@muc.example.com
2
+-- Must be loaded on the client host in Prosody
3
+
4
+module:set_global();
5
+
6
+-- It is recommended to set muc_mapper_domain_base to the main domain being served (example.com)
7
+
8
+local jid = require "util.jid";
9
+
10
+local filters = require "util.filters";
11
+
12
+local muc_domain_prefix = module:get_option_string("muc_mapper_domain_prefix", "conference");
13
+
14
+local muc_domain_base = module:get_option_string("muc_mapper_domain_base");
15
+if not muc_domain_base then
16
+    module:log("warn", "No 'muc_domain_base' option set, disabling muc_mapper plugin inactive");
17
+    return
18
+end
19
+
20
+-- The "real" MUC domain that we are proxying to
21
+local muc_domain = module:get_option_string("muc_mapper_domain", muc_domain_prefix.."."..muc_domain_base);
22
+
23
+local escaped_muc_domain_base = muc_domain_base:gsub("%p", "%%%1");
24
+local escaped_muc_domain_prefix = muc_domain_prefix:gsub("%p", "%%%1");
25
+-- The pattern used to extract the target subdomain (e.g. extract 'foo' from 'foo.muc.example.com')
26
+local target_subdomain_pattern = "^"..escaped_muc_domain_prefix..".([^%.]+)%."..escaped_muc_domain_base;
27
+
28
+-- table to store all incoming iqs without roomname in it, like discoinfo to the muc compoent
29
+local roomless_iqs = {};
30
+
31
+if not muc_domain then
32
+    module:log("warn", "No 'muc_mapper_domain' option set, disabling muc_mapper plugin inactive");
33
+    return
34
+end
35
+
36
+
37
+-- Utility function to check and convert a room JID from virtual room1@muc.foo.example.com to real [foo]room1@muc.example.com
38
+local function match_rewrite_to_jid(room_jid, stanza)
39
+    local node, host, resource = jid.split(room_jid);
40
+    local target_subdomain = host and host:match(target_subdomain_pattern);
41
+    if not target_subdomain then
42
+        module:log("debug", "No need to rewrite out 'to' %s", room_jid);
43
+        return room_jid;
44
+    end
45
+    -- Ok, rewrite room_jid  address to new format
46
+    local new_node, new_host, new_resource;
47
+    if node then
48
+        new_node, new_host, new_resource = "["..target_subdomain.."]"..node, muc_domain, resource;
49
+    else
50
+        module:log("debug", "No room name provided so rewriting only host 'to' %s", room_jid);
51
+        new_host, new_resource = muc_domain, resource;
52
+
53
+        if (stanza.attr and stanza.attr.id) then
54
+            roomless_iqs[stanza.attr.id] = stanza.attr.to;
55
+        end
56
+    end
57
+    room_jid = jid.join(new_node, new_host, new_resource);
58
+    module:log("debug", "Rewrote to %s", room_jid);
59
+    return room_jid
60
+end
61
+
62
+-- Utility function to check and convert a room JID from real [foo]room1@muc.example.com to virtual room1@muc.foo.example.com
63
+local function match_rewrite_from_jid(room_jid, stanza)
64
+    local node, host, resource = jid.split(room_jid);
65
+    if host ~= muc_domain or not node then
66
+        module:log("debug", "No need to rewrite %s (not from the MUC host) %s, %s", room_jid, stanza.attr.id, roomless_iqs[stanza.attr.id]);
67
+
68
+        if (stanza.attr and stanza.attr.id and roomless_iqs[stanza.attr.id]) then
69
+            local result = roomless_iqs[stanza.attr.id];
70
+            roomless_iqs[stanza.attr.id] = nil;
71
+            return result;
72
+        end
73
+
74
+        return room_jid;
75
+    end
76
+    local target_subdomain, target_node = node:match("^%[([^%]]+)%](.+)$");
77
+    if not (target_node and target_subdomain) then
78
+        module:log("debug", "Not rewriting... unexpected node format: %s", node);
79
+        return room_jid;
80
+    end
81
+    -- Ok, rewrite room_jid address to pretty format
82
+    local new_node, new_host, new_resource = target_node, muc_domain_prefix..".".. target_subdomain.."."..muc_domain_base, resource;
83
+    room_jid = jid.join(new_node, new_host, new_resource);
84
+    module:log("debug", "Rewrote to %s", room_jid);
85
+    return room_jid
86
+end
87
+
88
+
89
+-- We must filter stanzas in order to hook in to all incoming and outgoing messaging which skips the stanza routers
90
+function filter_stanza(stanza)
91
+    if stanza.name == "message" or stanza.name == "iq" or stanza.name == "presence" then
92
+        module:log("debug", "Filtering stanza type %s  to %s from %s",stanza.name,stanza.attr.to,stanza.attr.from);
93
+        if stanza.name == "iq" then
94
+            local conf = stanza:get_child('conference')
95
+            if conf then
96
+                module:log("debug", "Filtering stanza conference %s to %s from %s",conf.attr.room,stanza.attr.to,stanza.attr.from);
97
+                conf.attr.room = match_rewrite_to_jid(conf.attr.room, stanza)
98
+            end
99
+        end
100
+        if stanza.attr.to then
101
+            stanza.attr.to = match_rewrite_to_jid(stanza.attr.to, stanza)
102
+        end
103
+        if stanza.attr.from then
104
+            stanza.attr.from = match_rewrite_from_jid(stanza.attr.from, stanza)
105
+        end
106
+    end
107
+    return stanza;
108
+end
109
+
110
+function filter_session(session)
111
+    module:log("warn", "Session filters applied");
112
+--    filters.add_filter(session, "stanzas/in", filter_stanza_in);
113
+    filters.add_filter(session, "stanzas/out", filter_stanza);
114
+end
115
+
116
+function module.load()
117
+    if module.reloading then
118
+        module:log("debug", "Reloading MUC mapper!");
119
+    else        
120
+        module:log("debug", "First load of MUC mapper!");
121
+    end
122
+    filters.add_filter_hook(filter_session);
123
+end
124
+
125
+function module.unload()
126
+    filters.remove_filter_hook(filter_session); 
127
+end
128
+
129
+
130
+local function outgoing_stanza_rewriter(event)
131
+    local stanza = event.stanza;
132
+    if stanza.attr.to then
133
+        stanza.attr.to = match_rewrite_to_jid(stanza.attr.to, stanza)
134
+    end
135
+end
136
+
137
+local function incoming_stanza_rewriter(event)
138
+    local stanza = event.stanza;
139
+    if stanza.attr.from then
140
+        stanza.attr.from = match_rewrite_from_jid(stanza.attr.from, stanza)
141
+    end
142
+end
143
+
144
+-- The stanza rewriters helper functions are attached for all stanza router hooks
145
+local function hook_all_stanzas(handler, host_module, event_prefix)
146
+    for _, stanza_type in ipairs({ "message", "presence", "iq" }) do
147
+        for _, jid_type in ipairs({ "host", "bare", "full" }) do
148
+            host_module:hook((event_prefix or "")..stanza_type.."/"..jid_type, handler);
149
+        end
150
+    end
151
+end
152
+
153
+
154
+function module.add_host(host_module)
155
+    module:log("info",
156
+               "Loading mod_muc_domain_mapper for host %s!", host_module.host);
157
+    hook_all_stanzas(incoming_stanza_rewriter, host_module);
158
+    hook_all_stanzas(outgoing_stanza_rewriter, host_module, "pre-");
159
+end

Loading…
取消
儲存