mirror of https://github.com/jitsi/jitsi-meet
multidomain mapper functionality and examples (#4773)
* first pass at mod_muc_domain open source plus example * doc - prosody config and config.js examples for mapperpull/4804/head jitsi-meet_4056
parent
6ecd150f75
commit
be0950c1ec
@ -0,0 +1,14 @@ |
||||
var subdomain = "<!--# echo var="subdomain" default="" -->"; |
||||
if (subdomain) { |
||||
subdomain = subdomain.substr(0,subdomain.length-1).split('.').join('_').toLowerCase() + '.'; |
||||
} |
||||
|
||||
var config = { |
||||
hosts: { |
||||
domain: 'jitsi.example.com', |
||||
muc: 'conference.'+subdomain+'jitsi.example.com', // FIXME: use XEP-0030 |
||||
focus: 'focus.jitsi.example.com', |
||||
}, |
||||
useNicks: false, |
||||
bosh: '//jitsi.example.com/http-bind' // FIXME: use xep-0156 for that |
||||
}; |
@ -0,0 +1,67 @@ |
||||
server { |
||||
listen 80; |
||||
|
||||
server_name jitsi.example.com; |
||||
# set the root |
||||
root /srv/jitsi.example.com; |
||||
# ssi on with javascript for multidomain variables in config.js |
||||
ssi on; |
||||
ssi_types application/x-javascript application/javascript; |
||||
index index.html; |
||||
set $prefix ""; |
||||
|
||||
|
||||
# BOSH |
||||
location /http-bind { |
||||
proxy_pass http://localhost:5280/http-bind; |
||||
proxy_set_header X-Forwarded-For $remote_addr; |
||||
proxy_set_header Host $http_host; |
||||
} |
||||
|
||||
# xmpp websockets |
||||
location /xmpp-websocket { |
||||
proxy_pass http://localhost:5280/xmpp-websocket; |
||||
proxy_http_version 1.1; |
||||
proxy_set_header Upgrade $http_upgrade; |
||||
proxy_set_header Connection "upgrade"; |
||||
proxy_set_header Host $host; |
||||
tcp_nodelay on; |
||||
} |
||||
|
||||
location ~ ^/([^/?&:'"]+)$ { |
||||
try_files $uri @root_path; |
||||
} |
||||
|
||||
location @root_path { |
||||
rewrite ^/(.*)$ / break; |
||||
} |
||||
|
||||
location / { |
||||
ssi on; |
||||
} |
||||
|
||||
location ~ ^/([^/?&:'"]+)/config.js$ |
||||
{ |
||||
set $subdomain "$1."; |
||||
set $subdir "$1/"; |
||||
|
||||
alias /etc/jitsi/meet/{{jitsi_meet_domain_name}}-config.js; |
||||
} |
||||
|
||||
#Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to / |
||||
location ~ ^/([^/?&:'"]+)/(.*)$ { |
||||
set $subdomain "$1."; |
||||
set $subdir "$1/"; |
||||
rewrite ^/([^/?&:'"]+)/(.*)$ /$2; |
||||
} |
||||
|
||||
# BOSH for subdomains |
||||
location ~ ^/([^/?&:'"]+)/http-bind { |
||||
set $subdomain "$1."; |
||||
set $subdir "$1/"; |
||||
set $prefix "$1"; |
||||
|
||||
rewrite ^/(.*)$ /http-bind; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,220 @@ |
||||
-- Prosody XMPP Server Configuration |
||||
-- |
||||
-- Information on configuring Prosody can be found on our |
||||
-- website at http://prosody.im/doc/configure |
||||
-- |
||||
-- Tip: You can check that the syntax of this file is correct |
||||
-- when you have finished by running: prosodyctl check config |
||||
-- If there are any errors, it will let you know what and where |
||||
-- they are, otherwise it will keep quiet. |
||||
-- |
||||
-- Good luck, and happy Jabbering! |
||||
|
||||
|
||||
---------- Server-wide settings ---------- |
||||
-- Settings in this section apply to the whole server and are the default settings |
||||
-- for any virtual hosts |
||||
|
||||
-- This is a (by default, empty) list of accounts that are admins |
||||
-- for the server. Note that you must create the accounts separately |
||||
-- (see http://prosody.im/doc/creating_accounts for info) |
||||
-- Example: admins = { "user1@example.com", "user2@example.net" } |
||||
admins = { } |
||||
daemonize = true |
||||
cross_domain_bosh = true; |
||||
component_ports = { 5347 } |
||||
--component_interface = "192.168.0.10" |
||||
|
||||
-- Enable use of libevent for better performance under high load |
||||
-- For more information see: http://prosody.im/doc/libevent |
||||
--use_libevent = true |
||||
|
||||
-- This is the list of modules Prosody will load on startup. |
||||
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too. |
||||
-- Documentation on modules can be found at: http://prosody.im/doc/modules |
||||
modules_enabled = { |
||||
|
||||
-- Generally required |
||||
"roster"; -- Allow users to have a roster. Recommended ;) |
||||
"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. |
||||
"tls"; -- Add support for secure TLS on c2s/s2s connections |
||||
"dialback"; -- s2s dialback support |
||||
"disco"; -- Service discovery |
||||
"posix"; -- POSIX functionality, sends server to background, enables syslog, etc. |
||||
|
||||
-- Not essential, but recommended |
||||
"private"; -- Private XML storage (for room bookmarks, etc.) |
||||
"vcard"; -- Allow users to set vCards |
||||
|
||||
-- These are commented by default as they have a performance impact |
||||
--"privacy"; -- Support privacy lists |
||||
"compression"; -- Stream compression (requires the lua-zlib package installed) |
||||
|
||||
-- Nice to have |
||||
"version"; -- Replies to server version requests |
||||
"uptime"; -- Report how long server has been running |
||||
"time"; -- Let others know the time here on this server |
||||
"ping"; -- Replies to XMPP pings with pongs |
||||
"pep"; -- Enables users to publish their mood, activity, playing music and more |
||||
"register"; -- Allow users to register on this server using a client and change passwords |
||||
|
||||
-- Admin interfaces |
||||
"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands |
||||
--"admin_telnet"; -- Opens telnet console interface on localhost port 5582 |
||||
|
||||
-- HTTP modules |
||||
"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" |
||||
--"http_files"; -- Serve static files from a directory over HTTP |
||||
|
||||
-- Other specific functionality |
||||
--"groups"; -- Shared roster support |
||||
--"announce"; -- Send announcement to all online users |
||||
--"welcome"; -- Welcome users who register accounts |
||||
--"watchregistrations"; -- Alert admins of registrations |
||||
--"motd"; -- Send a message to users when they log in |
||||
--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. |
||||
-- jitsi |
||||
"smacks"; |
||||
"carbons"; |
||||
"mam"; |
||||
"lastactivity"; |
||||
"offline"; |
||||
"pubsub"; |
||||
"adhoc"; |
||||
"websocket"; |
||||
"http_altconnect"; |
||||
-- include domain mapper as global level module |
||||
"muc_domain_mapper"; |
||||
} |
||||
|
||||
-- domain mapper options, must at least have domain base set to use the mapper |
||||
muc_mapper_domain_base = "jitsi.example.com"; |
||||
|
||||
-- These modules are auto-loaded, but should you want |
||||
-- to disable them then uncomment them here: |
||||
modules_disabled = { |
||||
-- "offline"; -- Store offline messages |
||||
-- "c2s"; -- Handle client connections |
||||
-- "s2s"; -- Handle server-to-server connections |
||||
} |
||||
|
||||
-- Disable account creation by default, for security |
||||
-- For more information see http://prosody.im/doc/creating_accounts |
||||
allow_registration = false |
||||
|
||||
-- These are the SSL/TLS-related settings. If you don't want |
||||
-- to use SSL/TLS, you may comment or remove this |
||||
ssl = { |
||||
key = "/etc/prosody/certs/localhost.key"; |
||||
certificate = "/etc/prosody/certs/localhost.crt"; |
||||
} |
||||
|
||||
-- Force clients to use encrypted connections? This option will |
||||
-- prevent clients from authenticating unless they are using encryption. |
||||
|
||||
-- c2s_require_encryption = true |
||||
|
||||
-- Force certificate authentication for server-to-server connections? |
||||
-- This provides ideal security, but requires servers you communicate |
||||
-- with to support encryption AND present valid, trusted certificates. |
||||
-- NOTE: Your version of LuaSec must support certificate verification! |
||||
-- For more information see http://prosody.im/doc/s2s#security |
||||
|
||||
-- s2s_secure_auth = false |
||||
|
||||
-- Many servers don't support encryption or have invalid or self-signed |
||||
-- certificates. You can list domains here that will not be required to |
||||
-- authenticate using certificates. They will be authenticated using DNS. |
||||
|
||||
--s2s_insecure_domains = { "gmail.com" } |
||||
|
||||
-- Even if you leave s2s_secure_auth disabled, you can still require valid |
||||
-- certificates for some domains by specifying a list here. |
||||
|
||||
--s2s_secure_domains = { "jabber.org" } |
||||
|
||||
-- Required for init scripts and prosodyctl |
||||
pidfile = "/var/run/prosody/prosody.pid" |
||||
|
||||
-- Select the authentication backend to use. The 'internal' providers |
||||
-- use Prosody's configured data storage to store the authentication data. |
||||
-- To allow Prosody to offer secure authentication mechanisms to clients, the |
||||
-- default provider stores passwords in plaintext. If you do not trust your |
||||
-- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed |
||||
-- for information about using the hashed backend. |
||||
|
||||
-- authentication = "internal_plain" |
||||
authentication = "internal_hashed" |
||||
|
||||
-- Select the storage backend to use. By default Prosody uses flat files |
||||
-- in its configured data directory, but it also supports more backends |
||||
-- through modules. An "sql" backend is included by default, but requires |
||||
-- additional dependencies. See http://prosody.im/doc/storage for more info. |
||||
|
||||
--storage = "sql" -- Default is "internal" |
||||
|
||||
-- For the "sql" backend, you can uncomment *one* of the below to configure: |
||||
--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename. |
||||
--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } |
||||
--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" } |
||||
|
||||
-- Logging configuration |
||||
-- For advanced logging see http://prosody.im/doc/logging |
||||
log = { |
||||
info = "/var/log/prosody/prosody.log"; -- Change 'info' to 'debug' for verbose logging |
||||
error = "/var/log/prosody/prosody.err"; |
||||
"*syslog"; |
||||
} |
||||
|
||||
----------- Virtual hosts ----------- |
||||
-- You need to add a VirtualHost entry for each domain you wish Prosody to serve. |
||||
-- Settings under each VirtualHost entry apply *only* to that host. |
||||
|
||||
--VirtualHost "localhost" |
||||
|
||||
VirtualHost "jitsi.example.com" |
||||
-- enabled = false -- Remove this line to enable this host |
||||
authentication = "anonymous" |
||||
-- Assign this host a certificate for TLS, otherwise it would use the one |
||||
-- set in the global section (if any). |
||||
-- Note that old-style SSL on port 5223 only supports one certificate, and will always |
||||
-- use the global one. |
||||
ssl = { |
||||
key = "/var/lib/prosody/jitsi.example.com.key"; |
||||
certificate = "/var/lib/prosody/jitsi.example.com.crt"; |
||||
} |
||||
|
||||
c2s_require_encryption = false |
||||
|
||||
VirtualHost "auth.jitsi.example.com" |
||||
ssl = { |
||||
key = "/var/lib/prosody/auth.jitsi.example.com.key"; |
||||
certificate = "/var/lib/prosody/auth.jitsi.example.com.crt"; |
||||
} |
||||
authentication = "internal_plain" |
||||
|
||||
------ Components ------ |
||||
-- You can specify components to add hosts that provide special services, |
||||
-- like multi-user conferences, and transports. |
||||
-- For more information on components, see http://prosody.im/doc/components |
||||
|
||||
---Set up a MUC (multi-user chat) room server on conference.example.com: |
||||
--Component "conference.example.com" "muc" |
||||
|
||||
-- Set up a SOCKS5 bytestream proxy for server-proxied file transfers: |
||||
--Component "proxy.example.com" "proxy65" |
||||
|
||||
---Set up an external component (default component port is 5347) |
||||
-- |
||||
-- External components allow adding various services, such as gateways/ |
||||
-- transports to other networks like ICQ, MSN and Yahoo. For more info |
||||
-- see: http://prosody.im/doc/components#adding_an_external_component |
||||
-- |
||||
--Component "gateway.example.com" |
||||
-- component_secret = "password" |
||||
|
||||
Component "conference.jitsi.example.com" "muc" |
||||
modules_enabled = { "muc_domain_mapper" } |
||||
|
||||
Component "jitsi-videobridge.jitsi.example.com" |
||||
component_secret = "IfGaish6" |
@ -0,0 +1,159 @@ |
||||
-- Maps MUC JIDs like room1@muc.foo.example.com to JIDs like [foo]room1@muc.example.com |
||||
-- Must be loaded on the client host in Prosody |
||||
|
||||
module:set_global(); |
||||
|
||||
-- It is recommended to set muc_mapper_domain_base to the main domain being served (example.com) |
||||
|
||||
local jid = require "util.jid"; |
||||
|
||||
local filters = require "util.filters"; |
||||
|
||||
local muc_domain_prefix = module:get_option_string("muc_mapper_domain_prefix", "conference"); |
||||
|
||||
local muc_domain_base = module:get_option_string("muc_mapper_domain_base"); |
||||
if not muc_domain_base then |
||||
module:log("warn", "No 'muc_domain_base' option set, disabling muc_mapper plugin inactive"); |
||||
return |
||||
end |
||||
|
||||
-- The "real" MUC domain that we are proxying to |
||||
local muc_domain = module:get_option_string("muc_mapper_domain", muc_domain_prefix.."."..muc_domain_base); |
||||
|
||||
local escaped_muc_domain_base = muc_domain_base:gsub("%p", "%%%1"); |
||||
local escaped_muc_domain_prefix = muc_domain_prefix:gsub("%p", "%%%1"); |
||||
-- The pattern used to extract the target subdomain (e.g. extract 'foo' from 'foo.muc.example.com') |
||||
local target_subdomain_pattern = "^"..escaped_muc_domain_prefix..".([^%.]+)%."..escaped_muc_domain_base; |
||||
|
||||
-- table to store all incoming iqs without roomname in it, like discoinfo to the muc compoent |
||||
local roomless_iqs = {}; |
||||
|
||||
if not muc_domain then |
||||
module:log("warn", "No 'muc_mapper_domain' option set, disabling muc_mapper plugin inactive"); |
||||
return |
||||
end |
||||
|
||||
|
||||
-- Utility function to check and convert a room JID from virtual room1@muc.foo.example.com to real [foo]room1@muc.example.com |
||||
local function match_rewrite_to_jid(room_jid, stanza) |
||||
local node, host, resource = jid.split(room_jid); |
||||
local target_subdomain = host and host:match(target_subdomain_pattern); |
||||
if not target_subdomain then |
||||
module:log("debug", "No need to rewrite out 'to' %s", room_jid); |
||||
return room_jid; |
||||
end |
||||
-- Ok, rewrite room_jid address to new format |
||||
local new_node, new_host, new_resource; |
||||
if node then |
||||
new_node, new_host, new_resource = "["..target_subdomain.."]"..node, muc_domain, resource; |
||||
else |
||||
module:log("debug", "No room name provided so rewriting only host 'to' %s", room_jid); |
||||
new_host, new_resource = muc_domain, resource; |
||||
|
||||
if (stanza.attr and stanza.attr.id) then |
||||
roomless_iqs[stanza.attr.id] = stanza.attr.to; |
||||
end |
||||
end |
||||
room_jid = jid.join(new_node, new_host, new_resource); |
||||
module:log("debug", "Rewrote to %s", room_jid); |
||||
return room_jid |
||||
end |
||||
|
||||
-- Utility function to check and convert a room JID from real [foo]room1@muc.example.com to virtual room1@muc.foo.example.com |
||||
local function match_rewrite_from_jid(room_jid, stanza) |
||||
local node, host, resource = jid.split(room_jid); |
||||
if host ~= muc_domain or not node then |
||||
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]); |
||||
|
||||
if (stanza.attr and stanza.attr.id and roomless_iqs[stanza.attr.id]) then |
||||
local result = roomless_iqs[stanza.attr.id]; |
||||
roomless_iqs[stanza.attr.id] = nil; |
||||
return result; |
||||
end |
||||
|
||||
return room_jid; |
||||
end |
||||
local target_subdomain, target_node = node:match("^%[([^%]]+)%](.+)$"); |
||||
if not (target_node and target_subdomain) then |
||||
module:log("debug", "Not rewriting... unexpected node format: %s", node); |
||||
return room_jid; |
||||
end |
||||
-- Ok, rewrite room_jid address to pretty format |
||||
local new_node, new_host, new_resource = target_node, muc_domain_prefix..".".. target_subdomain.."."..muc_domain_base, resource; |
||||
room_jid = jid.join(new_node, new_host, new_resource); |
||||
module:log("debug", "Rewrote to %s", room_jid); |
||||
return room_jid |
||||
end |
||||
|
||||
|
||||
-- We must filter stanzas in order to hook in to all incoming and outgoing messaging which skips the stanza routers |
||||
function filter_stanza(stanza) |
||||
if stanza.name == "message" or stanza.name == "iq" or stanza.name == "presence" then |
||||
module:log("debug", "Filtering stanza type %s to %s from %s",stanza.name,stanza.attr.to,stanza.attr.from); |
||||
if stanza.name == "iq" then |
||||
local conf = stanza:get_child('conference') |
||||
if conf then |
||||
module:log("debug", "Filtering stanza conference %s to %s from %s",conf.attr.room,stanza.attr.to,stanza.attr.from); |
||||
conf.attr.room = match_rewrite_to_jid(conf.attr.room, stanza) |
||||
end |
||||
end |
||||
if stanza.attr.to then |
||||
stanza.attr.to = match_rewrite_to_jid(stanza.attr.to, stanza) |
||||
end |
||||
if stanza.attr.from then |
||||
stanza.attr.from = match_rewrite_from_jid(stanza.attr.from, stanza) |
||||
end |
||||
end |
||||
return stanza; |
||||
end |
||||
|
||||
function filter_session(session) |
||||
module:log("warn", "Session filters applied"); |
||||
-- filters.add_filter(session, "stanzas/in", filter_stanza_in); |
||||
filters.add_filter(session, "stanzas/out", filter_stanza); |
||||
end |
||||
|
||||
function module.load() |
||||
if module.reloading then |
||||
module:log("debug", "Reloading MUC mapper!"); |
||||
else |
||||
module:log("debug", "First load of MUC mapper!"); |
||||
end |
||||
filters.add_filter_hook(filter_session); |
||||
end |
||||
|
||||
function module.unload() |
||||
filters.remove_filter_hook(filter_session); |
||||
end |
||||
|
||||
|
||||
local function outgoing_stanza_rewriter(event) |
||||
local stanza = event.stanza; |
||||
if stanza.attr.to then |
||||
stanza.attr.to = match_rewrite_to_jid(stanza.attr.to, stanza) |
||||
end |
||||
end |
||||
|
||||
local function incoming_stanza_rewriter(event) |
||||
local stanza = event.stanza; |
||||
if stanza.attr.from then |
||||
stanza.attr.from = match_rewrite_from_jid(stanza.attr.from, stanza) |
||||
end |
||||
end |
||||
|
||||
-- The stanza rewriters helper functions are attached for all stanza router hooks |
||||
local function hook_all_stanzas(handler, host_module, event_prefix) |
||||
for _, stanza_type in ipairs({ "message", "presence", "iq" }) do |
||||
for _, jid_type in ipairs({ "host", "bare", "full" }) do |
||||
host_module:hook((event_prefix or "")..stanza_type.."/"..jid_type, handler); |
||||
end |
||||
end |
||||
end |
||||
|
||||
|
||||
function module.add_host(host_module) |
||||
module:log("info", |
||||
"Loading mod_muc_domain_mapper for host %s!", host_module.host); |
||||
hook_all_stanzas(incoming_stanza_rewriter, host_module); |
||||
hook_all_stanzas(outgoing_stanza_rewriter, host_module, "pre-"); |
||||
end |
Loading…
Reference in new issue