Restrict creation of rooms

Dear all,

thanks for creating the Jitsi Meet tool. It’s very useful, works well, and it was easy to set up. Unfortunately, authentication seems to be a lot harder to configure the way that I want it than I initially thought.

Basically, I want to continue to use the anonymous login mode that is configured after installation, where anybody can join a conference room if they know the link, but I would like to restrict the list of possible names for conferences rooms. That means anyone who knows the name of an existent chat room (that I will create in advance as an admin) can join without providing login details, but unless they know the name of a chatroom it’s impossible to create a room. This is meant to prevent abuse of our system for purposes not related to our service.

I found out that by setting the restrict_room_creation for Prosody, I can restrict the creation of rooms to admins. Is there a command line tool that I can run to automatically create a chat room and send its name to the users who I would like to invite to join?

Many thanks & best wishes,
Philipp

Hey Philipp and welcome.

The current use of the muc in jitsi-meet was always directed in a way to not keep any state on the xmpp server. A room is created when first accessed and destroyed when the last person leaves. This allows flexibility and scalability. For example, if you need creating rooms and you have multiple as we call them shards, multiple xmpp servers, you will need cluster and you step in very complicated deployments.

But I think you can accomplish this with a simple prosody module, which will catch the event of trying to create a room, will check using a rest call service is the room name allowed and will return an error if not allowed … something like that, the problem in the implementation will be that room creations is not async while the call to a service will be …
Or you can implement this as an authentication provider, as we had done for tokens …
There are multiple approaches based on using a simple prosody module, which will keep scalability and simplicity of deployments.

Dear Damian,

thanks so much for your reply. Your help is very much appreciated.

With the authentication provider, would this require users to sign in or anything similar? I know that my users may be put off by any unnecessary step in using the service, so I want to make usage as simple as feasibly possible. I.e., I would prefer if users could just follow a link and end up in the right video channel.

Regarding the Prosody module, do you think the desired functionality could be accomplished using the MUC Access Control module?

Many thanks again for your support,
All the best wishes,
Philipp

Sorry, I also just found the MUC Restrict Rooms module, maybe that could do the job? I need to find out how to define the allowed chat room names dynamically though. You mentioned something related to rest call services?

Well you can get inspired from that module and from the jwt auth module how it is fetching the public key: https://github.com/jitsi/jitsi-meet/blob/master/resources/prosody-plugins/token/util.lib.lua#L106
and use the same to query for your dynamic values.

Dear all,

just wanted to let you know that I accomplished this by slightly modifying the muc_restrict_room module for Prosody.

I created a new module that compares the muc chatroom name (the bit that goes at the end of a Jitsi Meet URL) with the output of a callable script. Mine is written in bash but I presume it could be anything else. Each line is interpreted as an allowed name. I posted the module (and a bug fix for the original module) to the Prosody maintainers a few weeks ago but haven’t heard back yet.

This is the module (I called it mod_muc_restrict_rooms_exec.lua):

local st = require "util.stanza";
local jid = require "util.jid";
local nodeprep = require "util.encodings".stringprep.nodeprep;

local rooms = module:shared "muc/rooms";
if not rooms then
        module:log("error", "This module only works on MUC components!");
        return;
end

local restrict_patterns = module:get_option("muc_restrict_matching", {});
local restrict_excepts = module:get_option_set("muc_restrict_exceptions", {});
local restrict_allow_admins = module:get_option_boolean("muc_restrict_allow_admins", false);
local restrict_executable = module:get_option_string("muc_restrict_executable", "/bin/false");
local restrict_executable_reason = module:get_option_string("muc_restrict_executable_reason", "Room is not in list of allowed rooms obtained from executable.");

local function is_restricted(room, who)
	-- If admins can join prohibited rooms, we allow them to
	if restrict_allow_admins and usermanager.is_admin(who, module.host) then
		module:log("debug", "Admins are allowed to enter restricted rooms (%s on %s)", who, room)
		return nil;
	end

	-- Don't evaluate exceptions
	if restrict_excepts:contains(room) then
		module:log("debug", "Room %s is amongst restriction exceptions", room)
		return nil;
	end

	-- Evaluate regexps of restricted patterns
        for pattern,reason in pairs(restrict_patterns) do
                if room:match(pattern) then
			module:log("debug", "Room %s is restricted by pattern %s, user %s is not allowed to join (%s)", room, pattern, who, reason)
                        return reason;
                end
        end

        -- Get list of allowed chat rooms from external executable
	local executable = assert(io.popen(restrict_executable, 'r'))
	local output = executable:read('*all')
	executable:close()

        lines = {}
        for s in output:gmatch("[^\r\n]+") do
                table.insert(lines, s)
        end

        for i, token in ipairs(lines) do
                if string.lower(token) == room then
                        return nil
                end
        end

        module:log("debug", "Room %s is not in list of allowed rooms obtained from executable: %s", room, restrict_executable)
        return restrict_executable_reason
end

module:hook("presence/full", function(event)
        local stanza = event.stanza;

        if stanza.name == "presence" and stanza.attr.type == "unavailable" then   -- Leaving events get discarded
                return;
        end

	-- Get the room
	local room = jid.split(stanza.attr.to);
        if not room then return; end

	-- Get who has tried to join it
	local who = jid.bare(stanza.attr.from)

	-- Checking whether room is restricted
	local check_restricted = is_restricted(room, who)
        if check_restricted ~= nil then
                event.allowed = false;
                event.stanza.attr.type = 'error';
	        return event.origin.send(st.error_reply(event.stanza, "cancel", "forbidden", "You're not allowed to enter this room: " .. check_restricted));
        end
end, 10);

On Ubuntu 18.04, this file would have to go under /usr/lib/prosody/modules/.

You will then have to put something similar to this in your Prosody config file for the Jitsi Meet server:

Component "conference.meet.yourdomain.org" "muc"
    storage = "null"
    -- restrict_room_creation = "admin"
    modules_enabled = {"muc_restrict_rooms_exec"}
    muc_restrict_exceptions = { "exception1", "exception2", "exception3" }
    muc_restrict_executable = "/path/to/executable.sh"

where the muc_restrict_exceptions are optional. These would always be allowed, no matter what the output of the script is.

Hope this helps other people as well!

1 Like

Hi!

Please explain that bash script.

Thank you!

As I said, the bash script can be anything. It can also be written in any other language, say Python. Each line is interpreted as a possible name for a chatroom. My script produced chatroom names composed of letters and numbers – I don’t know how it would work if you tried to use special characters. The shell script I used is specific to my use case, so I’m not sure it would help sharing it.

Hi Philipp ,
thank you for the solution it works 100% or maybe 99%
typing the correct room (returned by the script) im able to enter , if the room is not returned by the script i can’t enter but i got the message :
"unfortunately , something went wrong . we’are tryng to fix this. Reconnecting in 24 sec … " this exception message is correct or i miss something ?
thank you