Parcourir la source

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

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

* squash: separate values ip and room.

* chore(deps) lib-jitsi-meet@latest

https://github.com/jitsi/lib-jitsi-meet/compare/v1886.0.0+bc446e99...v1887.0.0+9652999d

* squash: text adjust
factor2
Дамян Минков il y a 7 mois
Parent
révision
50e9413aad
Aucun compte lié à l'adresse e-mail de l'auteur

+ 2
- 0
lang/main.json Voir le fichier

641
         "on": "Live Streaming started",
641
         "on": "Live Streaming started",
642
         "onBy": "{{name}} started the live streaming",
642
         "onBy": "{{name}} started the live streaming",
643
         "pending": "Starting Live Stream…",
643
         "pending": "Starting Live Stream…",
644
+        "policyError": "You tried to start a live stream too quickly. Please try again later!",
644
         "serviceName": "Live Streaming service",
645
         "serviceName": "Live Streaming service",
645
         "sessionAlreadyActive": "This session is already being recorded or live streamed.",
646
         "sessionAlreadyActive": "This session is already being recorded or live streamed.",
646
         "signIn": "Sign in with Google",
647
         "signIn": "Sign in with Google",
1055
         "onBy": "{{name}} started the recording",
1056
         "onBy": "{{name}} started the recording",
1056
         "onlyRecordSelf": "Record only my audio and video streams",
1057
         "onlyRecordSelf": "Record only my audio and video streams",
1057
         "pending": "Preparing to record the meeting…",
1058
         "pending": "Preparing to record the meeting…",
1059
+        "policyError": "You tried to start a recording too quickly. Please try again later!",
1058
         "recordAudioAndVideo": "Record audio and video",
1060
         "recordAudioAndVideo": "Record audio and video",
1059
         "recordTranscription": "Record transcription",
1061
         "recordTranscription": "Record transcription",
1060
         "saveLocalRecording": "Save recording file locally (Beta)",
1062
         "saveLocalRecording": "Save recording file locally (Beta)",

+ 5
- 5
package-lock.json Voir le fichier

62
         "js-md5": "0.6.1",
62
         "js-md5": "0.6.1",
63
         "js-sha512": "0.8.0",
63
         "js-sha512": "0.8.0",
64
         "jwt-decode": "2.2.0",
64
         "jwt-decode": "2.2.0",
65
-        "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1886.0.0+bc446e99/lib-jitsi-meet.tgz",
65
+        "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1887.0.0+9652999d/lib-jitsi-meet.tgz",
66
         "lodash-es": "4.17.21",
66
         "lodash-es": "4.17.21",
67
         "moment": "2.29.4",
67
         "moment": "2.29.4",
68
         "moment-duration-format": "2.2.2",
68
         "moment-duration-format": "2.2.2",
15970
     },
15970
     },
15971
     "node_modules/lib-jitsi-meet": {
15971
     "node_modules/lib-jitsi-meet": {
15972
       "version": "0.0.0",
15972
       "version": "0.0.0",
15973
-      "resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1886.0.0+bc446e99/lib-jitsi-meet.tgz",
15974
-      "integrity": "sha512-/XTGm2r3cgKZBMyPS5LHaX9DCZVpY6omWSnh7xkwYtSQtJXIbSKI07Mgmah6o0p8Y3/XsC7xUMfS0qOKn8TlYQ==",
15973
+      "resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1887.0.0+9652999d/lib-jitsi-meet.tgz",
15974
+      "integrity": "sha512-WQ4sF0B+K0V+nqTr8ldFuQkvNxp+2DTUIu+ix0cE6L+NsS1yorRus/mG5lMlaQU9So0W83fnsl38kIj1RuymRQ==",
15975
       "hasInstallScript": true,
15975
       "hasInstallScript": true,
15976
       "license": "Apache-2.0",
15976
       "license": "Apache-2.0",
15977
       "dependencies": {
15977
       "dependencies": {
35316
       }
35316
       }
35317
     },
35317
     },
35318
     "lib-jitsi-meet": {
35318
     "lib-jitsi-meet": {
35319
-      "version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1886.0.0+bc446e99/lib-jitsi-meet.tgz",
35320
-      "integrity": "sha512-/XTGm2r3cgKZBMyPS5LHaX9DCZVpY6omWSnh7xkwYtSQtJXIbSKI07Mgmah6o0p8Y3/XsC7xUMfS0qOKn8TlYQ==",
35319
+      "version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1887.0.0+9652999d/lib-jitsi-meet.tgz",
35320
+      "integrity": "sha512-WQ4sF0B+K0V+nqTr8ldFuQkvNxp+2DTUIu+ix0cE6L+NsS1yorRus/mG5lMlaQU9So0W83fnsl38kIj1RuymRQ==",
35321
       "requires": {
35321
       "requires": {
35322
         "@jitsi/js-utils": "2.2.1",
35322
         "@jitsi/js-utils": "2.2.1",
35323
         "@jitsi/logger": "2.0.2",
35323
         "@jitsi/logger": "2.0.2",

+ 1
- 1
package.json Voir le fichier

68
     "js-md5": "0.6.1",
68
     "js-md5": "0.6.1",
69
     "js-sha512": "0.8.0",
69
     "js-sha512": "0.8.0",
70
     "jwt-decode": "2.2.0",
70
     "jwt-decode": "2.2.0",
71
-    "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1886.0.0+bc446e99/lib-jitsi-meet.tgz",
71
+    "lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1887.0.0+9652999d/lib-jitsi-meet.tgz",
72
     "lodash-es": "4.17.21",
72
     "lodash-es": "4.17.21",
73
     "moment": "2.29.4",
73
     "moment": "2.29.4",
74
     "moment-duration-format": "2.2.2",
74
     "moment-duration-format": "2.2.2",

+ 6
- 0
react/features/recording/middleware.ts Voir le fichier

364
             titleKey: isStreamMode ? 'liveStreaming.inProgress' : 'recording.inProgress'
364
             titleKey: isStreamMode ? 'liveStreaming.inProgress' : 'recording.inProgress'
365
         }));
365
         }));
366
         break;
366
         break;
367
+    case JitsiMeetJS.constants.recording.error.POLICY_VIOLATION:
368
+        dispatch(showRecordingWarning({
369
+            descriptionKey: isStreamMode ? 'liveStreaming.policyError' : 'recording.policyError',
370
+            titleKey: isStreamMode ? 'liveStreaming.failedToStart' : 'recording.failedToStart'
371
+        }));
372
+        break;
367
     default:
373
     default:
368
         dispatch(showRecordingError({
374
         dispatch(showRecordingError({
369
             descriptionKey: isStreamMode
375
             descriptionKey: isStreamMode

+ 39
- 4
resources/prosody-plugins/mod_filter_iq_jibri.lua Voir le fichier

1
 -- This module is enabled under the main virtual host
1
 -- This module is enabled under the main virtual host
2
+local cache = require 'util.cache';
3
+local new_throttle = require 'util.throttle'.create;
2
 local st = require "util.stanza";
4
 local st = require "util.stanza";
3
 local jid_bare = require "util.jid".bare;
5
 local jid_bare = require "util.jid".bare;
4
 local util = module:require 'util';
6
 local util = module:require 'util';
5
 local is_feature_allowed = util.is_feature_allowed;
7
 local is_feature_allowed = util.is_feature_allowed;
8
+local get_ip = util.get_ip;
6
 local get_room_from_jid = util.get_room_from_jid;
9
 local get_room_from_jid = util.get_room_from_jid;
7
 local room_jid_match_rewrite = util.room_jid_match_rewrite;
10
 local room_jid_match_rewrite = util.room_jid_match_rewrite;
8
 
11
 
12
+local limit_jibri_reach_ip_attempts;
13
+local limit_jibri_reach_room_attempts;
14
+local rates_per_ip;
15
+local function load_config()
16
+    limit_jibri_reach_ip_attempts = module:get_option_number("max_number_ip_attempts_per_minute", 9);
17
+    limit_jibri_reach_room_attempts = module:get_option_number("max_number_room_attempts_per_minute", 3);
18
+    -- The size of the cache that saves state for IP addresses
19
+    cache_size = module:get_option_number("jibri_rate_limit_cache_size", 10000);
20
+
21
+    -- Maps an IP address to a util.throttle which keeps the rate of attempts to reach jibri events from that IP.
22
+    rates_per_ip = cache.new(cache_size);
23
+end
24
+load_config();
25
+
9
 -- filters jibri iq in case of requested from jwt authenticated session that
26
 -- filters jibri iq in case of requested from jwt authenticated session that
10
 -- has features in the user context, but without feature for recording
27
 -- has features in the user context, but without feature for recording
11
 module:hook("pre-iq/full", function(event)
28
 module:hook("pre-iq/full", function(event)
24
                 session.granted_jitsi_meet_context_features,
41
                 session.granted_jitsi_meet_context_features,
25
                 occupant.role == 'moderator');
42
                 occupant.role == 'moderator');
26
 
43
 
27
-            if jibri.attr.action == 'start' and not is_allowed then
28
-                module:log('info', 'Filtering jibri start recording, stanza:%s', tostring(stanza));
29
-                session.send(st.error_reply(stanza, 'auth', 'forbidden'));
30
-                return true;
44
+            if jibri.attr.action == 'start' then
45
+                if not is_allowed then
46
+                    module:log('info', 'Filtering jibri start recording, stanza:%s', tostring(stanza));
47
+                    session.send(st.error_reply(stanza, 'auth', 'forbidden'));
48
+                    return true;
49
+                end
50
+
51
+                local ip = get_ip(session);
52
+                if not rates_per_ip:get(ip) then
53
+                    rates_per_ip:set(ip, new_throttle(limit_jibri_reach_ip_attempts, 60));
54
+                end
55
+
56
+                if not room.jibri_throttle then
57
+                    room.jibri_throttle = new_throttle(limit_jibri_reach_room_attempts, 60);
58
+                end
59
+
60
+                if not rates_per_ip:get(ip):poll(1) or not room.jibri_throttle:poll(1) then
61
+                    module:log('warn', 'Filtering jibri start recording, ip:%s, room:%s stanza:%s',
62
+                        ip, room.jid, tostring(stanza));
63
+                    session.send(st.error_reply(stanza, 'wait', 'policy-violation'));
64
+                    return true;
65
+                end
31
             end
66
             end
32
         end
67
         end
33
     end
68
     end

+ 3
- 8
resources/prosody-plugins/mod_rate_limit.lua Voir le fichier

14
 local new_ip = ip_util.new_ip;
14
 local new_ip = ip_util.new_ip;
15
 local match_ip = ip_util.match;
15
 local match_ip = ip_util.match;
16
 local parse_cidr = ip_util.parse_cidr;
16
 local parse_cidr = ip_util.parse_cidr;
17
+local get_ip = module:require "util".get_ip;
17
 
18
 
18
 local config = {};
19
 local config = {};
19
 local limits_resolution = 1;
20
 local limits_resolution = 1;
76
 	return config.whitelist_hosts:contains(h);
77
 	return config.whitelist_hosts:contains(h);
77
 end
78
 end
78
 
79
 
79
-local get_request_from_conn = http_server.get_request_from_conn or function (conn)
80
-	local response = conn and conn._http_open_response;
81
-	return response and response.request or nil;
82
-end;
83
-
84
 -- Add an IP to the set of limied IPs
80
 -- Add an IP to the set of limied IPs
85
 local function limit_ip(ip)
81
 local function limit_ip(ip)
86
 	module:log("info", "Limiting %s due to login/join rate exceeded.", ip);
82
 	module:log("info", "Limiting %s due to login/join rate exceeded.", ip);
192
         return;
185
         return;
193
     end
186
     end
194
 
187
 
195
-	local request = get_request_from_conn(session.conn);
196
-	local ip = request and request.ip or session.ip;
197
-	module:log("debug", "New session from %s", ip);
188
+    local ip = get_ip(session);
189
+    module:log("debug", "New session from %s", ip);
198
     if is_whitelisted(ip) or is_whitelisted_host(session.host) then
190
     if is_whitelisted(ip) or is_whitelisted_host(session.host) then
199
         return;
191
         return;
200
     end
192
     end

+ 15
- 0
resources/prosody-plugins/util.lib.lua Voir le fichier

1
+local http_server = require "net.http.server";
1
 local jid = require "util.jid";
2
 local jid = require "util.jid";
2
 local st = require 'util.stanza';
3
 local st = require 'util.stanza';
3
 local timer = require "util.timer";
4
 local timer = require "util.timer";
578
     }));
579
     }));
579
 end
580
 end
580
 
581
 
582
+-- Note: http_server.get_request_from_conn() was added in Prosody 0.12.3,
583
+-- this code provides backwards compatibility with older versions
584
+local get_request_from_conn = http_server.get_request_from_conn or function (conn)
585
+    local response = conn and conn._http_open_response;
586
+    return response and response.request or nil;
587
+end;
588
+
589
+-- Discover real remote IP of a session
590
+function get_ip(session)
591
+    local request = get_request_from_conn(session.conn);
592
+    return request and request.ip or session.ip;
593
+end
594
+
581
 return {
595
 return {
582
     OUTBOUND_SIP_JIBRI_PREFIXES = OUTBOUND_SIP_JIBRI_PREFIXES;
596
     OUTBOUND_SIP_JIBRI_PREFIXES = OUTBOUND_SIP_JIBRI_PREFIXES;
583
     INBOUND_SIP_JIBRI_PREFIXES = INBOUND_SIP_JIBRI_PREFIXES;
597
     INBOUND_SIP_JIBRI_PREFIXES = INBOUND_SIP_JIBRI_PREFIXES;
590
     is_transcriber_jigasi = is_transcriber_jigasi;
604
     is_transcriber_jigasi = is_transcriber_jigasi;
591
     is_vpaas = is_vpaas;
605
     is_vpaas = is_vpaas;
592
     get_focus_occupant = get_focus_occupant;
606
     get_focus_occupant = get_focus_occupant;
607
+    get_ip = get_ip;
593
     get_room_from_jid = get_room_from_jid;
608
     get_room_from_jid = get_room_from_jid;
594
     get_room_by_name_and_subdomain = get_room_by_name_and_subdomain;
609
     get_room_by_name_and_subdomain = get_room_by_name_and_subdomain;
595
     get_sip_jibri_email_prefix = get_sip_jibri_email_prefix;
610
     get_sip_jibri_email_prefix = get_sip_jibri_email_prefix;

Chargement…
Annuler
Enregistrer