Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
139 lines
4.8 KiB
Lua
139 lines
4.8 KiB
Lua
-- to be enabled under the main virtual host with all required settings
|
|
-- short_lived_token = {
|
|
-- issuer = 'myissuer';
|
|
-- accepted_audiences = { 'file-sharing' };
|
|
-- key_path = '/etc/prosody/short_lived_token.key';
|
|
-- key_id = 'my_kid';
|
|
-- ttl_seconds = 30;
|
|
-- };
|
|
-- The key in key_path can be generated via: openssl genrsa -out $PRIVATE_KEY_PATH 2048
|
|
-- And you can get the public key from it, which can be used ot verify those tokens via:
|
|
-- openssl rsa -in $PRIVATE_KEY_PATH -pubout -out $PUBLIC_KEY_PATH
|
|
|
|
local jid = require 'util.jid';
|
|
local st = require 'util.stanza';
|
|
local jwt = module:require 'luajwtjitsi';
|
|
|
|
local util = module:require 'util';
|
|
local is_vpaas = util.is_vpaas;
|
|
local process_host_module = util.process_host_module;
|
|
local table_find = util.table_find;
|
|
local create_throttle = require 'prosody.util.throttle'.create;
|
|
|
|
local SERVICE_TYPE = 'short-lived-token';
|
|
local options = module:get_option('short_lived_token');
|
|
|
|
if not (options.issuer and options.accepted_audiences
|
|
and options.key_path and options.key_id and options.ttl_seconds) then
|
|
module:log('error', 'Missing required options for short_lived_token');
|
|
return;
|
|
end
|
|
|
|
local f = io.open(options.key_path, 'r');
|
|
if f then
|
|
options.key = f:read('*all');
|
|
f:close();
|
|
end
|
|
|
|
local accepted_requests = {};
|
|
for _, host in pairs(options.accepted_audiences) do
|
|
accepted_requests[string.format('%s:%s:0', SERVICE_TYPE, host)] = host;
|
|
end
|
|
|
|
local server_region_name = module:get_option_string('region_name');
|
|
|
|
local main_muc_component_host = module:get_option_string('main_muc');
|
|
if main_muc_component_host == nil then
|
|
module:log('error', 'main_muc not configured. Cannot proceed.');
|
|
return;
|
|
end
|
|
local main_muc_service;
|
|
|
|
function generateToken(session, audience, room, occupant)
|
|
local t = os.time();
|
|
local exp = t + options.ttl_seconds;
|
|
local presence = occupant:get_presence(session.full_jid);
|
|
local _, _, id = extract_subdomain(jid.node(room.jid));
|
|
|
|
local payload = {
|
|
iss = options.issuer,
|
|
aud = audience,
|
|
nbf = t,
|
|
exp = exp,
|
|
sub = session.jitsi_web_query_prefix or module.host,
|
|
context = {
|
|
group = session.jitsi_meet_context_group or session.granted_jitsi_meet_context_group_id,
|
|
user = session.jitsi_meet_context_user or {
|
|
id = session.full_jid,
|
|
name = presence:get_child_text('nick', 'http://jabber.org/protocol/nick'),
|
|
email = presence:get_child_text("email") or nil,
|
|
nick = jid.resource(occupant.nick)
|
|
},
|
|
features = session.jitsi_meet_context_features
|
|
},
|
|
room = session.jitsi_web_query_room,
|
|
meeting_id = room._data.meetingId,
|
|
granted_from = session.granted_jitsi_meet_context_user_id,
|
|
customer_id = id or session.jitsi_meet_context_group or session.granted_jitsi_meet_context_group_id,
|
|
backend_region = server_region_name,
|
|
user_region = session.user_region
|
|
};
|
|
|
|
local alg = 'RS256';
|
|
local token, err = jwt.encode(payload, options.key, alg, { kid = options.key_id });
|
|
if not err then
|
|
return token
|
|
else
|
|
module:log('error', 'Error generating token: %s', err);
|
|
return ''
|
|
end
|
|
end
|
|
|
|
module:hook('external_service/credentials', function (event)
|
|
local requested_credentials, services, session, stanza
|
|
= event.requested_credentials, event.services, event.origin, event.stanza;
|
|
local room = get_room_by_name_and_subdomain(session.jitsi_web_query_room, session.jitsi_web_query_prefix);
|
|
|
|
if not room then
|
|
session.send(st.error_reply(stanza, 'cancel', 'not-allowed'));
|
|
return;
|
|
end
|
|
|
|
local occupant = room:get_occupant_by_real_jid(session.full_jid);
|
|
if not occupant then
|
|
session.send(st.error_reply(stanza, 'cancel', 'not-allowed'));
|
|
return;
|
|
end
|
|
|
|
for request in requested_credentials do
|
|
local host = accepted_requests[request];
|
|
if host then
|
|
services:push({
|
|
type = SERVICE_TYPE;
|
|
host = host;
|
|
username = 'token';
|
|
password = generateToken(session, host, room, occupant);
|
|
expires = os.time() + options.ttl_seconds;
|
|
restricted = true;
|
|
transport = 'https';
|
|
port = 443;
|
|
});
|
|
end
|
|
end
|
|
|
|
end);
|
|
|
|
process_host_module(main_muc_component_host, function(host_module, host)
|
|
local muc_module = prosody.hosts[host].modules.muc;
|
|
|
|
if muc_module then
|
|
main_muc_service = muc_module;
|
|
else
|
|
prosody.hosts[host].events.add_handler('module-loaded', function(event)
|
|
if (event.module == 'muc') then
|
|
main_muc_service = prosody.hosts[host].modules.muc;
|
|
end
|
|
end);
|
|
end
|
|
end);
|