mirror of
				https://gitlab.com/comunic/comunicconsole
				synced 2025-10-31 10:14:42 +00:00 
			
		
		
		
	Add support for security keys password
This commit is contained in:
		| @@ -15,10 +15,12 @@ export interface AdminAccountKey { | ||||
| 	id: number; | ||||
| 	name: string; | ||||
| 	time_add: number; | ||||
| 	has_password: boolean; | ||||
| } | ||||
| export interface AuthKey { | ||||
| 	name: string; | ||||
| 	id: number; | ||||
| 	password: boolean; | ||||
| } | ||||
|  | ||||
| export class AdminKeyHelper { | ||||
| @@ -42,8 +44,13 @@ export class AdminKeyHelper { | ||||
| 	 * | ||||
| 	 * @param name The name of the key to create | ||||
| 	 * @param cred The credentials to register | ||||
| 	 * @param password The password required to use the key | ||||
| 	 */ | ||||
| 	static async RegisterKey(name: string, cred: any): Promise<void> { | ||||
| 	static async RegisterKey( | ||||
| 		name: string, | ||||
| 		cred: any, | ||||
| 		password: string | ||||
| 	): Promise<void> { | ||||
| 		const res = { | ||||
| 			id: cred.id, | ||||
| 			rawId: ArrayBufferToBase64(cred.rawId), | ||||
| @@ -61,6 +68,7 @@ export class AdminKeyHelper { | ||||
| 		await serverRequest("keys/register_key", { | ||||
| 			name: name, | ||||
| 			key: JSON.stringify(res), | ||||
| 			password: password, | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| @@ -96,11 +104,13 @@ export class AdminKeyHelper { | ||||
| 	 * @param mail Target admin account email address | ||||
| 	 * @param key Key used to authenticate | ||||
| 	 * @param cred Response to authentication | ||||
| 	 * @param password The password associated with the key (if any) | ||||
| 	 */ | ||||
| 	static async AuthenticateWithKey( | ||||
| 		mail: string, | ||||
| 		key: AuthKey, | ||||
| 		cred: any | ||||
| 		cred: any, | ||||
| 		password: string | ||||
| 	): Promise<any> { | ||||
| 		const creds = { | ||||
| 			id: cred.id, | ||||
| @@ -122,6 +132,7 @@ export class AdminKeyHelper { | ||||
| 			mail: mail, | ||||
| 			key_id: key.id, | ||||
| 			credential: JSON.stringify(creds), | ||||
| 			password: password, | ||||
| 		}); | ||||
|  | ||||
| 		sessionStorage.setItem(SESSION_STORAGE_TOKEN, res.token); | ||||
|   | ||||
| @@ -1,24 +1,26 @@ | ||||
| import { | ||||
| 	Button, | ||||
| 	Divider, | ||||
| 	IconButton, | ||||
| 	Table, | ||||
| 	TableBody, | ||||
| 	TableCell, | ||||
| 	TableHead, | ||||
| 	TableRow, | ||||
| 	TableCell, | ||||
| 	TableBody, | ||||
| 	IconButton, | ||||
| 	Divider, | ||||
| 	Button, | ||||
| 	Tooltip, | ||||
| } from "@material-ui/core"; | ||||
| import { Delete } from "@material-ui/icons"; | ||||
| import LockIcon from "@material-ui/icons/Lock"; | ||||
| import React from "react"; | ||||
| import { AdminAccount, AccountHelper } from "../../helpers/AccountHelper"; | ||||
| import { AccountHelper, AdminAccount } from "../../helpers/AccountHelper"; | ||||
| import { AdminAccountKey, AdminKeyHelper } from "../../helpers/AdminKeyHelper"; | ||||
| import { CopyToClipboard } from "../../utils/ClipboardUtils"; | ||||
| import { AsyncWidget } from "../widgets/AsyncWidget"; | ||||
| import { | ||||
| 	input, | ||||
| 	matAlert, | ||||
| 	matConfirm, | ||||
| 	snackbar, | ||||
| 	matAlert, | ||||
| 	input, | ||||
| } from "../widgets/DialogsProvider"; | ||||
| import { TimestampWidget } from "../widgets/TimestampWidget"; | ||||
| import { SettingsSection } from "./SettingsSection"; | ||||
| @@ -83,7 +85,14 @@ export class KeySettingsSection extends React.Component< | ||||
| 				minLength: 2, | ||||
| 			}); | ||||
|  | ||||
| 			await AdminKeyHelper.RegisterKey(name, credential); | ||||
| 			const password = await input({ | ||||
| 				label: "Key password (10 characters min)", | ||||
| 				maxLength: 4000, | ||||
| 				minLength: 10, | ||||
| 				type: "password", | ||||
| 			}); | ||||
|  | ||||
| 			await AdminKeyHelper.RegisterKey(name, credential, password); | ||||
|  | ||||
| 			snackbar("Successfully enrolled a new key!"); | ||||
|  | ||||
| @@ -139,7 +148,19 @@ export class KeySettingsSection extends React.Component< | ||||
| 						{this.state.keys.map((key) => ( | ||||
| 							<TableRow key={key.id}> | ||||
| 								<TableCell component="th" scope="row"> | ||||
| 									{key.name} | ||||
| 									{key.name}{" "} | ||||
| 									{key.has_password ? ( | ||||
| 										<Tooltip | ||||
| 											disableFocusListener | ||||
| 											title="This key requires a password to be used" | ||||
| 											placement="top" | ||||
| 											arrow | ||||
| 										> | ||||
| 											<LockIcon fontSize="inherit" /> | ||||
| 										</Tooltip> | ||||
| 									) : ( | ||||
| 										<></> | ||||
| 									)} | ||||
| 								</TableCell> | ||||
| 								<TableCell align="right"> | ||||
| 									<TimestampWidget time={key.time_add} /> | ||||
|   | ||||
| @@ -24,6 +24,7 @@ import React from "react"; | ||||
| import { AccountHelper, AuthOptions } from "../../helpers/AccountHelper"; | ||||
| import { AdminKeyHelper, AuthKey } from "../../helpers/AdminKeyHelper"; | ||||
| import { input, matAlert } from "../widgets/DialogsProvider"; | ||||
| import LockIcon from "@material-ui/icons/Lock"; | ||||
|  | ||||
| function ErrorGettingOptions(p: { message: string }) { | ||||
| 	return ( | ||||
| @@ -248,10 +249,22 @@ class AuthOptionsWidget extends React.Component< | ||||
|  | ||||
| 			const result = await navigator.credentials.get(challenge); | ||||
|  | ||||
| 			const password = key.password | ||||
| 				? await input({ | ||||
| 						label: "Key password", | ||||
| 						message: | ||||
| 							"A password is required to sign in using this key.", | ||||
| 						minLength: 2, | ||||
| 						title: "Login with " + key.name, | ||||
| 						type: "password", | ||||
| 				  }) | ||||
| 				: ""; | ||||
|  | ||||
| 			await AdminKeyHelper.AuthenticateWithKey( | ||||
| 				this.props.email, | ||||
| 				key, | ||||
| 				result | ||||
| 				result, | ||||
| 				password | ||||
| 			); | ||||
|  | ||||
| 			document.location.href = document.location.href + ""; | ||||
| @@ -304,7 +317,12 @@ class AuthOptionsWidget extends React.Component< | ||||
| 							</ListItemAvatar> | ||||
| 							<ListItemText | ||||
| 								primary={key.name} | ||||
| 								secondary="Sign in using this security key" | ||||
| 								secondary={ | ||||
| 									"Sign in using this security key. " + | ||||
| 									(key.password | ||||
| 										? "A password is associated with this key." | ||||
| 										: "") | ||||
| 								} | ||||
| 							/> | ||||
| 						</ListItem> | ||||
| 					))} | ||||
|   | ||||
| @@ -27,6 +27,7 @@ export interface TextInputOptions { | ||||
| 	minLength?: number; | ||||
| 	maxLength?: number; | ||||
| 	label: string; | ||||
| 	type?: string; | ||||
| } | ||||
|  | ||||
| interface AppDiagProvState { | ||||
| @@ -287,6 +288,7 @@ export class ApplicationDialogsProvider extends React.Component< | ||||
| 							variant="outlined" | ||||
| 							value={this.state.inputValue} | ||||
| 							onChange={this.handleInputValueChanged} | ||||
| 							type={this.state.inputOptions.type || "text"} | ||||
| 						/> | ||||
| 					</DialogContent> | ||||
| 					<DialogActions> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user