mirror of
				https://gitlab.com/comunic/comunicconsole
				synced 2025-11-03 19:54:04 +00:00 
			
		
		
		
	Refactor code
This commit is contained in:
		@@ -4,17 +4,9 @@
 | 
			
		||||
 * @author Pierre Hubert
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
	ArrayBufferToBase64,
 | 
			
		||||
	base64NoPaddingToUint8Array,
 | 
			
		||||
} from "../utils/Base64Utils";
 | 
			
		||||
import { AuthKey } from "./AdminKeyHelper";
 | 
			
		||||
import { serverRequest } from "./APIHelper";
 | 
			
		||||
 | 
			
		||||
export interface AuthKey {
 | 
			
		||||
	name: string;
 | 
			
		||||
	id: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AuthOptions {
 | 
			
		||||
	reset_token: string;
 | 
			
		||||
	keys: AuthKey[];
 | 
			
		||||
@@ -33,18 +25,12 @@ export interface NewAdminGeneralSettings {
 | 
			
		||||
	email: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AdminAccountKey {
 | 
			
		||||
	id: number;
 | 
			
		||||
	name: string;
 | 
			
		||||
	time_add: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AdminResetToken {
 | 
			
		||||
	token: string;
 | 
			
		||||
	expire: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const SESSION_STORAGE_TOKEN = "auth_token";
 | 
			
		||||
export const SESSION_STORAGE_TOKEN = "auth_token";
 | 
			
		||||
 | 
			
		||||
let currentAccount: AdminAccount | null = null;
 | 
			
		||||
 | 
			
		||||
@@ -165,133 +151,4 @@ export class AccountHelper {
 | 
			
		||||
			id: adminID,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * First step of access key enrollment
 | 
			
		||||
	 */
 | 
			
		||||
	static async GetKeyRegistrationChallenge(): Promise<any> {
 | 
			
		||||
		const res = await serverRequest("accounts/challenge_register_key");
 | 
			
		||||
		res.publicKey.challenge = base64NoPaddingToUint8Array(
 | 
			
		||||
			res.publicKey.challenge
 | 
			
		||||
		);
 | 
			
		||||
		res.publicKey.user.id = base64NoPaddingToUint8Array(
 | 
			
		||||
			res.publicKey.user.id
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Register key
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param name The name of the key to create
 | 
			
		||||
	 * @param cred The credentials to register
 | 
			
		||||
	 */
 | 
			
		||||
	static async RegisterKey(name: string, cred: any): Promise<void> {
 | 
			
		||||
		const res = {
 | 
			
		||||
			id: cred.id,
 | 
			
		||||
			rawId: ArrayBufferToBase64(cred.rawId),
 | 
			
		||||
			type: cred.type,
 | 
			
		||||
			response: {
 | 
			
		||||
				attestationObject: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.attestationObject
 | 
			
		||||
				),
 | 
			
		||||
				clientDataJSON: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.clientDataJSON
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		await serverRequest("accounts/register_key", {
 | 
			
		||||
			name: name,
 | 
			
		||||
			key: JSON.stringify(res),
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * First step of security key authentication
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param mail Target admin account email address
 | 
			
		||||
	 * @param key The key to use to authentifcate
 | 
			
		||||
	 */
 | 
			
		||||
	static async GetAuthenticationChallenge(
 | 
			
		||||
		mail: string,
 | 
			
		||||
		key: AuthKey
 | 
			
		||||
	): Promise<any> {
 | 
			
		||||
		const res = await serverRequest("accounts/challenge_auth_with_key", {
 | 
			
		||||
			mail: mail,
 | 
			
		||||
			key_id: key.id,
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		res.publicKey.challenge = base64NoPaddingToUint8Array(
 | 
			
		||||
			res.publicKey.challenge
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		for (let cred of res.publicKey.allowCredentials) {
 | 
			
		||||
			cred.id = base64NoPaddingToUint8Array(cred.id);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Attempt to sign in using security key
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param mail Target admin account email address
 | 
			
		||||
	 * @param key Key used to authenticate
 | 
			
		||||
	 * @param cred Response to authentication
 | 
			
		||||
	 */
 | 
			
		||||
	static async AuthenticateWithKey(
 | 
			
		||||
		mail: string,
 | 
			
		||||
		key: AuthKey,
 | 
			
		||||
		cred: any
 | 
			
		||||
	): Promise<any> {
 | 
			
		||||
		const creds = {
 | 
			
		||||
			id: cred.id,
 | 
			
		||||
			rawId: ArrayBufferToBase64(cred.rawId),
 | 
			
		||||
			type: cred.type,
 | 
			
		||||
			response: {
 | 
			
		||||
				authenticatorData: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.authenticatorData
 | 
			
		||||
				),
 | 
			
		||||
				clientDataJSON: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.clientDataJSON
 | 
			
		||||
				),
 | 
			
		||||
				signature: ArrayBufferToBase64(cred.response.signature),
 | 
			
		||||
				userHandle: cred.response.userHandle,
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		const res = await serverRequest("accounts/auth_with_key", {
 | 
			
		||||
			mail: mail,
 | 
			
		||||
			key_id: key.id,
 | 
			
		||||
			credential: JSON.stringify(creds),
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		sessionStorage.setItem(SESSION_STORAGE_TOKEN, res.token);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get the list of keys of an admin
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param adminID The id of the target administrator
 | 
			
		||||
	 */
 | 
			
		||||
	static async GetAdminKeys(adminID: number): Promise<AdminAccountKey[]> {
 | 
			
		||||
		return await serverRequest("accounts/keys", {
 | 
			
		||||
			id: adminID,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Delete an admin auth key
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param adminID The id of the target admin
 | 
			
		||||
	 * @param keyID The id of the key to delete
 | 
			
		||||
	 */
 | 
			
		||||
	static async DeleteAuthKey(adminID: number, keyID: number) {
 | 
			
		||||
		return await serverRequest("accounts/delete_auth_key", {
 | 
			
		||||
			adminID: adminID,
 | 
			
		||||
			keyID: keyID,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										153
									
								
								src/helpers/AdminKeyHelper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/helpers/AdminKeyHelper.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,153 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Admin security keys management helper
 | 
			
		||||
 *
 | 
			
		||||
 * @author Pierre Hubert
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
	ArrayBufferToBase64,
 | 
			
		||||
	base64NoPaddingToUint8Array,
 | 
			
		||||
} from "../utils/Base64Utils";
 | 
			
		||||
import { SESSION_STORAGE_TOKEN } from "./AccountHelper";
 | 
			
		||||
import { serverRequest } from "./APIHelper";
 | 
			
		||||
 | 
			
		||||
export interface AdminAccountKey {
 | 
			
		||||
	id: number;
 | 
			
		||||
	name: string;
 | 
			
		||||
	time_add: number;
 | 
			
		||||
}
 | 
			
		||||
export interface AuthKey {
 | 
			
		||||
	name: string;
 | 
			
		||||
	id: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class AdminKeyHelper {
 | 
			
		||||
	/**
 | 
			
		||||
	 * First step of access key enrollment
 | 
			
		||||
	 */
 | 
			
		||||
	static async GetKeyRegistrationChallenge(): Promise<any> {
 | 
			
		||||
		const res = await serverRequest("keys/challenge_register_key");
 | 
			
		||||
		res.publicKey.challenge = base64NoPaddingToUint8Array(
 | 
			
		||||
			res.publicKey.challenge
 | 
			
		||||
		);
 | 
			
		||||
		res.publicKey.user.id = base64NoPaddingToUint8Array(
 | 
			
		||||
			res.publicKey.user.id
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Register key
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param name The name of the key to create
 | 
			
		||||
	 * @param cred The credentials to register
 | 
			
		||||
	 */
 | 
			
		||||
	static async RegisterKey(name: string, cred: any): Promise<void> {
 | 
			
		||||
		const res = {
 | 
			
		||||
			id: cred.id,
 | 
			
		||||
			rawId: ArrayBufferToBase64(cred.rawId),
 | 
			
		||||
			type: cred.type,
 | 
			
		||||
			response: {
 | 
			
		||||
				attestationObject: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.attestationObject
 | 
			
		||||
				),
 | 
			
		||||
				clientDataJSON: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.clientDataJSON
 | 
			
		||||
				),
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		await serverRequest("keys/register_key", {
 | 
			
		||||
			name: name,
 | 
			
		||||
			key: JSON.stringify(res),
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * First step of security key authentication
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param mail Target admin account email address
 | 
			
		||||
	 * @param key The key to use to authentifcate
 | 
			
		||||
	 */
 | 
			
		||||
	static async GetAuthenticationChallenge(
 | 
			
		||||
		mail: string,
 | 
			
		||||
		key: AuthKey
 | 
			
		||||
	): Promise<any> {
 | 
			
		||||
		const res = await serverRequest("keys/challenge_auth_with_key", {
 | 
			
		||||
			mail: mail,
 | 
			
		||||
			key_id: key.id,
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		res.publicKey.challenge = base64NoPaddingToUint8Array(
 | 
			
		||||
			res.publicKey.challenge
 | 
			
		||||
		);
 | 
			
		||||
 | 
			
		||||
		for (let cred of res.publicKey.allowCredentials) {
 | 
			
		||||
			cred.id = base64NoPaddingToUint8Array(cred.id);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return res;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Attempt to sign in using security key
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param mail Target admin account email address
 | 
			
		||||
	 * @param key Key used to authenticate
 | 
			
		||||
	 * @param cred Response to authentication
 | 
			
		||||
	 */
 | 
			
		||||
	static async AuthenticateWithKey(
 | 
			
		||||
		mail: string,
 | 
			
		||||
		key: AuthKey,
 | 
			
		||||
		cred: any
 | 
			
		||||
	): Promise<any> {
 | 
			
		||||
		const creds = {
 | 
			
		||||
			id: cred.id,
 | 
			
		||||
			rawId: ArrayBufferToBase64(cred.rawId),
 | 
			
		||||
			type: cred.type,
 | 
			
		||||
			response: {
 | 
			
		||||
				authenticatorData: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.authenticatorData
 | 
			
		||||
				),
 | 
			
		||||
				clientDataJSON: ArrayBufferToBase64(
 | 
			
		||||
					cred.response.clientDataJSON
 | 
			
		||||
				),
 | 
			
		||||
				signature: ArrayBufferToBase64(cred.response.signature),
 | 
			
		||||
				userHandle: cred.response.userHandle,
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		const res = await serverRequest("keys/auth_with_key", {
 | 
			
		||||
			mail: mail,
 | 
			
		||||
			key_id: key.id,
 | 
			
		||||
			credential: JSON.stringify(creds),
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		sessionStorage.setItem(SESSION_STORAGE_TOKEN, res.token);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Get the list of keys of an admin
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param adminID The id of the target administrator
 | 
			
		||||
	 */
 | 
			
		||||
	static async GetAdminKeys(adminID: number): Promise<AdminAccountKey[]> {
 | 
			
		||||
		return await serverRequest("keys/keys", {
 | 
			
		||||
			id: adminID,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Delete an admin auth key
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param adminID The id of the target admin
 | 
			
		||||
	 * @param keyID The id of the key to delete
 | 
			
		||||
	 */
 | 
			
		||||
	static async DeleteAuthKey(adminID: number, keyID: number) {
 | 
			
		||||
		return await serverRequest("keys/delete_auth_key", {
 | 
			
		||||
			adminID: adminID,
 | 
			
		||||
			keyID: keyID,
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -21,11 +21,8 @@ import {
 | 
			
		||||
import { Delete } from "@material-ui/icons";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import { useParams } from "react-router-dom";
 | 
			
		||||
import {
 | 
			
		||||
	AccountHelper,
 | 
			
		||||
	AdminAccount,
 | 
			
		||||
	AdminAccountKey,
 | 
			
		||||
} 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 {
 | 
			
		||||
@@ -199,7 +196,7 @@ export class KeySettingsSection extends React.Component<
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	async load() {
 | 
			
		||||
		const keys = await AccountHelper.GetAdminKeys(this.props.admin.id);
 | 
			
		||||
		const keys = await AdminKeyHelper.GetAdminKeys(this.props.admin.id);
 | 
			
		||||
 | 
			
		||||
		this.setState({ keys: keys });
 | 
			
		||||
	}
 | 
			
		||||
@@ -227,7 +224,8 @@ export class KeySettingsSection extends React.Component<
 | 
			
		||||
 | 
			
		||||
	async registerNewKey() {
 | 
			
		||||
		try {
 | 
			
		||||
			const challenge = await AccountHelper.GetKeyRegistrationChallenge();
 | 
			
		||||
			const challenge =
 | 
			
		||||
				await AdminKeyHelper.GetKeyRegistrationChallenge();
 | 
			
		||||
			const credential = await navigator.credentials.create(challenge);
 | 
			
		||||
 | 
			
		||||
			if (credential == null) throw new Error("Operation aborted!");
 | 
			
		||||
@@ -238,7 +236,7 @@ export class KeySettingsSection extends React.Component<
 | 
			
		||||
				minLength: 2,
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			await AccountHelper.RegisterKey(name, credential);
 | 
			
		||||
			await AdminKeyHelper.RegisterKey(name, credential);
 | 
			
		||||
 | 
			
		||||
			snackbar("Successfully enrolled a new key!");
 | 
			
		||||
 | 
			
		||||
@@ -258,7 +256,7 @@ export class KeySettingsSection extends React.Component<
 | 
			
		||||
			)
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			await AccountHelper.DeleteAuthKey(this.props.admin.id, key.id);
 | 
			
		||||
			await AdminKeyHelper.DeleteAuthKey(this.props.admin.id, key.id);
 | 
			
		||||
 | 
			
		||||
			snackbar("The key was successfully deleted!");
 | 
			
		||||
			this.setState({ counter: this.state.counter + 1 });
 | 
			
		||||
 
 | 
			
		||||
@@ -21,11 +21,8 @@ import {
 | 
			
		||||
import { ErrorOutline, Lock, VpnKey } from "@material-ui/icons";
 | 
			
		||||
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
 | 
			
		||||
import React from "react";
 | 
			
		||||
import {
 | 
			
		||||
	AccountHelper,
 | 
			
		||||
	AuthKey,
 | 
			
		||||
	AuthOptions,
 | 
			
		||||
} from "../../helpers/AccountHelper";
 | 
			
		||||
import { AccountHelper, AuthOptions } from "../../helpers/AccountHelper";
 | 
			
		||||
import { AdminKeyHelper, AuthKey } from "../../helpers/AdminKeyHelper";
 | 
			
		||||
import { input, matAlert } from "../widgets/DialogsProvider";
 | 
			
		||||
 | 
			
		||||
function ErrorGettingOptions(p: { message: string }) {
 | 
			
		||||
@@ -244,14 +241,14 @@ class AuthOptionsWidget extends React.Component<
 | 
			
		||||
 | 
			
		||||
	async loginWithSecurityKey(key: AuthKey) {
 | 
			
		||||
		try {
 | 
			
		||||
			const challenge = await AccountHelper.GetAuthenticationChallenge(
 | 
			
		||||
			const challenge = await AdminKeyHelper.GetAuthenticationChallenge(
 | 
			
		||||
				this.props.email,
 | 
			
		||||
				key
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
			const result = await navigator.credentials.get(challenge);
 | 
			
		||||
 | 
			
		||||
			await AccountHelper.AuthenticateWithKey(
 | 
			
		||||
			await AdminKeyHelper.AuthenticateWithKey(
 | 
			
		||||
				this.props.email,
 | 
			
		||||
				key,
 | 
			
		||||
				result
 | 
			
		||||
@@ -267,7 +264,7 @@ class AuthOptionsWidget extends React.Component<
 | 
			
		||||
	render() {
 | 
			
		||||
		// Check if no option is available
 | 
			
		||||
		if (
 | 
			
		||||
			this.props.options.keys.length == 0 &&
 | 
			
		||||
			this.props.options.keys.length === 0 &&
 | 
			
		||||
			!this.props.options.reset_token
 | 
			
		||||
		)
 | 
			
		||||
			return (
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,6 @@ import {
 | 
			
		||||
	ListItemIcon,
 | 
			
		||||
	ListItemText,
 | 
			
		||||
	makeStyles,
 | 
			
		||||
	MenuItem,
 | 
			
		||||
	Paper,
 | 
			
		||||
	Toolbar,
 | 
			
		||||
	Typography,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user