Refactor code

This commit is contained in:
Pierre HUBERT 2021-05-14 18:44:17 +02:00
parent bf46cc7043
commit 5334fd9430
5 changed files with 167 additions and 163 deletions

View File

@ -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,
});
}
}

View 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,
});
}
}

View File

@ -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 });

View File

@ -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 (

View File

@ -12,7 +12,6 @@ import {
ListItemIcon,
ListItemText,
makeStyles,
MenuItem,
Paper,
Toolbar,
Typography,