import { Component, JSX, createRef } from "preact"; import { CopyableInputBox } from "../../../elements/CopyableInputBox"; import { DefaultPageProps } from "../../../../types/DefaultPageProps"; import { Form } from "../../../elements/Form"; import { InputWithTitle } from "../../../elements/InputWithTitle"; import { Margin } from "../../../elements/Margin"; import { MarginInline } from "../../../elements/MarginInline"; import { NewTOTPResp } from "../../../../api/types/totp"; import { SecretTitleElement } from "../SecretTitleElement"; import { route } from "preact-router"; import { setErrorText } from "../../../../pageUtils"; import i18next from "i18next"; export class TOTPNewGeneratedForm extends Component< { baseMount: string } & DefaultPageProps, { exportedData: NewTOTPResp } > { uriInputRef = createRef<HTMLInputElement>(); render(): JSX.Element { if (!this.state.exportedData) { return ( <Form onSubmit={(data) => this.onSubmit(data)}> <Margin> <InputWithTitle title={i18next.t("common_name")}> <input class="uk-input uk-form-width-medium" name="name" type="text" placeholder={i18next.t("common_name")} required /> </InputWithTitle> </Margin> <Margin> <InputWithTitle title={i18next.t("totp_new_generated_issuer")}> <input class="uk-input uk-form-width-medium" name="issuer" type="text" required /> </InputWithTitle> </Margin> <Margin> <InputWithTitle title={i18next.t("totp_new_generated_account_name")}> <input class="uk-input uk-form-width-medium" name="account_name" type="text" required /> </InputWithTitle> </Margin> <Margin> <InputWithTitle title={i18next.t("totp_new_generated_algorithm")}> <select class="uk-select uk-form-width-medium" name="algorithm"> {["SHA512", "SHA256", "SHA1"].map((type) => ( <option label={type} value={type}> {type} </option> ))} </select> </InputWithTitle> </Margin> <Margin> <InputWithTitle title={i18next.t("totp_new_generated_key_size")}> <input class="uk-input uk-form-width-medium" name="key_size" type="number" value="20" /> </InputWithTitle> </Margin> <Margin> <InputWithTitle title={i18next.t("totp_new_generated_period")}> <input class="uk-input uk-form-width-medium" name="period" type="text" value="30s" /> </InputWithTitle> </Margin> <Margin> <InputWithTitle title={i18next.t("totp_new_generated_digits")}> <input class="uk-input uk-form-width-medium" name="digits" type="number" value="6" /> </InputWithTitle> </Margin> <Margin> <InputWithTitle title={i18next.t("totp_new_generated_export")}> <input class="uk-checkbox" name="exported" type="checkbox" value="yes" checked /> </InputWithTitle> </Margin> <p id="errorText" class="uk-text-danger" /> <MarginInline> <button class="uk-button uk-button-primary" type="submit"> {i18next.t("common_create")} </button> </MarginInline> </Form> ); } else { return ( <> <p>{i18next.t("totp_new_generated_warning")}</p> <img src={"data:image/png;base64," + this.state.exportedData.barcode} /> <CopyableInputBox copyable text={this.state.exportedData.url} /> <button class="uk-button uk-button-primary" onClick={async () => { route("/secrets/totp/list/" + this.props.baseMount); }} > {i18next.t("common_back")} </button> </> ); } } async onSubmit(data: FormData): Promise<void> { const isExported = data.get("exported") == "yes" ? true : false; const parms = { generate: true, name: data.get("name") as string, issuer: data.get("issuer") as string, account_name: data.get("account_name") as string, exported: isExported, key_size: parseInt(data.get("key_size") as string), period: data.get("period") as string, algorithm: data.get("algorithm") as string, digits: parseInt(data.get("digits") as string), }; try { const ret = await this.props.api.addNewTOTP(this.props.baseMount, parms); if (!isExported) { route("/secrets/totp/list/" + this.props.baseMount); } else { this.setState({ exportedData: ret }); } } catch (e: unknown) { const error = e as Error; setErrorText(`API Error: ${error.message}`); } } } export class TOTPNewGenerated extends Component<DefaultPageProps> { render() { const baseMount = this.props.matches["baseMount"]; return ( <> <SecretTitleElement type="totp" baseMount={baseMount} suffix={i18next.t("totp_new_generated_suffix")} /> <TOTPNewGeneratedForm settings={this.props.settings} api={this.props.api} baseMount={baseMount} /> </> ); } }