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