Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(recording): Shows notification when you try to start recording too quick. #15311

Merged
merged 4 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lang/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,7 @@
"on": "Live Streaming started",
"onBy": "{{name}} started the live streaming",
"pending": "Starting Live Stream…",
"policyError": "You tried to start live stream too quickly. Please try again later!",
"serviceName": "Live Streaming service",
"sessionAlreadyActive": "This session is already being recorded or live streamed.",
"signIn": "Sign in with Google",
Expand Down Expand Up @@ -1055,6 +1056,7 @@
"onBy": "{{name}} started the recording",
"onlyRecordSelf": "Record only my audio and video streams",
"pending": "Preparing to record the meeting…",
"policyError": "You tried to start recording too quickly. Please try again later!",
"recordAudioAndVideo": "Record audio and video",
"recordTranscription": "Record transcription",
"saveLocalRecording": "Save recording file locally (Beta)",
Expand Down
6 changes: 6 additions & 0 deletions react/features/recording/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,12 @@ function _showRecordingErrorNotification(session: any, dispatch: IStore['dispatc
titleKey: isStreamMode ? 'liveStreaming.inProgress' : 'recording.inProgress'
}));
break;
case JitsiMeetJS.constants.recording.error.POLICY_VIOLATION:
dispatch(showRecordingWarning({
descriptionKey: isStreamMode ? 'liveStreaming.policyError' : 'recording.policyError',
titleKey: isStreamMode ? 'liveStreaming.failedToStart' : 'recording.failedToStart'
}));
break;
default:
dispatch(showRecordingError({
descriptionKey: isStreamMode
Expand Down
41 changes: 37 additions & 4 deletions resources/prosody-plugins/mod_filter_iq_jibri.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
-- This module is enabled under the main virtual host
local cache = require 'util.cache';
local new_throttle = require 'util.throttle'.create;
local st = require "util.stanza";
local jid_bare = require "util.jid".bare;
local util = module:require 'util';
local is_feature_allowed = util.is_feature_allowed;
local get_ip = util.get_ip;
local get_room_from_jid = util.get_room_from_jid;
local room_jid_match_rewrite = util.room_jid_match_rewrite;

local limit_jibri_reach_attempts;
local rates_per_ip;
local function load_config()
limit_jibri_reach_attempts = module:get_option_number("max_number_attempt_per_minute", 3);
-- The size of the cache that saves state for IP addresses
cache_size = module:get_option_number("jibri_rate_limit_cache_size", 10000);

-- Maps an IP address to a util.throttle which keeps the rate of attempts to reach jibri events from that IP.
rates_per_ip = cache.new(cache_size);
end
load_config();

-- filters jibri iq in case of requested from jwt authenticated session that
-- has features in the user context, but without feature for recording
module:hook("pre-iq/full", function(event)
Expand All @@ -24,10 +39,28 @@ module:hook("pre-iq/full", function(event)
session.granted_jitsi_meet_context_features,
occupant.role == 'moderator');

if jibri.attr.action == 'start' and not is_allowed then
module:log('info', 'Filtering jibri start recording, stanza:%s', tostring(stanza));
session.send(st.error_reply(stanza, 'auth', 'forbidden'));
return true;
if jibri.attr.action == 'start' then
if not is_allowed then
module:log('info', 'Filtering jibri start recording, stanza:%s', tostring(stanza));
session.send(st.error_reply(stanza, 'auth', 'forbidden'));
return true;
end

local ip = get_ip(session);
if not rates_per_ip:get(ip) then
rates_per_ip:set(ip, new_throttle(limit_jibri_reach_attempts, 60));
end

if not room.jibri_throttle then
room.jibri_throttle = new_throttle(limit_jibri_reach_attempts, 60);
end

if not rates_per_ip:get(ip):poll(1) or not room.jibri_throttle:poll(1) then
module:log('warn', 'Filtering jibri start recording, ip:%s, room:%s stanza:%s',
ip, room.jid, tostring(stanza));
session.send(st.error_reply(stanza, 'wait', 'policy-violation'));
return true;
end
end
end
end
Expand Down
14 changes: 3 additions & 11 deletions resources/prosody-plugins/mod_rate_limit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ local ip_util = require "util.ip";
local new_ip = ip_util.new_ip;
local match_ip = ip_util.match;
local parse_cidr = ip_util.parse_cidr;
local get_ip = module:require "util".get_ip;

local config = {};
local limits_resolution = 1;
Expand Down Expand Up @@ -76,14 +77,6 @@ local function is_whitelisted_host(h)
return config.whitelist_hosts:contains(h);
end

-- Discover real remote IP of a session
-- Note: http_server.get_request_from_conn() was added in Prosody 0.12.3,
-- this code provides backwards compatibility with older versions
local get_request_from_conn = http_server.get_request_from_conn or function (conn)
local response = conn and conn._http_open_response;
return response and response.request or nil;
end;

-- Add an IP to the set of limied IPs
local function limit_ip(ip)
module:log("info", "Limiting %s due to login/join rate exceeded.", ip);
Expand Down Expand Up @@ -192,9 +185,8 @@ local function filter_hook(session)
return;
end

local request = get_request_from_conn(session.conn);
local ip = request and request.ip or session.ip;
module:log("debug", "New session from %s", ip);
local ip = get_ip(session);
module:log("debug", "New session from %s", ip);
if is_whitelisted(ip) or is_whitelisted_host(session.host) then
return;
end
Expand Down
15 changes: 15 additions & 0 deletions resources/prosody-plugins/util.lib.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local http_server = require "net.http.server";
local jid = require "util.jid";
local st = require 'util.stanza';
local timer = require "util.timer";
Expand Down Expand Up @@ -578,6 +579,19 @@ function respond_iq_result(origin, stanza)
}));
end

-- Note: http_server.get_request_from_conn() was added in Prosody 0.12.3,
-- this code provides backwards compatibility with older versions
local get_request_from_conn = http_server.get_request_from_conn or function (conn)
local response = conn and conn._http_open_response;
return response and response.request or nil;
end;

-- Discover real remote IP of a session
function get_ip(session)
local request = get_request_from_conn(session.conn);
return request and request.ip or session.ip;
end

return {
OUTBOUND_SIP_JIBRI_PREFIXES = OUTBOUND_SIP_JIBRI_PREFIXES;
INBOUND_SIP_JIBRI_PREFIXES = INBOUND_SIP_JIBRI_PREFIXES;
Expand All @@ -590,6 +604,7 @@ return {
is_transcriber_jigasi = is_transcriber_jigasi;
is_vpaas = is_vpaas;
get_focus_occupant = get_focus_occupant;
get_ip = get_ip;
get_room_from_jid = get_room_from_jid;
get_room_by_name_and_subdomain = get_room_by_name_and_subdomain;
get_sip_jibri_email_prefix = get_sip_jibri_email_prefix;
Expand Down