init
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
2025-09-02 14:49:16 +08:00
commit 38ba663466
2885 changed files with 391107 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
import React from 'react';
import { WithTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { IReduxState } from '../../app/types';
import { translate } from '../../base/i18n/functions';
import { IconE2EE } from '../../base/icons/svg';
import Label from '../../base/label/components/web/Label';
import { COLORS } from '../../base/label/constants';
import Tooltip from '../../base/tooltip/components/Tooltip';
export interface IProps extends WithTranslation {
/**
* Custom e2ee labels.
*/
_e2eeLabels?: any;
/**
* True if the label needs to be rendered, false otherwise.
*/
_showLabel?: boolean;
}
const E2EELabel = ({ _e2eeLabels, _showLabel, t }: IProps) => {
if (!_showLabel) {
return null;
}
const content = _e2eeLabels?.tooltip || t('e2ee.labelToolTip');
return (
<Tooltip
content = { content }
position = { 'bottom' }>
<Label
color = { COLORS.green }
icon = { IconE2EE } />
</Tooltip>
);
};
/**
* Maps (parts of) the redux state to the associated props of this {@code Component}.
*
* @param {Object} state - The redux state.
* @private
* @returns {IProps}
*/
export function _mapStateToProps(state: IReduxState) {
const { e2ee = {} } = state['features/base/config'];
return {
_e2eeLabels: e2ee.labels,
_showLabel: state['features/base/participants'].numberOfParticipantsDisabledE2EE === 0
};
}
export default translate(connect(_mapStateToProps)(E2EELabel));

View File

@@ -0,0 +1,174 @@
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { createE2EEEvent } from '../../analytics/AnalyticsEvents';
import { sendAnalytics } from '../../analytics/functions';
import { IReduxState, IStore } from '../../app/types';
import Switch from '../../base/ui/components/web/Switch';
import { toggleE2EE } from '../actions';
import { MAX_MODE } from '../constants';
import { doesEveryoneSupportE2EE } from '../functions';
interface IProps {
/**
* The resource for the description, computed based on the maxMode and whether the switch is toggled or not.
*/
_descriptionResource?: string;
/**
* Custom e2ee labels.
*/
_e2eeLabels: any;
/**
* Whether the switch is currently enabled or not.
*/
_enabled: boolean;
/**
* Indicates whether all participants in the conference currently support E2EE.
*/
_everyoneSupportE2EE: boolean;
/**
* Whether E2EE is currently enabled or not.
*/
_toggled: boolean;
/**
* The redux {@code dispatch} function.
*/
dispatch: IStore['dispatch'];
}
const useStyles = makeStyles()(() => {
return {
e2eeSection: {
display: 'flex',
flexDirection: 'column'
},
description: {
fontSize: '0.875rem',
margin: '15px 0'
},
controlRow: {
display: 'flex',
justifyContent: 'space-between',
marginTop: '15px',
'& label': {
fontSize: '0.875rem',
fontWeight: 'bold'
}
}
};
});
/**
* Implements a React {@code Component} for displaying a security dialog section with a field
* for setting the E2EE key.
*
* @param {IProps} props - Component's props.
* @returns {JSX}
*/
const E2EESection = ({
_descriptionResource,
_enabled,
_e2eeLabels,
_everyoneSupportE2EE,
_toggled,
dispatch
}: IProps) => {
const { classes } = useStyles();
const { t } = useTranslation();
const [ toggled, setToggled ] = useState(_toggled ?? false);
useEffect(() => {
setToggled(_toggled);
}, [ _toggled ]);
/**
* Callback to be invoked when the user toggles E2EE on or off.
*
* @private
* @returns {void}
*/
const _onToggle = useCallback(() => {
const newValue = !toggled;
setToggled(newValue);
sendAnalytics(createE2EEEvent(`enabled.${String(newValue)}`));
dispatch(toggleE2EE(newValue));
}, [ toggled ]);
const description = _e2eeLabels?.description || t(_descriptionResource ?? '');
const label = _e2eeLabels?.label || t('dialog.e2eeLabel');
const warning = _e2eeLabels?.warning || t('dialog.e2eeWarning');
return (
<div
className = { classes.e2eeSection }
id = 'e2ee-section'>
<p
aria-live = 'polite'
className = { classes.description }
id = 'e2ee-section-description'>
{description}
{!_everyoneSupportE2EE && <br />}
{!_everyoneSupportE2EE && warning}
</p>
<div className = { classes.controlRow }>
<label htmlFor = 'e2ee-section-switch'>
{label}
</label>
<Switch
checked = { toggled }
disabled = { !_enabled }
id = 'e2ee-section-switch'
onChange = { _onToggle } />
</div>
</div>
);
};
/**
* Maps (parts of) the Redux state to the associated props for this component.
*
* @param {Object} state - The Redux state.
* @private
* @returns {IProps}
*/
function mapStateToProps(state: IReduxState) {
const { enabled: e2eeEnabled, maxMode } = state['features/e2ee'];
const { e2ee = {} } = state['features/base/config'];
let descriptionResource: string | undefined = '';
if (e2ee.labels) {
// When e2eeLabels are present, the description resource is ignored.
descriptionResource = undefined;
} else if (maxMode === MAX_MODE.THRESHOLD_EXCEEDED) {
descriptionResource = 'dialog.e2eeDisabledDueToMaxModeDescription';
} else if (maxMode === MAX_MODE.ENABLED) {
descriptionResource = e2eeEnabled
? 'dialog.e2eeWillDisableDueToMaxModeDescription' : 'dialog.e2eeDisabledDueToMaxModeDescription';
} else {
descriptionResource = 'dialog.e2eeDescription';
}
return {
_descriptionResource: descriptionResource,
_e2eeLabels: e2ee.labels,
_enabled: maxMode === MAX_MODE.DISABLED || e2eeEnabled,
_toggled: e2eeEnabled,
_everyoneSupportE2EE: Boolean(doesEveryoneSupportE2EE(state))
};
}
export default connect(mapStateToProps)(E2EESection);

View File

@@ -0,0 +1,123 @@
import React, { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { makeStyles } from 'tss-react/mui';
import { IReduxState, IStore } from '../../app/types';
import { getParticipantById } from '../../base/participants/functions';
import Dialog from '../../base/ui/components/web/Dialog';
import { participantVerified } from '../actions';
import { ISas } from '../reducer';
interface IProps {
decimal: string;
dispatch: IStore['dispatch'];
emoji: string;
pId: string;
participantName?: string;
sas: ISas;
}
const useStyles = makeStyles()(() => {
return {
container: {
display: 'flex',
flexDirection: 'column',
margin: '16px'
},
row: {
alignSelf: 'center',
display: 'flex'
},
item: {
textAlign: 'center',
margin: '16px'
},
emoji: {
fontSize: '2.5rem',
margin: '12px'
}
};
});
const ParticipantVerificationDialog = ({
dispatch,
participantName,
pId,
sas
}: IProps) => {
const { classes } = useStyles();
const { t } = useTranslation();
const _onDismissed = useCallback(() => {
dispatch(participantVerified(pId, false));
return true;
}, [ pId ]);
const _onConfirmed = useCallback(() => {
dispatch(participantVerified(pId, true));
return true;
}, [ pId ]);
const { emoji } = sas;
return (
<Dialog
cancel = {{ translationKey: 'dialog.verifyParticipantDismiss' }}
ok = {{ translationKey: 'dialog.verifyParticipantConfirm' }}
onCancel = { _onDismissed }
onSubmit = { _onConfirmed }
titleKey = 'dialog.verifyParticipantTitle'>
<div>
{t('dialog.verifyParticipantQuestion', { participantName })}
</div>
<div className = { classes.container }>
<div className = { classes.row }>
{/* @ts-ignore */}
{emoji.slice(0, 4).map((e: Array<string>) =>
(<div
className = { classes.item }
key = { e.toString() }>
<div className = { classes.emoji }>{e[0]}</div>
<div>{e[1].charAt(0).toUpperCase() + e[1].slice(1)}</div>
</div>))}
</div>
<div className = { classes.row }>
{/* @ts-ignore */}
{emoji.slice(4, 7).map((e: Array<string>) =>
(<div
className = { classes.item }
key = { e.toString() }>
<div className = { classes.emoji }>{e[0]} </div>
<div>{e[1].charAt(0).toUpperCase() + e[1].slice(1)}</div>
</div>))}
</div>
</div>
</Dialog>
);
};
/**
* Maps part of the Redux store to the props of this component.
*
* @param {IReduxState} state - The Redux state.
* @param {IProps} ownProps - The own props of the component.
* @returns {IProps}
*/
export function _mapStateToProps(state: IReduxState, ownProps: IProps) {
const participant = getParticipantById(state, ownProps.pId);
return {
sas: ownProps.sas,
pId: ownProps.pId,
participantName: participant?.name
};
}
export default connect(_mapStateToProps)(ParticipantVerificationDialog);