Compare commits

...

5 Commits

Author SHA1 Message Date
Jaya Allamsetty
c9165b16b2 chore(deps): Update lib-jitsi-meet
Cherry picks 03eef6def7
2024-08-12 11:14:58 -04:00
Hristo Terezov
430fd77c7a feat(window.loaded): Add new metric. (#14965) 2024-08-09 12:54:56 -05:00
Hristo Terezov
0c200746e3 fix(gif): Restrict gif rendering to Giphy only 2024-08-09 11:18:58 -05:00
Hristo Terezov
83fe677e46 fix(giphy): Remove proxyUrl config option. 2024-08-09 11:17:18 -05:00
Mihaela Dumitru
6fa0195aa5 fix(visitors) remove default notification (#14970) 2024-08-06 12:01:07 +03:00
16 changed files with 90 additions and 116 deletions

View File

@@ -1747,8 +1747,6 @@ var config = {
// tileTime: 5000,
// // Limit results by rating: g, pg, pg-13, r. Default value: g.
// rating: 'pg',
// // The proxy server url for giphy requests in the web app.
// proxyUrl: 'https://giphy-proxy.example.com',
// },
// Logging

View File

@@ -69,6 +69,11 @@
window.indexLoadedTime = window.performance.now();
console.log("(TIME) index.html loaded:\t", indexLoadedTime);
window.addEventListener('load', function() {
window.loadedEventTime = window.performance.now();
console.log("(TIME) window loaded event:\t", loadedEventTime);
});
// XXX the code below listeners for errors and displays an error message
// in the document body when any of the required files fails to load.
// The intention is to prevent from displaying broken page.

View File

@@ -1502,7 +1502,6 @@
"labelTooltip": "Number of visitors: {{count}}",
"notification": {
"demoteDescription": "Sent here by {{actor}}, raise your hand to participate",
"description": "To participate raise your hand",
"noMainParticipantsDescription": "A participant needs to start the meeting. Please try again in a bit.",
"noMainParticipantsTitle": "This meeting hasnt started yet.",
"noVisitorLobby": "You cannot join while there is a lobby enabled for the meeting.",

9
package-lock.json generated
View File

@@ -61,7 +61,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1844.0.0+a9b6dd7e/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet#release-8091",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
@@ -12489,8 +12489,7 @@
},
"node_modules/lib-jitsi-meet": {
"version": "0.0.0",
"resolved": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1844.0.0+a9b6dd7e/lib-jitsi-meet.tgz",
"integrity": "sha512-ZLOF2lmTgMU+eEltT7UyZ9LY16g+IjA4sWfdFafbTxKub99Db8/B56vfeN3AEXy4ldtslifhgP2Cx0x+CX3Esg==",
"resolved": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#f55f72da6391126e1ffe7bb5d086d27c10f83289",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
@@ -27986,8 +27985,8 @@
}
},
"lib-jitsi-meet": {
"version": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1844.0.0+a9b6dd7e/lib-jitsi-meet.tgz",
"integrity": "sha512-ZLOF2lmTgMU+eEltT7UyZ9LY16g+IjA4sWfdFafbTxKub99Db8/B56vfeN3AEXy4ldtslifhgP2Cx0x+CX3Esg==",
"version": "git+ssh://git@github.com/jitsi/lib-jitsi-meet.git#f55f72da6391126e1ffe7bb5d086d27c10f83289",
"from": "lib-jitsi-meet@https://github.com/jitsi/lib-jitsi-meet#release-8091",
"requires": {
"@jitsi/js-utils": "2.2.1",
"@jitsi/logger": "2.0.2",

View File

@@ -67,7 +67,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet/releases/download/v1844.0.0+a9b6dd7e/lib-jitsi-meet.tgz",
"lib-jitsi-meet": "https://github.com/jitsi/lib-jitsi-meet#release-8091",
"lodash": "4.17.21",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",

View File

@@ -375,7 +375,6 @@ export interface IConfig {
giphy?: {
displayMode?: 'all' | 'tile' | 'chat';
enabled?: boolean;
proxyUrl?: string;
rating?: 'g' | 'pg' | 'pg-13' | 'r';
sdkKey?: string;
tileTime?: number;

View File

@@ -1,14 +1,21 @@
import React, { Component, ReactNode } from 'react';
import { toArray } from 'react-emoji-render';
import { connect } from 'react-redux';
import { IReduxState } from '../../../../app/types';
import GifMessage from '../../../../chat/components/web/GifMessage';
import { GIF_PREFIX } from '../../../../gifs/constants';
import { isGifMessage } from '../../../../gifs/functions.web';
import { isGifEnabled, isGifMessage } from '../../../../gifs/functions.web';
import Linkify from './Linkify';
interface IProps {
/**
* Whether the gifs are enabled or not.
*/
gifEnabled: boolean;
/**
* The body of the message.
*/
@@ -43,11 +50,11 @@ class Message extends Component<IProps> {
// Tokenize the text in order to avoid emoji substitution for URLs
const tokens = text ? text.split(' ') : [];
const content = [];
const { gifEnabled } = this.props;
// check if the message is a GIF
if (isGifMessage(text)) {
if (gifEnabled && isGifMessage(text)) {
const url = text.substring(GIF_PREFIX.length, text.length - 1);
content.push(<GifMessage
@@ -93,4 +100,16 @@ class Message extends Component<IProps> {
}
}
export default Message;
/**
* Maps part of the redux state to the props of this component.
*
* @param {IReduxState} state - The Redux state.
* @returns {IProps}
*/
function _mapStateToProps(state: IReduxState) {
return {
gifEnabled: isGifEnabled(state)
};
}
export default connect(_mapStateToProps)(Message);

View File

@@ -6,7 +6,7 @@ import { IReduxState } from '../../../app/types';
import Avatar from '../../../base/avatar/components/Avatar';
import { translate } from '../../../base/i18n/functions';
import Linkify from '../../../base/react/components/native/Linkify';
import { isGifMessage } from '../../../gifs/functions.native';
import { isGifEnabled, isGifMessage } from '../../../gifs/functions.native';
import { MESSAGE_TYPE_ERROR, MESSAGE_TYPE_LOCAL } from '../../constants';
import {
getCanReplyToMessage,
@@ -32,7 +32,7 @@ class ChatMessage extends Component<IChatMessageProps> {
* @inheritdoc
*/
render() {
const { message, knocking } = this.props;
const { gifEnabled, message, knocking } = this.props;
const localMessage = message.messageType === MESSAGE_TYPE_LOCAL;
const { privateMessage, lobbyChat } = message;
@@ -82,7 +82,7 @@ class ChatMessage extends Component<IChatMessageProps> {
<View style = { messageBubbleStyle }>
<View style = { styles.textWrapper as ViewStyle } >
{ this._renderDisplayName() }
{ isGifMessage(messageText)
{ gifEnabled && isGifMessage(messageText)
? <GifMessage message = { messageText } />
: (
<Linkify
@@ -210,6 +210,7 @@ class ChatMessage extends Component<IChatMessageProps> {
function _mapStateToProps(state: IReduxState, { message }: IChatMessageProps) {
return {
canReply: getCanReplyToMessage(state, message),
gifEnabled: isGifEnabled(state),
knocking: state['features/lobby'].knocking
};
}

View File

@@ -25,7 +25,7 @@ import StateListenerRegistry from '../base/redux/StateListenerRegistry';
import { playSound, registerSound, unregisterSound } from '../base/sounds/actions';
import { addGif } from '../gifs/actions';
import { GIF_PREFIX } from '../gifs/constants';
import { getGifDisplayMode, isGifMessage } from '../gifs/function.any';
import { getGifDisplayMode, isGifEnabled, isGifMessage } from '../gifs/function.any';
import { showMessageNotification } from '../notifications/actions';
import { NOTIFICATION_TIMEOUT_TYPE } from '../notifications/constants';
import { resetNbUnreadPollsMessages } from '../polls/actions';
@@ -314,7 +314,7 @@ function _addChatMsgListener(conference: IJitsiConference, store: IStore) {
function _onConferenceMessageReceived(store: IStore, { displayName, id, isGuest, message, timestamp, privateMessage }: {
displayName?: string; id: string; isGuest?: boolean;
message: string; privateMessage: boolean; timestamp: number; }) {
const isGif = isGifMessage(message);
const isGif = isGifEnabled(store.getState()) && isGifMessage(message);
if (isGif) {
_handleGifMessageReceived(store, id, message);

View File

@@ -44,6 +44,11 @@ export interface IChatMessageProps extends WithTranslation {
*/
canReply?: boolean;
/**
* Whether gifs are enabled or not.
*/
gifEnabled?: boolean;
/**
* Whether current participant is currently knocking in the lobby room.
*/

View File

@@ -9,7 +9,7 @@ import JitsiScreen from '../../../base/modal/components/JitsiScreen';
import Input from '../../../base/ui/components/native/Input';
import { sendMessage } from '../../../chat/actions.any';
import { goBack } from '../../../mobile/navigation/components/conference/ConferenceNavigationContainerRef';
import { formatGifUrlMessage, getGifRating, getGifUrl, getGiphyProxyUrl } from '../../functions.native';
import { formatGifUrlMessage, getGifRating, getGifUrl } from '../../functions.native';
import GifsMenuFooter from './GifsMenuFooter';
import styles from './styles';
@@ -19,8 +19,6 @@ const GifsMenu = () => {
const dispatch = useDispatch();
const { t } = useTranslation();
const rating = useSelector(getGifRating) as GiphyRating;
const proxyUrl = useSelector(getGiphyProxyUrl);
const options = {
mediaType: GiphyMediaType.Gif,
limit: 20,
@@ -35,7 +33,7 @@ const GifsMenu = () => {
});
const sendGif = useCallback(e => {
const url = getGifUrl(e.nativeEvent.media, proxyUrl);
const url = getGifUrl(e.nativeEvent.media);
sendAnalytics(createGifSentEvent());

View File

@@ -1,4 +1,4 @@
import { GiphyFetch, TrendingOptions, setServerUrl } from '@giphy/js-fetch-api';
import { GiphyFetch, TrendingOptions } from '@giphy/js-fetch-api';
import { Grid } from '@giphy/react-components';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
@@ -20,8 +20,7 @@ import {
formatGifUrlMessage,
getGifAPIKey,
getGifRating,
getGifUrl,
getGiphyProxyUrl
getGifUrl
} from '../../function.any';
const OVERFLOW_DRAWER_PADDING = 16;
@@ -104,7 +103,6 @@ function GifsMenu({ columns = 2, parent }: IProps) {
= parent === IReactionsMenuParent.OverflowDrawer || parent === IReactionsMenuParent.OverflowMenu;
const { clientWidth } = useSelector((state: IReduxState) => state['features/base/responsive-ui']);
const rating = useSelector(getGifRating);
const proxyUrl = useSelector(getGiphyProxyUrl);
const fetchGifs = useCallback(async (offset = 0) => {
const options: TrendingOptions = {
@@ -126,7 +124,7 @@ function GifsMenu({ columns = 2, parent }: IProps) {
const handleGifClick = useCallback((gif, e) => {
e?.stopPropagation();
const url = getGifUrl(gif, proxyUrl);
const url = getGifUrl(gif);
sendAnalytics(createGifSentEvent());
batch(() => {
@@ -189,12 +187,6 @@ function GifsMenu({ columns = 2, parent }: IProps) {
// This fixes that.
useEffect(() => setSearchKey(''), []);
useEffect(() => {
if (proxyUrl) {
setServerUrl(proxyUrl);
}
}, []);
const onInputKeyPress = useCallback((e: React.KeyboardEvent) => {
e.stopPropagation();
}, []);

View File

@@ -33,15 +33,6 @@ export function getGifRating(state: IReduxState) {
return getGifConfig(state).rating || GIF_DEFAULT_RATING;
}
/**
* Get the Giphy proxy url.
*
* @param {IReduxState} state - Redux state.
* @returns {string}
*/
export function getGiphyProxyUrl(state: IReduxState) {
return getGifConfig(state).proxyUrl;
}
/**
* Gets the URL of the GIF for the given participant or null if there's none.
@@ -54,6 +45,26 @@ export function getGifForParticipant(state: IReduxState, participantId: string):
return isGifEnabled(state) ? state['features/gifs'].gifList.get(participantId) || {} : {};
}
/**
* Returns true if a given URL is allowed to be rendered as gif and false otherwise.
*
* @param {string} url - The URL to be validated.
* @returns {boolean} - True if a given URL is allowed to be rendered as gif and false otherwise.
*/
export function isGifUrlAllowed(url: string) {
let hostname: string | undefined;
try {
const urlObject = new URL(url);
hostname = urlObject?.hostname;
} catch (_error) {
return false;
}
return hostname === 'i.giphy.com';
}
/**
* Whether or not the message is a GIF message.
*
@@ -61,26 +72,23 @@ export function getGifForParticipant(state: IReduxState, participantId: string):
* @returns {boolean}
*/
export function isGifMessage(message: string) {
const url = message.substring(GIF_PREFIX.length, message.length - 1);
return message.trim().toLowerCase()
.startsWith(GIF_PREFIX);
.startsWith(GIF_PREFIX) && isGifUrlAllowed(url);
}
/**
* Returns the url of the gif selected in the gifs menu.
*
* @param {Object} gif - The gif data.
* @param {string} proxyUrl - The proxy server url.
* @returns {boolean}
*/
export function getGifUrl(gif?: { data?: { embed_url: string; }; embed_url?: string; }, proxyUrl?: string) {
export function getGifUrl(gif?: { data?: { embed_url: string; }; embed_url?: string; }) {
const embedUrl = gif?.embed_url || gif?.data?.embed_url || '';
const idx = embedUrl.lastIndexOf('/');
const id = embedUrl.substr(idx + 1);
if (proxyUrl) {
return `${proxyUrl}gifs/id/${id}`;
}
return `https://i.giphy.com/media/${id}/giphy.gif`;
}

View File

@@ -72,26 +72,26 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const { conference } = action;
if (getState()['features/visitors'].iAmVisitor) {
dispatch(openDialog(JoinMeetingDialog));
const { demoteActorDisplayName } = getState()['features/visitors'];
dispatch(setVisitorDemoteActor(undefined));
const notificationParams: INotificationProps = {
titleKey: 'visitors.notification.title',
descriptionKey: 'visitors.notification.description'
};
if (demoteActorDisplayName) {
notificationParams.descriptionKey = 'visitors.notification.demoteDescription';
notificationParams.descriptionArguments = {
actor: demoteActorDisplayName
const notificationParams: INotificationProps = {
titleKey: 'visitors.notification.title',
descriptionKey: 'visitors.notification.demoteDescription',
descriptionArguments: {
actor: demoteActorDisplayName
}
};
batch(() => {
dispatch(showNotification(notificationParams, NOTIFICATION_TIMEOUT_TYPE.STICKY));
dispatch(setVisitorDemoteActor(undefined));
});
} else {
dispatch(openDialog(JoinMeetingDialog));
}
// check for demote actor and update notification
dispatch(showNotification(notificationParams, NOTIFICATION_TIMEOUT_TYPE.STICKY));
} else {
dispatch(setVisitorsSupported(conference.isVisitorsSupported()));
conference.on(JitsiConferenceEvents.VISITORS_SUPPORTED_CHANGED, (value: boolean) => {

View File

@@ -51,6 +51,10 @@ globalNS.connectionTimes = {
'index.loaded': window.indexLoadedTime
};
window.addEventListener('load', () => {
globalNS.connectionTimes['window.loaded'] = window.loadedEventTime;
});
document.addEventListener('DOMContentLoaded', () => {
const now = window.performance.now();

View File

@@ -1,53 +0,0 @@
server {
listen 443 ssl;
server_name giphy-proxy.example.com;
ssl_certificate /etc/nginx/ssl/giphy-proxy.example.com.crt;
ssl_certificate_key /etc/nginx/ssl/giphy-proxy.example.com.key;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
root /usr/share/nginx/html;
index index.html index.htm;
}
location /gifs/trending {
proxy_pass https://api.giphy.com/v1/gifs/trending;
}
location /gifs/search {
proxy_pass https://api.giphy.com/v1/gifs/search;
}
location ~ /gifs/id/(.*) {
proxy_pass https://i.giphy.com/media/$1/giphy.gif;
}
}