mirror of
https://gitlab.com/comunic/comunicconsole
synced 2024-11-23 13:59:23 +00:00
Refactor code
This commit is contained in:
parent
bf46cc7043
commit
5334fd9430
@ -4,17 +4,9 @@
|
|||||||
* @author Pierre Hubert
|
* @author Pierre Hubert
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { AuthKey } from "./AdminKeyHelper";
|
||||||
ArrayBufferToBase64,
|
|
||||||
base64NoPaddingToUint8Array,
|
|
||||||
} from "../utils/Base64Utils";
|
|
||||||
import { serverRequest } from "./APIHelper";
|
import { serverRequest } from "./APIHelper";
|
||||||
|
|
||||||
export interface AuthKey {
|
|
||||||
name: string;
|
|
||||||
id: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AuthOptions {
|
export interface AuthOptions {
|
||||||
reset_token: string;
|
reset_token: string;
|
||||||
keys: AuthKey[];
|
keys: AuthKey[];
|
||||||
@ -33,18 +25,12 @@ export interface NewAdminGeneralSettings {
|
|||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdminAccountKey {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
time_add: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AdminResetToken {
|
export interface AdminResetToken {
|
||||||
token: string;
|
token: string;
|
||||||
expire: number;
|
expire: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SESSION_STORAGE_TOKEN = "auth_token";
|
export const SESSION_STORAGE_TOKEN = "auth_token";
|
||||||
|
|
||||||
let currentAccount: AdminAccount | null = null;
|
let currentAccount: AdminAccount | null = null;
|
||||||
|
|
||||||
@ -165,133 +151,4 @@ export class AccountHelper {
|
|||||||
id: adminID,
|
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 { Delete } from "@material-ui/icons";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import {
|
import { AccountHelper, AdminAccount } from "../../helpers/AccountHelper";
|
||||||
AccountHelper,
|
import { AdminAccountKey, AdminKeyHelper } from "../../helpers/AdminKeyHelper";
|
||||||
AdminAccount,
|
|
||||||
AdminAccountKey,
|
|
||||||
} from "../../helpers/AccountHelper";
|
|
||||||
import { CopyToClipboard } from "../../utils/ClipboardUtils";
|
import { CopyToClipboard } from "../../utils/ClipboardUtils";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
import {
|
import {
|
||||||
@ -199,7 +196,7 @@ export class KeySettingsSection extends React.Component<
|
|||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
const keys = await AccountHelper.GetAdminKeys(this.props.admin.id);
|
const keys = await AdminKeyHelper.GetAdminKeys(this.props.admin.id);
|
||||||
|
|
||||||
this.setState({ keys: keys });
|
this.setState({ keys: keys });
|
||||||
}
|
}
|
||||||
@ -227,7 +224,8 @@ export class KeySettingsSection extends React.Component<
|
|||||||
|
|
||||||
async registerNewKey() {
|
async registerNewKey() {
|
||||||
try {
|
try {
|
||||||
const challenge = await AccountHelper.GetKeyRegistrationChallenge();
|
const challenge =
|
||||||
|
await AdminKeyHelper.GetKeyRegistrationChallenge();
|
||||||
const credential = await navigator.credentials.create(challenge);
|
const credential = await navigator.credentials.create(challenge);
|
||||||
|
|
||||||
if (credential == null) throw new Error("Operation aborted!");
|
if (credential == null) throw new Error("Operation aborted!");
|
||||||
@ -238,7 +236,7 @@ export class KeySettingsSection extends React.Component<
|
|||||||
minLength: 2,
|
minLength: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
await AccountHelper.RegisterKey(name, credential);
|
await AdminKeyHelper.RegisterKey(name, credential);
|
||||||
|
|
||||||
snackbar("Successfully enrolled a new key!");
|
snackbar("Successfully enrolled a new key!");
|
||||||
|
|
||||||
@ -258,7 +256,7 @@ export class KeySettingsSection extends React.Component<
|
|||||||
)
|
)
|
||||||
return;
|
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!");
|
snackbar("The key was successfully deleted!");
|
||||||
this.setState({ counter: this.state.counter + 1 });
|
this.setState({ counter: this.state.counter + 1 });
|
||||||
|
@ -21,11 +21,8 @@ import {
|
|||||||
import { ErrorOutline, Lock, VpnKey } from "@material-ui/icons";
|
import { ErrorOutline, Lock, VpnKey } from "@material-ui/icons";
|
||||||
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
|
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import { AccountHelper, AuthOptions } from "../../helpers/AccountHelper";
|
||||||
AccountHelper,
|
import { AdminKeyHelper, AuthKey } from "../../helpers/AdminKeyHelper";
|
||||||
AuthKey,
|
|
||||||
AuthOptions,
|
|
||||||
} from "../../helpers/AccountHelper";
|
|
||||||
import { input, matAlert } from "../widgets/DialogsProvider";
|
import { input, matAlert } from "../widgets/DialogsProvider";
|
||||||
|
|
||||||
function ErrorGettingOptions(p: { message: string }) {
|
function ErrorGettingOptions(p: { message: string }) {
|
||||||
@ -244,14 +241,14 @@ class AuthOptionsWidget extends React.Component<
|
|||||||
|
|
||||||
async loginWithSecurityKey(key: AuthKey) {
|
async loginWithSecurityKey(key: AuthKey) {
|
||||||
try {
|
try {
|
||||||
const challenge = await AccountHelper.GetAuthenticationChallenge(
|
const challenge = await AdminKeyHelper.GetAuthenticationChallenge(
|
||||||
this.props.email,
|
this.props.email,
|
||||||
key
|
key
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await navigator.credentials.get(challenge);
|
const result = await navigator.credentials.get(challenge);
|
||||||
|
|
||||||
await AccountHelper.AuthenticateWithKey(
|
await AdminKeyHelper.AuthenticateWithKey(
|
||||||
this.props.email,
|
this.props.email,
|
||||||
key,
|
key,
|
||||||
result
|
result
|
||||||
@ -267,7 +264,7 @@ class AuthOptionsWidget extends React.Component<
|
|||||||
render() {
|
render() {
|
||||||
// Check if no option is available
|
// Check if no option is available
|
||||||
if (
|
if (
|
||||||
this.props.options.keys.length == 0 &&
|
this.props.options.keys.length === 0 &&
|
||||||
!this.props.options.reset_token
|
!this.props.options.reset_token
|
||||||
)
|
)
|
||||||
return (
|
return (
|
||||||
|
@ -12,7 +12,6 @@ import {
|
|||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
makeStyles,
|
makeStyles,
|
||||||
MenuItem,
|
|
||||||
Paper,
|
Paper,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
Typography,
|
Typography,
|
||||||
|
Loading…
Reference in New Issue
Block a user