"Fossies" - the Fresh Open Source Software Archive 
Member "jitsi-meet-7319/react/features/security/components/security-dialog/web/PasswordSection.tsx" (6 Jun 2023, 11467 Bytes) of package /linux/misc/jitsi-meet-7319.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TSX (TypeScript with React) source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the last
Fossies "Diffs" side-by-side code changes report for "PasswordSection.tsx":
jitsi-meet_8319_vs_jitsi-meet_8615.
1 /* eslint-disable react/jsx-no-bind */
2 import React, { useRef, useState } from 'react';
3 import { WithTranslation } from 'react-i18next';
4
5 import { translate } from '../../../../base/i18n/functions';
6 import { copyText } from '../../../../base/util/copyText.web';
7 import { LOCKED_LOCALLY } from '../../../../room-lock/constants';
8 import { NOTIFY_CLICK_MODE } from '../../../../toolbox/constants';
9
10 import PasswordForm from './PasswordForm';
11 import { INotifyClick } from './SecurityDialog';
12
13 const DIGITS_ONLY = /^\d+$/;
14 const KEY = 'add-passcode';
15
16 interface IProps extends WithTranslation {
17
18 /**
19 * Toolbar buttons which have their click exposed through the API.
20 */
21 buttonsWithNotifyClick: Array<string | INotifyClick>;
22
23 /**
24 * Whether or not the current user can modify the current password.
25 */
26 canEditPassword: boolean;
27
28 /**
29 * The JitsiConference for which to display a lock state and change the
30 * password.
31 */
32 conference: any;
33
34 /**
35 * The value for how the conference is locked (or undefined if not locked)
36 * as defined by room-lock constants.
37 */
38 locked?: string;
39
40 /**
41 * The current known password for the JitsiConference.
42 */
43 password?: string;
44
45 /**
46 * Whether or not to show the password in editing mode.
47 */
48 passwordEditEnabled: boolean;
49
50 /**
51 * The number of digits to be used in the password.
52 */
53 passwordNumberOfDigits?: number;
54
55 /**
56 * Action that sets the conference password.
57 */
58 setPassword: Function;
59
60 /**
61 * Method that sets whether the password editing is enabled or not.
62 */
63 setPasswordEditEnabled: Function;
64 }
65
66 /**
67 * Component that handles the password manipulation from the invite dialog.
68 *
69 * @returns {React$Element<any>}
70 */
71 function PasswordSection({
72 buttonsWithNotifyClick,
73 canEditPassword,
74 conference,
75 locked,
76 password,
77 passwordEditEnabled,
78 passwordNumberOfDigits,
79 setPassword,
80 setPasswordEditEnabled,
81 t }: IProps) {
82
83 const formRef = useRef<HTMLDivElement>(null);
84 const [ passwordVisible, setPasswordVisible ] = useState(false);
85
86 /**
87 * Callback invoked to set a password on the current JitsiConference.
88 *
89 * @param {string} enteredPassword - The new password to be used to lock the
90 * current JitsiConference.
91 * @private
92 * @returns {void}
93 */
94 function onPasswordSubmit(enteredPassword: string) {
95 if (enteredPassword && passwordNumberOfDigits && !DIGITS_ONLY.test(enteredPassword)) {
96 // Don't set the password.
97 return;
98 }
99 setPassword(conference, conference.lock, enteredPassword);
100 }
101
102 /**
103 * Toggles whether or not the password should currently be shown as being
104 * edited locally.
105 *
106 * @private
107 * @returns {void}
108 */
109 function onTogglePasswordEditState() {
110 if (typeof APP === 'undefined' || !buttonsWithNotifyClick?.length) {
111 setPasswordEditEnabled(!passwordEditEnabled);
112
113 return;
114 }
115
116 let notifyMode;
117 const notify = buttonsWithNotifyClick.find(
118 (btn: string | INotifyClick) =>
119 (typeof btn === 'string' && btn === KEY)
120 || (typeof btn === 'object' && btn.key === KEY)
121 );
122
123 if (notify) {
124 notifyMode = typeof notify === 'string' || notify.preventExecution
125 ? NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
126 : NOTIFY_CLICK_MODE.ONLY_NOTIFY;
127 APP.API.notifyToolbarButtonClicked(
128 KEY, notifyMode === NOTIFY_CLICK_MODE.PREVENT_AND_NOTIFY
129 );
130 }
131
132 if (notifyMode === NOTIFY_CLICK_MODE.ONLY_NOTIFY) {
133 setPasswordEditEnabled(!passwordEditEnabled);
134 }
135 }
136
137 /**
138 * Method to remotely submit the password from outside of the password form.
139 *
140 * @returns {void}
141 */
142 function onPasswordSave() {
143 if (formRef.current) {
144 // @ts-ignore
145 const { value } = formRef.current.querySelector('div > input');
146
147 if (value) {
148 onPasswordSubmit(value);
149 }
150 }
151 }
152
153 /**
154 * Callback invoked to unlock the current JitsiConference.
155 *
156 * @returns {void}
157 */
158 function onPasswordRemove() {
159 onPasswordSubmit('');
160 }
161
162 /**
163 * Copies the password to the clipboard.
164 *
165 * @returns {void}
166 */
167 function onPasswordCopy() {
168 copyText(password ?? '');
169 }
170
171 /**
172 * Toggles whether or not the password should currently be shown as being
173 * edited locally.
174 *
175 * @param {Object} e - The key event to handle.
176 *
177 * @private
178 * @returns {void}
179 */
180 function onTogglePasswordEditStateKeyPressHandler(e: React.KeyboardEvent) {
181 if (e.key === ' ' || e.key === 'Enter') {
182 e.preventDefault();
183 onTogglePasswordEditState();
184 }
185 }
186
187 /**
188 * Method to remotely submit the password from outside of the password form.
189 *
190 * @param {Object} e - The key event to handle.
191 *
192 * @private
193 * @returns {void}
194 */
195 function onPasswordSaveKeyPressHandler(e: React.KeyboardEvent) {
196 if (e.key === ' ' || e.key === 'Enter') {
197 e.preventDefault();
198 onPasswordSave();
199 }
200 }
201
202 /**
203 * Callback invoked to unlock the current JitsiConference.
204 *
205 * @param {Object} e - The key event to handle.
206 *
207 * @private
208 * @returns {void}
209 */
210 function onPasswordRemoveKeyPressHandler(e: React.KeyboardEvent) {
211 if (e.key === ' ' || e.key === 'Enter') {
212 e.preventDefault();
213 onPasswordRemove();
214 }
215 }
216
217 /**
218 * Copies the password to the clipboard.
219 *
220 * @param {Object} e - The key event to handle.
221 *
222 * @private
223 * @returns {void}
224 */
225 function onPasswordCopyKeyPressHandler(e: React.KeyboardEvent) {
226 if (e.key === ' ' || e.key === 'Enter') {
227 e.preventDefault();
228 onPasswordCopy();
229 }
230 }
231
232 /**
233 * Callback invoked to show the current password.
234 *
235 * @returns {void}
236 */
237 function onPasswordShow() {
238 setPasswordVisible(true);
239 }
240
241 /**
242 * Callback invoked to show the current password.
243 *
244 * @param {Object} e - The key event to handle.
245 *
246 * @returns {void}
247 */
248 function onPasswordShowKeyPressHandler(e: React.KeyboardEvent) {
249 if (e.key === ' ' || e.key === 'Enter') {
250 e.preventDefault();
251 setPasswordVisible(true);
252 }
253 }
254
255 /**
256 * Callback invoked to hide the current password.
257 *
258 * @returns {void}
259 */
260 function onPasswordHide() {
261 setPasswordVisible(false);
262 }
263
264 /**
265 * Callback invoked to hide the current password.
266 *
267 * @param {Object} e - The key event to handle.
268 *
269 * @returns {void}
270 */
271 function onPasswordHideKeyPressHandler(e: React.KeyboardEvent) {
272 if (e.key === ' ' || e.key === 'Enter') {
273 e.preventDefault();
274 setPasswordVisible(false);
275 }
276 }
277
278 /**
279 * Method that renders the password action(s) based on the current
280 * locked-status of the conference.
281 *
282 * @returns {React$Element<any>}
283 */
284 function renderPasswordActions() {
285 if (!canEditPassword) {
286 return null;
287 }
288
289 if (passwordEditEnabled) {
290 return (
291 <>
292 <a
293 aria-label = { t('dialog.Cancel') }
294 onClick = { onTogglePasswordEditState }
295 onKeyPress = { onTogglePasswordEditStateKeyPressHandler }
296 role = 'button'
297 tabIndex = { 0 }>{ t('dialog.Cancel') }</a>
298 <a
299 aria-label = { t('dialog.add') }
300 onClick = { onPasswordSave }
301 onKeyPress = { onPasswordSaveKeyPressHandler }
302 role = 'button'
303 tabIndex = { 0 }>{ t('dialog.add') }</a>
304 </>
305 );
306 }
307
308 if (locked) {
309 return (
310 <>
311 <a
312 aria-label = { t('dialog.Remove') }
313 className = 'remove-password'
314 onClick = { onPasswordRemove }
315 onKeyPress = { onPasswordRemoveKeyPressHandler }
316 role = 'button'
317 tabIndex = { 0 }>{ t('dialog.Remove') }</a>
318 {
319
320 // There are cases like lobby and grant moderator when password is not available
321 password ? <>
322 <a
323 aria-label = { t('dialog.copy') }
324 className = 'copy-password'
325 onClick = { onPasswordCopy }
326 onKeyPress = { onPasswordCopyKeyPressHandler }
327 role = 'button'
328 tabIndex = { 0 }>{ t('dialog.copy') }</a>
329 </> : null
330 }
331 {locked === LOCKED_LOCALLY && (
332 <a
333 aria-label = { t(passwordVisible ? 'dialog.hide' : 'dialog.show') }
334 onClick = { passwordVisible ? onPasswordHide : onPasswordShow }
335 onKeyPress = { passwordVisible
336 ? onPasswordHideKeyPressHandler
337 : onPasswordShowKeyPressHandler
338 }
339 role = 'button'
340 tabIndex = { 0 }>{t(passwordVisible ? 'dialog.hide' : 'dialog.show')}</a>
341 )}
342 </>
343 );
344 }
345
346 return (
347 <a
348 aria-label = { t('info.addPassword') }
349 className = 'add-password'
350 onClick = { onTogglePasswordEditState }
351 onKeyPress = { onTogglePasswordEditStateKeyPressHandler }
352 role = 'button'
353 tabIndex = { 0 }>{ t('info.addPassword') }</a>
354 );
355 }
356
357 return (
358 <div className = 'security-dialog password-section'>
359 <p className = 'description'>
360 { t(canEditPassword ? 'security.about' : 'security.aboutReadOnly') }
361 </p>
362 <div className = 'security-dialog password'>
363 <div
364 className = 'info-dialog info-dialog-column info-dialog-password'
365 ref = { formRef }>
366 <PasswordForm
367 editEnabled = { passwordEditEnabled }
368 locked = { locked }
369 onSubmit = { onPasswordSubmit }
370 password = { password }
371 passwordNumberOfDigits = { passwordNumberOfDigits }
372 visible = { passwordVisible } />
373 </div>
374 <div className = 'security-dialog password-actions'>
375 { renderPasswordActions() }
376 </div>
377 </div>
378 </div>
379 );
380 }
381
382 export default translate(PasswordSection);