Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 14 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ deploy-appbundle:
$(BUILD_DIR)/close3.min.js \
$(BUILD_DIR)/close3.min.js.map \
$(DEPLOY_DIR) || true
cp \
$(BUILD_DIR)/excalidraw.min.js \
$(BUILD_DIR)/excalidraw.min.js.map \
$(BUILD_DIR)/rnnoise.min.js \
$(BUILD_DIR)/rnnoise.min.js.map \
$(BUILD_DIR)/ts-ebml.min.js \
$(BUILD_DIR)/ts-ebml.min.js.map \
$(BUILD_DIR)/zxcvbn.min.js \
$(BUILD_DIR)/zxcvbn.min.js.map \
$(BUILD_DIR)/vendor.min.js \
$(BUILD_DIR)/vendor.min.js.map \
$(BUILD_DIR)/react.min.js \
$(BUILD_DIR)/react.min.js.map \
$(DEPLOY_DIR) || true

deploy-lib-jitsi-meet:
cp \
Expand Down
4 changes: 4 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@
"do_external_connect.js",
"interface_config.js",
"lib-jitsi-meet.min.js",
"react.min.js",
"vendor.min.js",
"app.bundle.min.js",
"all.css"
];
Expand Down Expand Up @@ -198,6 +200,8 @@
<script><!--#include virtual="/config.js" --></script><!-- adapt to your needs, i.e. set hosts and bosh path -->
<script><!--#include virtual="/interface_config.js" --></script>
<script src="libs/lib-jitsi-meet.min.js?v=139"></script>
<script src="libs/react.min.js?v=139"></script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this defeat the purpose of bundling it out, if we are going to load it at the start all the same?

Copy link
Author

@catFurr catFurr Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The react and vendor scripts are cached separately by the browser. So if we change our app code, browsers can reuse those (only app.bundle will be fetched).

We should only increment the ?v number for react and vendor if the package-lock.json file changes.

Stuff like excalidraw and rnnoise are still lazy loaded when needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@damencho Do you foresee a problem here? Any of our deployment scripts will need an update?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well here at build time we put the jitsi-meet new version and on our deployments we always use base url. So that will be updated with the packages. I don't see a reason to handle it differently than the app bundle.
There is no point of following package-lock file, as that is always changed between stable versions and so on.

<script src="libs/vendor.min.js?v=139"></script>
<script src="libs/app.bundle.min.js?v=139"></script>
<!--#include virtual="title.html" -->
<!--#include virtual="plugin.head.html" -->
Expand Down
2 changes: 1 addition & 1 deletion react/features/app/actions.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
dispatch(clearNotifications());

if (!options.hidePrejoin && isPrejoinPageEnabled(getState())) {
if (isUnsafeRoomWarningEnabled(getState()) && isInsecureRoomName(room)) {
if (isUnsafeRoomWarningEnabled(getState()) && await isInsecureRoomName(room)) {
navigateRoot(screen.unsafeRoomWarning);
} else {
navigateRoot(screen.preJoin);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,13 @@ function _checkRoomName(roomName = '') {
* Returns true if the room name is considered a weak (insecure) one.
*
* @param {string} roomName - The room name.
* @returns {boolean}
* @returns {Promise<boolean>}
*/
export default function isInsecureRoomName(roomName = ''): boolean {
export default async function isInsecureRoomName(roomName = ''): Promise<boolean> {
// Note: This function returns a Promise to maintain compatibility with the web implementation.
// The web version needs to be async because it dynamically imports the zxcvbn library for code splitting.
// While the native version can use zxcvbn synchronously, both implementations must share the same
// Promise-based interface so AbstractWelcomePage can use them interchangeably.

// room names longer than 200 chars we consider secure
return !isValidUUID(roomName) && (roomName.length < 200 && _checkRoomName(roomName).score < 3);
Expand Down
75 changes: 75 additions & 0 deletions react/features/base/util/isInsecureRoomName.web.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { isEqual } from 'lodash-es';
import { NIL, parse as parseUUID } from 'uuid';

// The null UUID.
const NIL_UUID = parseUUID(NIL);

const _zxcvbnCache = new Map();
let _zxcvbnPromise: Promise<any> | null = null;

/**
* Checks if the given string is a valid UUID or not.
*
* @param {string} str - The string to be checked.
* @returns {boolean} - Whether the string is a valid UUID or not.
*/
function isValidUUID(str: string) {
let uuid;

try {
uuid = parseUUID(str);
} catch (e) {
return false;
}

return !isEqual(uuid, NIL_UUID);
}

/**
* Dynamically imports zxcvbn library.
*
* @returns {Promise} - Promise that resolves to zxcvbn module.
*/
function _getZxcvbn() {
if (!_zxcvbnPromise) {
_zxcvbnPromise = import(/* webpackChunkName: "zxcvbn" */ 'zxcvbn').then(module => module.default);
}

return _zxcvbnPromise;
}

/**
* Checks a room name and caches the result.
*
* @param {string} roomName - The room name.
* @returns {Promise<Object>} - Promise that resolves to zxcvbn result.
*/
async function _checkRoomName(roomName = '') {
if (_zxcvbnCache.has(roomName)) {
return _zxcvbnCache.get(roomName);
}

const zxcvbn = await _getZxcvbn();
const result = zxcvbn(roomName);

_zxcvbnCache.set(roomName, result);

return result;
}

/**
* Returns true if the room name is considered a weak (insecure) one.
*
* @param {string} roomName - The room name.
* @returns {Promise<boolean>} - Promise that resolves to boolean.
*/
export default async function isInsecureRoomName(roomName = ''): Promise<boolean> {
// room names longer than 200 chars we consider secure
if (isValidUUID(roomName) || roomName.length >= 200) {
return false;
}

const result = await _checkRoomName(roomName);

return result.score < 3;
}
43 changes: 43 additions & 0 deletions react/features/base/util/useInsecureRoomName.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, useState } from 'react';

import isInsecureRoomName from './isInsecureRoomName';

/**
* Custom hook to check if a room name is insecure asynchronously.
*
* @param {string} roomName - The room name to check.
* @param {boolean} enabled - Whether the check should be performed.
* @returns {boolean} - Whether the room name is insecure.
*/
export default function useInsecureRoomName(roomName: string, enabled: boolean): boolean {
const [ isInsecure, setIsInsecure ] = useState(false);

useEffect(() => {
if (!enabled || !roomName) {
setIsInsecure(false);

return;
}

let isMounted = true;

isInsecureRoomName(roomName)
.then(result => {
if (isMounted) {
setIsInsecure(result);
}
})
.catch(() => {
// If zxcvbn fails to load, assume room is secure
if (isMounted) {
setIsInsecure(false);
}
});

return () => {
isMounted = false;
};
}, [ roomName, enabled ]);

return isInsecure;
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,46 @@ import { connect } from 'react-redux';
import { translate } from '../../../base/i18n/functions';
import { IconWarning } from '../../../base/icons/svg';
import Label from '../../../base/label/components/native/Label';
import AbstractInsecureRoomNameLabel, { _mapStateToProps } from '../AbstractInsecureRoomNameLabel';
import useInsecureRoomName from '../../../base/util/useInsecureRoomName';
import { isUnsafeRoomWarningEnabled } from '../../../prejoin/functions.native';

import styles from './styles';

interface IProps {
room: string | undefined;
t: Function;
unsafeRoomWarningEnabled: boolean;
}

/**
* Renders a label indicating that we are in a room with an insecure name.
*
* @returns {JSX.Element|null} The insecure room name label component or null if not insecure.
*/
class InsecureRoomNameLabel extends AbstractInsecureRoomNameLabel {
/**
* Renders the platform dependent content.
*
* @inheritdoc
*/
_render() {
return (
<Label
icon = { IconWarning }
style = { styles.insecureRoomNameLabel } />
);
function InsecureRoomNameLabel({ room, unsafeRoomWarningEnabled, t: _t }: IProps) {
const isInsecure = useInsecureRoomName(room || '', unsafeRoomWarningEnabled);

if (!isInsecure) {
return null;
}

return (
<Label
icon = { IconWarning }
style = { styles.insecureRoomNameLabel } />
);
}

function mapStateToProps(state: any) {
const { locked, room } = state['features/base/conference'];
const { lobbyEnabled } = state['features/lobby'];

return {
room,
unsafeRoomWarningEnabled: Boolean(isUnsafeRoomWarningEnabled(state)
&& room
&& !(lobbyEnabled || Boolean(locked)))
};
}

export default translate(connect(_mapStateToProps)(InsecureRoomNameLabel));
export default translate(connect(mapStateToProps)(InsecureRoomNameLabel));
56 changes: 38 additions & 18 deletions react/features/conference/components/web/InsecureRoomNameLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,48 @@ import Label from '../../../base/label/components/web/Label';
import { COLORS } from '../../../base/label/constants';
import Tooltip from '../../../base/tooltip/components/Tooltip';
import getUnsafeRoomText from '../../../base/util/getUnsafeRoomText.web';
import AbstractInsecureRoomNameLabel, { _mapStateToProps } from '../AbstractInsecureRoomNameLabel';
import useInsecureRoomName from '../../../base/util/useInsecureRoomName';
import { isUnsafeRoomWarningEnabled } from '../../../prejoin/functions.web';

interface IProps {
room: string | undefined;
t: Function;
unsafeRoomWarningEnabled: boolean;
}

/**
* Renders a label indicating that we are in a room with an insecure name.
*
* @returns {JSX.Element|null} The insecure room name label component or null if not insecure.
*/
class InsecureRoomNameLabel extends AbstractInsecureRoomNameLabel {
/**
* Renders the platform dependent content.
*
* @inheritdoc
*/
override _render() {
return (
<Tooltip
content = { getUnsafeRoomText(this.props.t, 'meeting') }
position = 'bottom'>
<Label
color = { COLORS.red }
icon = { IconExclamationTriangle } />
</Tooltip>
);
function InsecureRoomNameLabel({ room, unsafeRoomWarningEnabled, t }: IProps) {
const isInsecure = useInsecureRoomName(room || '', unsafeRoomWarningEnabled);

if (!isInsecure) {
return null;
}

return (
<Tooltip
content = { getUnsafeRoomText(t, 'meeting') }
position = 'bottom'>
<Label
color = { COLORS.red }
icon = { IconExclamationTriangle } />
</Tooltip>
);
}

function mapStateToProps(state: any) {
const { locked, room } = state['features/base/conference'];
const { lobbyEnabled } = state['features/lobby'];

return {
room,
unsafeRoomWarningEnabled: Boolean(isUnsafeRoomWarningEnabled(state)
&& room
&& !(lobbyEnabled || Boolean(locked)))
};
}

export default translate(connect(_mapStateToProps)(InsecureRoomNameLabel));
export default translate(connect(mapStateToProps)(InsecureRoomNameLabel));
Loading
Loading