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