142 lines
3.9 KiB
TypeScript
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} />
|
|
</>
|
|
);
|
|
}
|
|
}
|