Compare commits

...

6 Commits

Author SHA1 Message Date
Дамян Минков
6aba231783 feat(tests): Adds dialIn expectation to disable more numbers page. (#17109)
* feat(tests): Adds dialIn expectation to disable more numbers page.

* squash: Cleaup.

---------

Co-authored-by: Boris Grozev <boris@jitsi.org>
2026-03-09 13:59:18 -05:00
damencho
052024e3b7 fix(etherpad): Checks the received command value. 2026-03-09 12:50:54 -05:00
Solomon
eeb80fddf7 fix(UI): Mirrors Virtual Background previews (#17090)
* fix(vb-preview mirror):

Add flipVideoX CSS class to VirtualBackgroundPreview component

Fixes: #17089

* Update VirtualBackgroundPreview.tsx

Fixed the Lint errors
2026-03-09 13:23:05 -04:00
damencho
5c1c00615f fix(auth_ban): Simplifies jaas test.
Checks tenant for magic cookie, fixes first check when room does not exist.
2026-03-09 12:16:53 -05:00
Vishal Malyan
c3e442f160 fix(ui): update Switch callback deps to prevent stale toggle handler for E2EE 2026-03-09 10:22:29 -04:00
Aaron van Meerten
6f8414e67f fix(base/util): prevent double URL encoding of non-ASCII room names
Room names with non-ASCII characters (e.g. ò) were double URL-encoded
when appended as query parameters to websocket, conference-request, and
keepalive URLs. getBackendSafeRoomName() returns a percent-encoded string
which was then re-encoded by URLSearchParams.append() via appendURLParam().

Extract getNormalizedRoomName() that decodes, NFKC-normalizes, and
lowercases without percent-encoding, and use it in the appendURLParam
call sites. getBackendSafeRoomName() is refactored to call it internally,
preserving identical behavior for all other callers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 08:22:22 -05:00
11 changed files with 57 additions and 28 deletions

View File

@@ -18,7 +18,7 @@ import isInsecureRoomName from '../base/util/isInsecureRoomName';
import { parseURLParams } from '../base/util/parseURLParams';
import {
appendURLParam,
getBackendSafeRoomName,
getNormalizedRoomName,
parseURIString,
toURLString
} from '../base/util/uri';
@@ -110,7 +110,7 @@ export function appNavigate(uri?: string, options: IReloadNowOptions = {}) {
let url = `${baseURL}config.js`;
// XXX In order to support multiple shards, tell the room to the deployment.
room && (url = appendURLParam(url, 'room', getBackendSafeRoomName(room) ?? ''));
room && (url = appendURLParam(url, 'room', getNormalizedRoomName(room) ?? ''));
const { release } = parseURLParams(location, true, 'search');

View File

@@ -9,7 +9,8 @@ import { isEmbedded } from '../util/embedUtils';
import { parseURLParams } from '../util/parseURLParams';
import {
appendURLParam,
getBackendSafeRoomName
getBackendSafeRoomName,
getNormalizedRoomName
} from '../util/uri';
import {
@@ -142,7 +143,7 @@ export function constructOptions(state: IReduxState) {
const { room } = state['features/base/conference'];
if (serviceUrl && room) {
const roomName = getBackendSafeRoomName(room);
const roomName = getNormalizedRoomName(room);
options.serviceUrl = appendURLParam(serviceUrl, 'room', roomName ?? '');

View File

@@ -116,7 +116,7 @@ const Switch = ({ className, id, checked, disabled, onChange }: IProps) => {
const change = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
onChange(e.target.checked);
}, []);
}, [ onChange ]);
return (
<span

View File

@@ -134,12 +134,13 @@ export function getBackendSafePath(path?: string): string | undefined {
}
/**
* Converts a room name to a backend-safe format. Properly lowercased and url encoded.
* Decodes, NFKC-normalizes, and lowercases a room name without percent-encoding the result.
* Use this when the result will be passed to an API (e.g. URLSearchParams) that encodes automatically.
*
* @param {string?} room - The room name to convert.
* @param {string?} room - The room name to normalize.
* @returns {string?}
*/
export function getBackendSafeRoomName(room?: string): string | undefined {
export function getNormalizedRoomName(room?: string): string | undefined {
if (!room) {
return room;
}
@@ -162,16 +163,27 @@ export function getBackendSafeRoomName(room?: string): string | undefined {
// Only decoded and normalized strings can be lowercased properly.
room = room?.toLowerCase();
// But we still need to (re)encode it.
room = encodeURIComponent(room ?? '');
/* eslint-enable no-param-reassign */
// Unfortunately we still need to lowercase it, because encoding a string will
// add some uppercase characters, but some backend services
// expect it to be full lowercase. However lowercasing an encoded string
// doesn't change the string value.
return room.toLowerCase();
return room;
}
/**
* Converts a room name to a backend-safe format. Properly lowercased and url encoded.
*
* @param {string?} room - The room name to convert.
* @returns {string?}
*/
export function getBackendSafeRoomName(room?: string): string | undefined {
const normalized = getNormalizedRoomName(room);
if (!normalized) {
return normalized;
}
// Lowercase again after encoding because encodeURIComponent produces uppercase hex digits,
// but some backend services expect fully lowercase encoded strings.
return encodeURIComponent(normalized).toLowerCase();
}
/**

View File

@@ -0,0 +1,3 @@
import { getLogger } from '../base/logging/functions';
export default getLogger('app:etherpad');

View File

@@ -1,3 +1,5 @@
import { sanitizeUrl as _sanitizePath } from '@braintree/sanitize-url';
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
import { getCurrentConference } from '../base/conference/functions';
import MiddlewareRegistry from '../base/redux/MiddlewareRegistry';
@@ -6,6 +8,7 @@ import { sanitizeUrl } from '../base/util/uri';
import { TOGGLE_DOCUMENT_EDITING } from './actionTypes';
import { setDocumentUrl } from './actions';
import logger from './logger';
const ETHERPAD_COMMAND = 'etherpad';
@@ -28,6 +31,16 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
const { etherpad_base: etherpadBase } = getState()['features/base/config'];
const etherpadBaseUrl = sanitizeUrl(etherpadBase);
try {
new URL(_sanitizePath(value));
logger.warn(`Received suspicious value for etherpad command: ${value}`);
return;
} catch (e) {
// we should receive a relative path for the URL and should not be able to construct a url from it
}
if (etherpadBaseUrl) {
const urlObj = new URL(value, etherpadBaseUrl.toString());

View File

@@ -1,4 +1,5 @@
import { Theme } from '@mui/material';
import cx from 'classnames';
import React, { PureComponent } from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
@@ -16,7 +17,6 @@ import { NOTIFICATION_TIMEOUT_TYPE } from '../../notifications/constants';
import { toggleBackgroundEffect } from '../actions';
import logger from '../logger';
import { IVirtualBackground } from '../reducer';
/**
* The type of the React {@code PureComponent} props of {@link VirtualBackgroundPreview}.
*/
@@ -243,7 +243,7 @@ class VirtualBackgroundPreview extends PureComponent<IProps, IState> {
return (
<Video
className = { classes.previewVideo }
className = { cx(classes.previewVideo, 'flipVideoX') }
id = 'virtual_background_preview'
playsinline = { true }
videoTrack = {{ jitsiTrack: data }} />

View File

@@ -12,8 +12,7 @@ local http = require "net.http";
local inspect = require 'inspect';
local util = module:require 'util';
local get_room_by_name_and_subdomain = util.get_room_by_name_and_subdomain;
local is_vpaas = util.is_vpaas;
local starts_with = util.starts_with;
local ban_check_count = module:measure("muc_auth_ban_check", "rate")
local ban_check_users_banned_count = module:measure("muc_auth_ban_users_banned", "rate")
@@ -49,11 +48,7 @@ local function shouldAllow(session)
return false;
end
local room = get_room_by_name_and_subdomain(session.jitsi_web_query_room, session.jitsi_web_query_prefix);
if not room then
return nil;
end
if not is_vpaas(room) then
if not starts_with(session.jitsi_web_query_prefix, 'vpaas-magic-cookie-') then
return true;
end

View File

@@ -12,7 +12,10 @@ const defaultExpectations = {
* null -> if the config is enabled, assert the UI elements are displayed and the feature works.
*/
enabled: null,
minPinLength: 8
minPinLength: 8,
/* Whether to verify that the "more numbers" page is displayed. Note that only the positive verification is
performed: when set to 'false' we do not assert that the "more numbers" page is not displayed. */
moreNumbersPage: true
},
iframe: {
// Whether the iframe integration is enabled (the inverse of `disableIframeAPI` from config.js)

View File

@@ -48,7 +48,7 @@ describe('Dial-in', () => {
if (expectations.dialIn.enabled !== null) {
await assertDialInDisplayed(p1, expectations.dialIn.enabled);
}
if (expectations.dialIn.enabled === true) {
if (expectations.dialIn.moreNumbersPage) {
// TODO: assert the page is NOT shown when the expectation is false.
await verifyMoreNumbersPage(p1);
}

View File

@@ -72,7 +72,9 @@ describe('Dial-in', () => {
it('view more numbers page', async () => {
await verifyMoreNumbersPage(ctx.p1);
if (expectations.dialIn.moreNumbersPage) {
await verifyMoreNumbersPage(ctx.p1);
}
});
it('retrieve pin', async () => {