1
0
Fork 0
VaultUI/src/ui/pages/Secrets/Transit/TransitRewrap.tsx

133 lines
4.1 KiB
TypeScript

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