import { Button } from "../../../elements/Button"; import { Component, createRef } from "preact"; import { CopyableBox } from "../../../elements/CopyableBox"; import { DefaultPageProps } from "../../../../types/DefaultPageProps"; import { ErrorMessage, sendErrorNotification } from "../../../elements/ErrorMessage"; import { Form } from "../../../elements/Form"; import { Margin } from "../../../elements/Margin"; import { SecretTitleElement } from "../SecretTitleElement"; import { TransitKeyType } from "../../../../api/types/transit"; import { objectToMap } from "../../../../utils"; import i18next from "i18next"; type versionOption = { version: string; label: string }; type TransitRewrapState = { transitKey: TransitKeyType; ciphertext: string; }; export class TransitRewrap extends Component<DefaultPageProps, TransitRewrapState> { errorMessageRef = createRef<ErrorMessage>(); async componentDidMount() { const baseMount = this.props.matches["baseMount"]; const secretItem = this.props.matches["secretItem"]; try { const transitKey = await this.props.api.getTransitKey(baseMount, secretItem); this.setState({ transitKey }); } catch (e: unknown) { const error = e as Error; sendErrorNotification(error.message); } } render() { if (!this.state.transitKey) return; const baseMount = this.props.matches["baseMount"]; const secretItem = this.props.matches["secretItem"]; const title = ( <SecretTitleElement type="transit" baseMount={baseMount} item={secretItem} suffix={i18next.t("transit_rewrap_suffix")} /> ); if (!this.state.ciphertext) { const stringVersions = Array.from( objectToMap(this.state.transitKey.keys).keys(), ).reverse() as unknown as string[]; const versions = stringVersions.map((val): number => parseInt(val, 10)); // get the selectable version options in the same // format the official UI uses. // e.g: ["2 (latest)", "1"] const options: versionOption[] = versions.map((val): versionOption => { const i18nkey = val == Math.max(...versions) ? "transit_rewrap_latest_version_option_text" : "transit_rewrap_version_option_text"; return { version: String(val), label: i18next.t(i18nkey, { version_num: String(val) }), }; }); return ( <> {title} <Form onSubmit={async (data) => await this.onSubmit(data)}> <Margin> <select class="uk-select uk-width-1-2" name="version"> {options.map((option) => ( <option label={option.label} value={option.version}> {option.label} </option> ))} </select> </Margin> <Margin> <textarea class="uk-textarea uk-width-1-2" name="ciphertext" placeholder={i18next.t("transit_rewrap_input_placeholder")} /> </Margin> <Margin> <ErrorMessage ref={this.errorMessageRef} /> </Margin> <Button text={i18next.t("transit_rewrap")} color="primary" type="submit" /> </Form> </> ); } else { return ( <> {title} <CopyableBox title={i18next.t("transit_rewrap_result_title")} contentString={this.state.ciphertext} goBack={() => { this.setState({ ciphertext: null }); }} /> </> ); } } async onSubmit(data: FormData): Promise<void> { const baseMount = this.props.matches["baseMount"]; const secretItem = this.props.matches["secretItem"]; try { const res = await this.props.api.transitRewrap(baseMount, secretItem, { ciphertext: data.get("ciphertext") as string, key_version: parseInt(data.get("version") as string, 10), }); this.setState({ ciphertext: res.ciphertext }); } catch (e: unknown) { const error = e as Error; this.errorMessageRef.current.setErrorMessage(error.message); } } }