1
0
Fork 0
VaultUI/src/ui/pages/Secrets/TOTP/TOTPNew.tsx

142 lines
3.9 KiB
TypeScript

import { Button } from "../../../elements/Button";
import { Component, JSX, createRef } from "preact";
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
import { ErrorMessage } from "../../../elements/ErrorMessage";
import { Form } from "../../../elements/Form";
import { Margin } from "../../../elements/Margin";
import { MarginInline } from "../../../elements/MarginInline";
import { QRScanner } from "../../../elements/QRScanner";
import { SecretTitleElement } from "../SecretTitleElement";
import { route } from "preact-router";
import i18next from "i18next";
function replaceAll(str: string, replace: string, replaceWith: string): string {
return str.replace(new RegExp(replace, "g"), replaceWith);
}
function removeDashSpaces(str: string): string {
str = replaceAll(str, "-", "");
str = replaceAll(str, " ", "");
return str;
}
export class TOTPNewForm extends Component<
{ baseMount: string } & DefaultPageProps,
{ qrMode: boolean }
> {
constructor() {
super();
this.state = {
qrMode: false,
};
}
errorMessageRef = createRef<ErrorMessage>();
uriInputRef = createRef<HTMLInputElement>();
async onSubmit(data: FormData): Promise<void> {
const parms = {
url: data.get("uri") as string,
key: removeDashSpaces(data.get("key") as string).toUpperCase(),
name: data.get("name") as string,
generate: false,
};
try {
await this.props.api.addNewTOTP(this.props.baseMount, parms);
route("/secrets/totp/list/" + this.props.baseMount);
} catch (e: unknown) {
const error = e as Error;
this.errorMessageRef.current.setErrorMessage(error.message);
}
}
render(): JSX.Element {
return (
<Form onSubmit={(data) => this.onSubmit(data)}>
<Margin>
<input
class="uk-input uk-form-width-medium"
name="name"
type="text"
placeholder={i18next.t("common_name")}
required
/>
</Margin>
<p hidden={this.state.qrMode}>{i18next.t("totp_new_info")}</p>
<Margin>
<input
class="uk-input uk-form-width-medium"
name="key"
type="text"
hidden={this.state.qrMode}
placeholder={i18next.t("totp_new_key_input")}
/>
</Margin>
<Margin>
<input
class="uk-input uk-form-width-medium"
ref={this.uriInputRef}
name="uri"
type="text"
hidden={this.state.qrMode}
placeholder={i18next.t("totp_new_uri_input")}
/>
</Margin>
{/* TODO: please redo this to be more like Unseal page qr mode */}
{this.state.qrMode && (
<QRScanner
onScan={(uri) => {
this.uriInputRef.current.value = uri;
this.setState({ qrMode: !this.state.qrMode });
}}
/>
)}
<MarginInline>
<Button
text={
!this.state.qrMode
? i18next.t("totp_new_switch_to_qr_btn")
: i18next.t("totp_new_switch_back_to_manual_input_btn")
}
color="primary"
onClick={() => {
this.setState({ qrMode: !this.state.qrMode });
}}
/>
</MarginInline>
<Margin>
<ErrorMessage ref={this.errorMessageRef} />
</Margin>
<MarginInline>
<Button text={i18next.t("common_create")} color="primary" type="submit" />
</MarginInline>
</Form>
);
}
}
export class TOTPNew extends Component<DefaultPageProps> {
render() {
const baseMount = this.props.matches["baseMount"];
return (
<>
<SecretTitleElement
type="totp"
baseMount={baseMount}
suffix={i18next.t("totp_new_suffix")}
/>
<TOTPNewForm settings={this.props.settings} api={this.props.api} baseMount={baseMount} />
</>
);
}
}