Skip to content

Commit e4a4de9

Browse files
committed
Add jitsi-meet modules and README.md
1 parent 9957f73 commit e4a4de9

8 files changed

Lines changed: 1340 additions & 2 deletions

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Add the plugin javascript file to your kiwiirc `config.json` and configure the s
3636
### Security note!
3737
By default, this plugin uses Jisti's public servers. It should be noted that by using these public servers, your conference calls are not secure in that anybody can join them if they can guess the room name.
3838

39-
Note that the "secure" option enables JWT authentication, but will not work on Jitsi's public server.
39+
Note that the "secure" option enables JWT authentication, but will not work on Jitsi's public server. For more information see [Running your own conference server](#Running-your-own-conference-server)
4040

4141
### Extra configuration
4242
Jitsi Meet supports extra configuration to customise its interface and functions. You can configure these via the optional `interfaceConfigOverwrite` and `configOverwrite` config options.
@@ -103,7 +103,12 @@ You may also choose to hide the conference call icon in either channels or priva
103103
}
104104
```
105105
### Running your own conference server
106-
Running your own conference server allows you to secure your conference rooms. We make use of the Jitsi Meet server to handle the conference calls, the installation steps can be found here: https://github.com/jitsi/jitsi-meet/blob/master/doc/quick-install.md
106+
Running your own conference server allows you to secure your conference rooms. We make use of the Jitsi Meet server to handle the conference calls, the installation steps can be found here: https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart
107+
108+
If docker is your preferred method then see here: https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker
109+
110+
For installing and configuring jitsi to support [IRCv3 EXTJWT](https://github.com/ircv3/ircv3-specifications/pull/341) documentation can can be found here: https://github.com/kiwiirc/plugin-conference/blob/master/jitsi-meet-modules/README.md
111+
107112

108113
## License
109114

jitsi-meet-modules/README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Jitsi Meet Kiwi IRC auth plugin
2+
3+
## About
4+
5+
This repository contains modified copy of Jitsi Meet's Prosody token authentication modules for use with [kiwiirc/plugin-conference].
6+
7+
The purpose of these files is to mirror the access control model and user identity from the IRC environment to the Jitsi conference room.
8+
9+
This auth method is necessary when using `{ "conference.secure": true }` in your KiwiIRC client config.
10+
11+
___
12+
13+
## Docker install
14+
15+
Follow the [jitsi documentation](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker) for setting up jitsi docker
16+
17+
After setting up docker copy the contents of `jitsi-meet-modules/` to `~/.jitsi-meet-cfg/prosody/prosody-plugins-custom`
18+
19+
### Editing the docker .env file
20+
21+
Uncomment and set the following settings
22+
23+
```
24+
ENABLE_WELCOME_PAGE=0
25+
26+
ENABLE_AUTH=1
27+
28+
ENABLE_GUESTS=0
29+
30+
AUTH_TYPE=jwt
31+
32+
JWT_APP_ID=<hostname of your ircd as specified in startupOptions.server>
33+
34+
JWT_APP_SECRET=<your jwt secret>
35+
36+
XMPP_MUC_MODULES=kiwi_muc_role_from_jwt,kiwi_presence_identity
37+
```
38+
39+
The following vars will require adding:
40+
41+
```
42+
ENABLE_P2P=false
43+
44+
ENABLE_AUTO_OWNER=false
45+
46+
JWT_AUTH_TYPE=kiwi_token
47+
48+
JWT_TOKEN_AUTH_MODULE=kiwi_token_verification
49+
```
50+
51+
___
52+
53+
## Native install
54+
55+
Before proceeding, you'll need to complete the installation of the Jitsi Meet backend. Using the apt repository mentioned in [Jitsi Meet's instructions](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart), install the `jitsi-meet` and `jitsi-meet-tokens` packages. e.g. `apt-get install jitsi-meet jitsi-meet-tokens`.
56+
57+
> A few hints:
58+
>
59+
> - On Ubuntu 16.04 `jitsi-meet-tokens` currently has a dependency on `prosody-trunk`, rather than the `prosody` package available in the main repositories. See [Prosody's documentation] to add their apt repository as a package source on your system.
60+
> - The Jitsi Meet packaging may have issues on Ubuntu 18.04.
61+
> - Use an interactive shell when installing `jitsi-meet` because the packages will ask questions via debconf during installation and errors will occur if no debconf frontend is available.
62+
> - Install `nginx` **before** `jitsi-meet` if you want the `jitsi-meet` package to automatically create an nginx site configuration for you.
63+
> - On debian there is an issue building the dependencies at install time due to a difference in libssl packages. As a workaround, do `sudo apt-get install apt-transport-https libssl1.0-dev luarocks git && sudo luarocks install luacrypto` before trying to install the jitsi packages. `libssl1.0-dev` is needed to build luacrypto, but it will get uninstalled and replaced with `libssl-dev` due to the dependencies specified by jitsi packages later on.
64+
> - On Ubuntu 20.04 / Debian 10 `liblua5.2-dev` package is required before installing `jitsi-meet-tokens`.
65+
> - To restart jitsi services after editing configs you can use `sudo systemctl restart prosody.service jicofo.service jitsi-videobridge2.service`.
66+
67+
### Post install
68+
69+
After installing the required packages copy the contents of `jitsi-meet-modules/` to `/usr/share/jitsi-meet-kiwi`
70+
71+
### Configuring
72+
73+
In `/etc/prosody/conf.d/<your jitsi domain>.cfg.lua`:
74+
75+
1. Edit `plugin_paths` to add the newly created `/usr/share/jitsi-meet-kiwi` directory.
76+
77+
2. At the top level of the config, add these two lines, replacing `<your jitsi domain>` with the appropriate value for your installation:
78+
79+
```lua
80+
jitsi_meet_domain = "<your jitsi domain>";
81+
jitsi_meet_focus_hostname = "auth.<your jitsi domain>";
82+
```
83+
84+
3. `authentication = "kiwi_token"`
85+
86+
4. `app_secret` (referred to as `application secret` during the interactive debconf prompts) needs to match the secret set in your webircgateway config.
87+
88+
5. `app_id` (`application ID` in debconf) must match the hostname in the upstream section of your webircgateway config **as well as** the server hostname that the KiwiIRC *client* uses (i.e. `startupOptions.server` in the client `config.json`)
89+
90+
6. Remove `"token_verification"` and add `"kiwi_token_verification"; "kiwi_muc_role_from_jwt"; "kiwi_presence_identity";` to `modules_enabled` in `Component "conference.<your jitsi domain>" "muc"`.
91+
92+
7. If you're hosting Jitsi on a separate hostname from KiwiIRC, you will need to either add
93+
94+
```lua
95+
cross_domain_bosh = true;
96+
```
97+
98+
at the top level of the config or manually add CORS headers in your nginx config.
99+
100+
### Jicofo SIP Communicator properties
101+
102+
8. Open `/etc/jitsi/jicofo/sip-communicator.properties` and add the following line:
103+
104+
```ini
105+
org.jitsi.jicofo.DISABLE_AUTO_OWNER=True
106+
```
107+
108+
### Jitsi Meet config
109+
110+
9. You may also want to disable P2P connectivity in the videobridge's config file at `/etc/jitsi/meet/<your jitsi domain>-config.js`.
111+
112+
```js
113+
p2p: { enabled: false }
114+
```
115+
116+
See `/usr/share/doc/jitsi-meet-web-config/config.js` for an example of the configuration format.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
-- Token authentication
2+
-- Copyright (C) 2015 Atlassian
3+
4+
local formdecode = require "util.http".formdecode;
5+
local generate_uuid = require "util.uuid".generate;
6+
local new_sasl = require "util.sasl".new;
7+
local sasl = require "util.sasl";
8+
local token_util = module:require "token/util_kiwi".new(module);
9+
local sessions = prosody.full_sessions;
10+
11+
module:log("info", "kiwiirc patch active: prosody-plugins/mod_auth_kiwi_token.lua");
12+
13+
-- no token configuration
14+
if token_util == nil then
15+
return;
16+
end
17+
18+
-- define auth provider
19+
local provider = {};
20+
21+
local host = module.host;
22+
23+
-- Extract 'token' param from URL when session is created
24+
function init_session(event)
25+
local session, request = event.session, event.request;
26+
local query = request.url.query;
27+
28+
if query ~= nil then
29+
local params = formdecode(query);
30+
31+
-- The following fields are filled in the session, by extracting them
32+
-- from the query and no validation is beeing done.
33+
-- After validating auth_token will be cleaned in case of error and few
34+
-- other fields will be extracted from the token and set in the session
35+
36+
session.auth_token = query and params.token or nil;
37+
-- previd is used together with https://modules.prosody.im/mod_smacks.html
38+
-- the param is used to find resumed session and re-use anonymous(random) user id
39+
-- (see get_username_from_token)
40+
session.previd = query and params.previd or nil;
41+
42+
-- The room name and optional prefix from the web query
43+
session.jitsi_web_query_room = params.room;
44+
session.jitsi_web_query_prefix = params.prefix or "";
45+
46+
-- Deprecated, you should use jitsi_web_query_room and jitsi_web_query_prefix
47+
session.jitsi_bosh_query_room = session.jitsi_web_query_room;
48+
session.jitsi_bosh_query_prefix = session.jitsi_web_query_prefix;
49+
end
50+
end
51+
52+
module:hook_global("bosh-session", init_session);
53+
module:hook_global("websocket-session", init_session);
54+
55+
function provider.test_password(username, password)
56+
return nil, "Password based auth not supported";
57+
end
58+
59+
function provider.get_password(username)
60+
return nil;
61+
end
62+
63+
function provider.set_password(username, password)
64+
return nil, "Set password not supported";
65+
end
66+
67+
function provider.user_exists(username)
68+
return nil;
69+
end
70+
71+
function provider.create_user(username, password)
72+
return nil;
73+
end
74+
75+
function provider.delete_user(username)
76+
return nil;
77+
end
78+
79+
function provider.get_sasl_handler(session)
80+
81+
local function get_username_from_token(self, message)
82+
83+
-- retrieve custom public key from server and save it on the session
84+
local pre_event_result = prosody.events.fire_event("pre-jitsi-authentication-fetch-key", session);
85+
if pre_event_result ~= nil and pre_event_result.res == false then
86+
log("warn",
87+
"Error verifying token on pre authentication stage:%s, reason:%s", pre_event_result.error, pre_event_result.reason);
88+
session.auth_token = nil;
89+
return pre_event_result.res, pre_event_result.error, pre_event_result.reason;
90+
end
91+
92+
local res, error, reason = token_util:process_and_verify_token(session);
93+
if res == false then
94+
log("warn",
95+
"Error verifying token err:%s, reason:%s", error, reason);
96+
session.auth_token = nil;
97+
return res, error, reason;
98+
end
99+
100+
local customUsername
101+
= prosody.events.fire_event("pre-jitsi-authentication", session);
102+
103+
if (customUsername) then
104+
self.username = customUsername;
105+
elseif (session.previd ~= nil) then
106+
for _, session1 in pairs(sessions) do
107+
if (session1.resumption_token == session.previd) then
108+
self.username = session1.username;
109+
break;
110+
end
111+
end
112+
else
113+
self.username = message;
114+
end
115+
116+
local post_event_result = prosody.events.fire_event("post-jitsi-authentication", session);
117+
if post_event_result ~= nil and post_event_result.res == false then
118+
log("warn",
119+
"Error verifying token on post authentication stage :%s, reason:%s", post_event_result.error, post_event_result.reason);
120+
session.auth_token = nil;
121+
return post_event_result.res, post_event_result.error, post_event_result.reason;
122+
end
123+
124+
return res;
125+
end
126+
127+
return new_sasl(host, { anonymous = get_username_from_token });
128+
end
129+
130+
module:provides("auth", provider);
131+
132+
local function anonymous(self, message)
133+
134+
local username = generate_uuid();
135+
136+
-- This calls the handler created in 'provider.get_sasl_handler(session)'
137+
local result, err, msg = self.profile.anonymous(self, username, self.realm);
138+
139+
if result == true then
140+
if (self.username == nil) then
141+
self.username = username;
142+
end
143+
return "success";
144+
else
145+
return "failure", err, msg;
146+
end
147+
end
148+
149+
sasl.registerMechanism("ANONYMOUS", {"anonymous"}, anonymous);
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
2+
3+
local muc_service = module:depends("muc");
4+
local room_mt = muc_service.room_mt;
5+
6+
--local occupant = muc_service.occupant_mt;
7+
module:set_global();
8+
--module:depends("c2s");
9+
--local sessions = module:shared("c2s/sessions");
10+
local sessions = module:shared("sessions");
11+
12+
local muc_util = module:require "muc/util";
13+
local valid_affiliations = muc_util.valid_affiliations;
14+
15+
local jid_bare = require "util.jid".bare;
16+
local jid_split = require "util.jid".split;
17+
18+
-- package.path = '?.lua;' .. package.path
19+
-- local inspect = require('/usr/share/jitsi-meet/prosody-plugins/inspect');
20+
21+
module:log("info", "kiwiirc patch active: prosody-plugins/mod_kiwi_muc_role_from_jwt.lua");
22+
23+
function len(t)
24+
local n = 0;
25+
for _ in pairs(t) do
26+
n = n + 1
27+
end
28+
return n
29+
end
30+
31+
local seen={}
32+
33+
function dump(t,i)
34+
module:log("debug", "dump table size: " .. len(t));
35+
seen[t]=true
36+
local s={}
37+
local n=0
38+
for k in pairs(t) do
39+
n=n+1 s[n]=k
40+
end
41+
if pcall(function () table.sort(s); end) then
42+
table.sort(s)
43+
end
44+
for k,v in ipairs(s) do
45+
module:log("debug", "dump: " .. tostring(i) .. tostring(v))
46+
v=t[v]
47+
if type(v)=="table" and not seen[v] then
48+
dump(v,i.."\t")
49+
end
50+
end
51+
end
52+
53+
local jitsi_meet_focus_hostname = module:get_option("jitsi_meet_focus_hostname", os.getenv("XMPP_AUTH_DOMAIN"));
54+
55+
room_mt.get_affiliation = function(room, jid)
56+
--module:log("debug", "--- entered get_affiliation: jid=" .. jid);
57+
--module:log("debug", debug.traceback());
58+
-- dump(_G,"");
59+
-- dump(_G.full_sessions, "");
60+
--module:log("debug", "sessions - " .. inspect(prosody.full_sessions));
61+
local bare_jid = jid_bare(jid);
62+
-- module:log("debug", "jid : " .. session);
63+
--local sess = occupant:get_presence(jid);
64+
--module.log("debug", "sess - " .. sess);
65+
local affiliation = nil;
66+
67+
-- TODO: don't allow earlier sessions to override affiliation claim from later ones
68+
for conn, session in pairs(prosody.full_sessions) do
69+
--module:log("debug", "test session: " .. jid .. " - " .. session.full_jid);
70+
if jid_bare(session.full_jid) == bare_jid then
71+
--module:log("debug", "found session - " .. inspect(session));
72+
--module:log("debug", "found session - " .. session.full_jid);
73+
if valid_affiliations[session.jitsi_meet_room_affiliation] ~= nil then
74+
affiliation = session.jitsi_meet_room_affiliation;
75+
-- module:log("debug", "setting affil - " .. affiliation);
76+
end
77+
end
78+
end
79+
local default_focus_affil = "owner";
80+
local node, host, resource = jid_split(jid);
81+
if host == jitsi_meet_focus_hostname then
82+
module:log("debug", "affil (focus): " .. default_focus_affil .. " jid: " .. jid);
83+
return default_focus_affil;
84+
end
85+
local default_affil = "member";
86+
if affiliation == nil then
87+
module:log("debug", "affil (default): " .. default_affil .. " jid: " .. jid);
88+
return default_affil;
89+
end
90+
module:log("debug", "affil: " .. affiliation .. " jid: " .. jid);
91+
return affiliation;
92+
end

0 commit comments

Comments
 (0)