Persistent Passwords on Self Hosted Rooms

Do you see an error in the client’s js console?

Here are the errors that prosody 0.11 appears to generate

XML Parsing Error: mismatched tag. Expected: .
Location: https://domain. com/http-bind?room=test
Line Number 6, Column 3: http-bind:6:3
[JitsiMeetJS.js] : UnhandledError: null Script: null Line: null Column: null StackTrace: Error: “Strophe: request id 1.1 error 502 happened”
log strophe.util.js:89
error strophe.js:2083
_onRequestStateChange strophe.js:5569
Logger.js:125:17
i Logger.js:125
getGlobalOnErrorHandler JitsiMeetJS.js:548
onerror middleware.js:100
callErrorHandler GlobalOnErrorHandler.js:61
log strophe.util.js:89
error strophe.js:2083
_onRequestStateChange strophe.js:5569
[modules/xmpp/strophe.util.js] <t.a/i.Strophe.log>: Strophe: request id 1.1 error 502 happened Logger.js:125:17
[modules/xmpp/strophe.util.js] <t.a/i.Strophe.log>: Strophe: request errored, status: 502, number of errors: 1 Logger.js:125:17
XML Parsing Error: mismatched tag. Expected: .
Location: https://domain. com/http-bind?room=test
Line Number 6, Column 3: http-bind:6:3
[JitsiMeetJS.js] : UnhandledError: null Script: null Line: null Column: null StackTrace: Error: “Strophe: request id 2.2 error 502 happened”
log strophe.util.js:89
error strophe.js:2083
_onRequestStateChange strophe.js:5569
Logger.js:125:17
i Logger.js:125
getGlobalOnErrorHandler JitsiMeetJS.js:548
onerror middleware.js:100
callErrorHandler GlobalOnErrorHandler.js:61
log strophe.util.js:89
error strophe.js:2083
_onRequestStateChange strophe.js:5569
[modules/xmpp/strophe.util.js] <t.a/i.Strophe.log>: Strophe: request id 2.2 error 502 happened Logger.js:125:17
[modules/xmpp/strophe.util.js] <t.a/i.Strophe.log>: Strophe: request errored, status: 502, number of errors: 2

Etc. etc. etc.

[modules/xmpp/strophe.util.js] <t.a/i.Strophe.log>: Strophe: request id 4.4 error 502 happened Logger.js:125:17
i Logger.js:125
log strophe.util.js:90
error strophe.js:2083
_onRequestStateChange strophe.js:5569
[modules/xmpp/strophe.util.js] <t.a/i.Strophe.log>: Strophe: request errored, status: 502, number of errors: 4 Logger.js:125:17
[modules/xmpp/xmpp.js] : (TIME) Strophe connfail[giving-up]: 37839 Logger.js:125:17
[modules/statistics/statistics.js] <b.sendAnalyticsAndLog>: {“type”:“operational”,“action”:“connection.failed”,“attributes”:{“error_type”:“connection.otherError”,“error_message”:“giving-up”}} Logger.js:125:17

Hi Damencho,
i have tried both options:

  • Installed prosody 0.11, set muc_room_default_persistent=true
    I set a password, left the call and je-joined. Prosody will crash.

  • for the second option i think i also need prosody 0.11. In prosody 0.10 i do not find where the event muc-room-pre-create ist fired. I have no lua knowledge, but syntax is not accepted

            local pass = http.query.for.password for this event.room;
    modulemanager   error   Unable to load module 'muc_room_pre_crea
    te/mod_muc_room_pre_create': ...ules/mod_muc_room_pre_create/mod_muc_room_pre_cr
    eate.lua:3: <name> expected near 'for'

Joachim

1 Like

I think there just needs to be more documentation on the different use cases for authentication.

It’s weird that the Jitsi Devs are using a set up they wont document publicly.

The ‘secure domain’ set up is very specific. A more common set up is groups who may be given admin or user access to particular rooms. Why no set up for this documented is strange.

Hopefully we can one out soon.

2 Likes

Hello Damencho,
can you tell about were to configure the hook for muc-room-pre-create? I enabled to module at the Component “conference.***” “muc” but couln’t succeed. As far I can see the additional module is called by the hook but afterwards the password is reset to nil in password.lib.lua (the same hook).

Kind regards,
Martin

Hi,

I was looking for a solution to a similar problem and could not get this done using persistent rooms nor with the muc-room-pre-create hook. However, using the muc-room-created hook seems to work.

Here is what I came up with (sorry if thats horrible code, first time that I use Lua):

local store = module:open_store("persistent_muc_passwds", "map");
if not store then
    module:log("error","Failed to open storage.");
    return nil;
end

module:hook("muc-room-destroyed", function (event)
    local room = event.room;
    local password = room:get_password(room);

    if password then
        module:log("debug", "Room %s with pass %s about to be destroyed", room, password);
        if not store then
                module:log("debug","failed to open store on destroy");
            return nil;
        end
        
        local now = os.time();
        store:set(room.jid, "last_used", now);
        store:set(room.jid, "password" , password);
        module:log("debug", "Stored %s, %s for room %s", password, now, room);
    elseif store:get(room.jid, "password") then
	    -- moderator removed old password from restored room, delete stored entry
        store:set(room.jid, "last_used", nil);
        store:set(room.jid, "password" , nil);
        module:log("debug", "Deleted stored entries for room %s", room);
    end

    return nil; -- can be removed
end, 0);

module:hook("muc-room-created", function (event)    
    local room = event.room;
    module:log("debug","hooked room create for %s", room);

    local old_pass = store:get(room.jid, "password");
    if not old_pass then
        module:log("debug", "No password to restore for room %s", room);
	return nil;
    end

    module:log("debug", "Loaded old password '%s' for room %s", old_pass, room);
    local last_used = store:get(room.jid, "last_used");
    if not last_used then
        module:log("debug", "No stored timestamp found for room %s. Removing stored entry.", room, err);
        store:set(room.jid, "last_used", nil);
        store:set(room.jid, "password" , nil);
	return nil;
    end

    if is_room_stale(last_used) then
        -- delete entry
        store:set(room.jid, "last_used", nil);
        store:set(room.jid, "password" , nil);
	module:log("debug", "deleted password for stale room %s", room); 
	return nil;
    end

    -- restore old pass for the mucroom
    local success = room:set_password(old_pass);
    if not success then 
        module:log("warn", "Failed to set old password %s for restored room %s.", old_pass, room);
    end
    
    module:log("debug", "Set password '%s' for restored room %s.", old_pass, room);
    return nil;
end, 0);

function is_room_stale(last_used)
    local days = module:get_option_number("days_to_persist_muc_passwds", 30);
    module:log("debug", "Function is_stale() called with '%s', days is set to %s", last_used, days);
    local daysfrom = os.difftime(os.time(), last_used) / (24 * 60 * 60); 
    local roomage = math.floor(daysfrom) ;
    module:log("debug", "roomage is %s days", roomage);
    if roomage then
        return roomage > days; 
    end
    return false;
end

Save this as mod_persist_muc_passwords.lua in the modules directory and add the module to the muc’s list of enabled modules. You should also change the storage for this module to something persistent (instead of “memory”). My muc config looks like this:

Component "muc.meet.jitsi" "muc"
    --storage = "internal";
    default_storage = "memory";
    storage =  {
	    persistent_muc_passwds = "internal";
    }
    days_to_persist_muc_passwds = 7;
    modules_enabled = {
            "persist_muc_passwords";  
    }

Tested with Prosody Version: 0.11.2-1~bpo9+1 in the docker-jitsi-meet setup.

I am aware of several problems with this approach:

  • passwords are stored in plaintext
  • whoever restores the old room will be moderator and can change or remove the password
  • does not work with authentication/securedomain EDIT: apparently this works also with authentication, my config was wrong when I tested this.

Maybe somebody who has more experience with prosody, jitsi and the Lua language can help to improve this module in this regards…

9 Likes

Hi plotka,

tnx very much, this is what i looked for!

Here i have Ubuntu 19.10 / prosody 0.11.2-1
Your solution is working here together with authentification (secure domain).
Passwords are stored in files like /var/lib/prosody/conference%2emeet%2eexample%2eorg/persistent_muc_passwds/confname%40conference%2emeet%2eexample%2eorg.dat

Joachim

Hi!

Cannot get the snippet working, the ‘success’ is always nil. Please could you help out?

-- /usr/lib/prosody/modules/
module:hook("muc-room-created", function (event)
    local room = event.room;
    module:log("debug", "hooked room create for %s", tostring(room));

    local pass = randPW(8);
    local success = room:set_password(pass);

    if not success then
        module:log("warn", "Failed to set password '%s' for %s.", pass, tostring(room));
    end
    
    module:log("debug", "Set password '%s' for %s.", pass, tostring(room));
    return nil;
end, 0);

-- https://rosettacode.org/wiki/Password_generator#Lua
function randPW (length)
    local index, pw, rnd = 0, ""
    local chars = {
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
        "abcdefghijklmnopqrstuvwxyz",
        "0123456789"
    }
    repeat
        index = index + 1
        rnd = math.random(chars[index]:len())
        if math.random(2) == 1 then
            pw = pw .. chars[index]:sub(rnd, rnd)
        else
            pw = chars[index]:sub(rnd, rnd) .. pw
        end
        index = index % #chars
    until pw:len() >= length
    return pw
end


Prosody 0.9.10

# Prosody directories
Data directory:         /var/lib/prosody
Plugin directory:       /usr/share/jitsi-meet/prosody-plugins/;/usr/lib/prosody/modules/
Config directory:       /etc/prosody
Source directory:       /usr/lib/prosody

# Lua environment
Lua version:                    Lua 5.1

Lua module search paths:
  /usr/lib/prosody/?.lua
  /usr/local/share/lua/5.1/?.lua
  /usr/local/share/lua/5.1/?/init.lua
  /usr/local/lib/lua/5.1/?.lua
  /usr/local/lib/lua/5.1/?/init.lua
  /usr/share/lua/5.1/?.lua
  /usr/share/lua/5.1/?/init.lua

Lua C module search paths:
  /usr/lib/prosody/?.so
  /usr/local/lib/lua/5.1/?.so
  /usr/lib/x86_64-linux-gnu/lua/5.1/?.so
  /usr/lib/lua/5.1/?.so
  /usr/local/lib/lua/5.1/loadall.so

LuaRocks:               Not installed

# Lua module versions
lfs:            LuaFileSystem 1.6.3
lxp:            LuaExpat 1.3.0
pposix:         0.3.6
socket:         LuaSocket 3.0-rc1
ssl:            0.5.1
1 Like

That method never returns in prosody 0.9 https://github.com/bjc/prosody/blob/0.9.14/plugins/muc/muc.lib.lua#L296
While in 0.11 it returns https://github.com/bjc/prosody/blob/0.11/plugins/muc/password.lib.lua#L16

1 Like

@damencho Thanks, Damian!

module:hook("muc-room-created", function (event)
    local room = event.room;
    module:log("debug", "hooked room create for %s", tostring(room));
    local pass = tostring(randPW(8));
    local res = room:set_password(pass);
    module:log("info", "Set password '%s' for %s.", pass, tostring(room));
    return res;
end, 0);

However the hook is constantly repeated, the password is not set and in the logs I can see multiple set password events.
Please could you give a hint on what Im doing wrong?
Thanks, very much appreciated.

I believe I had some trouble when returning anything else but nil, so your return res; statement could be a problem. However, as mentioned before, I do not really know Lua, nor the prosody API.

Still the same…

-- For Prosody 0.9 /usr/lib/prosody/modules/
module:hook("muc-room-created", function (event)
    local room = event.room;
    module:log("debug", "hooked room create for %s", tostring(room));
    local pass = tostring(randPW(8));
    local res = room:set_password(pass);
    module:log("info", "Set password '%s' for %s.", pass, tostring(room));
    return nil;
end, 0);

@damencho Damian, maybe you can help?

Did you try the muc-room-pre-create hook? Did not work for me on prosody 0.11 because jicofo failed to join the room but this may be different when using prosody 0.9.

Well, you need to let jicofo in the room, as jicofo is the first one to join normally.

Well, you need to let jicofo in the room, as jicofo is the first one to join normally.

Yes, thats why I switched to using the muc-room-created hook, to set the password only after jicofo joined.

@osys Another idea: have you tried to lower the priority of your hook to some negative value instead of 0?

Merging my discussion into this as I’m now in the same situation.

1 Like

Using the muc_room_default_persistent = true method I now have a different error: connection.GET_SESSION_ID_ERROR
I just closed the browser and joined in a private tab.

Folks, I’ve finally made it working by updating to the freshest version of Prosody

Prosody 0.11.5

# Lua environment
Lua version:                    Lua 5.2
LuaRocks:               Not installed

# Network

Backend: select

# Lua module versions
DBI:            0.7
lfs:            LuaFileSystem 1.6.3
lxp:            LuaExpat 1.3.0
socket:         LuaSocket 3.0-rc1
ssl:            0.6
1 Like

You can try to adjust the module posted above to fit your needs, that is do not allow to delete the password and don’t let rooms go stale (perhaps just remove the muc-room-destroyed hook.
Restart prosody to enable the module.

Now create a room, set a password and leave the room. Check that a plaintext file has been created in prosody’s data folder in a folder called <your-muc-component>/persistent_muc_passwords/<urlencoded_muc_name>.dat

Then also enable the prosody module described here: https://modules.prosody.im/mod_muc_config_restrict.html and add the muc#roomconfig_roomsecret option. Restart prosody again. For each room you want to setup, create a file similar to the file you checked in the last step. Make sure these are only readable by the prosody user.

This is still just a workaround, as anybody who joins a room first (i.e. the moderator) will see the Remove Password button. However, clicking this button shows an error message stating that passwords were not supported.

Hope this helps!

3 Likes

I am using docker as well and would to have this setup. Is it possible for you to layout in a more detailed guide? I am struggling on where the modules locations are and if we need to turn that on in the docker-compose.yml file (via .env).