1
0
Fork 0

Add TransitRewrap page.

This commit is contained in:
Kitteh 2021-05-09 16:02:04 +01:00
parent 562ced442e
commit c635c2c5c7
8 changed files with 188 additions and 13 deletions

View file

@ -15,6 +15,7 @@ import { SetVaultURLPage } from "./pages/SetVaultURL";
import { TOTPViewPage } from "./pages/TOTP/TOTPView";
import { TransitDecryptPage } from "./pages/Transit/TransitDecrypt";
import { TransitEncryptPage } from "./pages/Transit/TransitEncrypt";
import { TransitRewrapPage } from "./pages/Transit/TransitRewrap";
import { TransitViewPage } from "./pages/Transit/TransitView";
import { TransitViewSecretPage } from "./pages/Transit/TransitViewSecret";
import { UnsealPage } from "./pages/Unseal";
@ -36,6 +37,7 @@ export const allPages: pagesList = {
TRANSIT_VIEW_SECRET: new TransitViewSecretPage(),
TRANSIT_ENCRYPT: new TransitEncryptPage(),
TRANSIT_DECRYPT: new TransitDecryptPage(),
TRANSIT_REWRAP: new TransitRewrapPage(),
KEY_VALUE_VIEW: new KeyValueViewPage(),
KEY_VALUE_SECRET: new KeyValueSecretPage(),
KEY_VALUE_VERSIONS: new KeyValueVersionsPage(),

View file

@ -0,0 +1,34 @@
import { appendAPIURL, getHeaders } from "../apiUtils";
import { removeDoubleSlash } from "../../utils";
type RewrapResult = {
ciphertext: string;
}
type RewrapPayload = {
ciphertext: string;
key_version?: number;
}
export async function transitRewrap(
baseMount: string,
name: string,
payload: RewrapPayload
): Promise<RewrapResult> {
const request = new Request(appendAPIURL(removeDoubleSlash(`/v1/${baseMount}/rewrap/${name}`)), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...getHeaders(),
},
body: JSON.stringify(payload)
});
const response = await fetch(request);
if (!response.ok) {
const json = await response.json();
throw new Error(json.errors[0]);
} else {
const json = await response.json();
return json.data;
}
}

View file

@ -24,7 +24,7 @@ export type TransitKeyBaseType = {
// Type returned when calling getTransitKey
export type TransitKeyType = TransitKeyBaseType & {
keys: {
[version: string]: number;
[version: number]: number;
};
min_decryption_version: number;
min_encryption_version: number;

12
src/elements/Option.ts Normal file
View file

@ -0,0 +1,12 @@
import { makeElement } from "../htmlUtils";
export function Option(label: string, value: string): HTMLElement {
return makeElement({
tag: "option",
text: label,
attributes: {
label: label,
value: value,
}
})
}

View file

@ -4,6 +4,7 @@ import { Page } from "../types/Page";
import { makeElement } from "../htmlUtils";
import { setPageContent } from "../pageUtils";
import i18next from 'i18next';
import { Option } from "../elements/Option";
const passwordLengthMin = 1;
const passwordLengthMax = 64;
@ -43,17 +44,6 @@ function genPassword(options = passwordOptionsDefault) {
return pw;
}
function Option(label, value) {
return makeElement({
tag: "option",
text: label,
attributes: {
label: label,
value: value,
}
})
}
export class PwGenPage extends Page {
constructor() {
super();

View file

@ -0,0 +1,117 @@
import { CopyableModal } from "../../elements/CopyableModal";
import { FileUploadInput } from "../../elements/FileUploadInput";
import { Margin } from "../../elements/Margin";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import UIkit from 'uikit/dist/js/uikit.min.js';
import i18next from "i18next";
import { getTransitKey } from "../../api/transit/getTransitKey";
import { objectToMap } from "../../utils";
import { Option } from "../../elements/Option";
import { transitRewrap } from "../../api/transit/transitRewrap";
type versionOption = { version: string; label: string }
export class TransitRewrapPage extends Page {
constructor() {
super();
}
goBack(): void {
changePage("TRANSIT_VIEW_SECRET");
}
transitRewrapForm: HTMLFormElement;
async render(): Promise<void> {
setTitleElement(pageState);
let transitKey = await getTransitKey(pageState.currentBaseMount, pageState.currentSecret);
let stringVersions = Array.from(objectToMap(transitKey.keys).keys()).reverse() as any as string[];
let versions = stringVersions.map((val) => parseInt(val, 10)) as any as number[];
// get the selectable version options in the same
// format the official UI uses.
// e.g: ["2 (latest)", "1"]
let options: versionOption[] = versions.map((val): versionOption => {
let 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) }),
}
})
setPageContent("");
this.transitRewrapForm = makeElement({
tag: "form",
children: [
makeElement({
tag: "select",
name: "version",
class: ["uk-select", "uk-width-1-2"],
children: options.map((option): HTMLElement => Option(option.label, option.version))
}),
Margin(makeElement({
tag: "textarea",
class: ["uk-textarea", "uk-width-1-2"],
attributes: {
placeholder: i18next.t("transit_rewrap_input_placeholder"),
name: "ciphertext",
}
})),
makeElement({
tag: "p",
id: "errorText",
class: "uk-text-danger"
}),
makeElement({
tag: "button",
class: ["uk-button", "uk-button-primary"],
text: i18next.t("transit_rewrap_rewrap_btn"),
attributes: {
type: "submit",
}
})
]
}) as HTMLFormElement;
setPageContent(this.transitRewrapForm);
this.transitRewrapForm.addEventListener("submit", async function (e: Event) {
e.preventDefault();
await this.transitRewrapFormHandler();
}.bind(this));
}
async transitRewrapFormHandler(): Promise<void> {
const formData = new FormData(this.transitRewrapForm);
const ciphertext = formData.get("ciphertext") as string;
try {
let res = await transitRewrap(
pageState.currentBaseMount,
pageState.currentSecret,
{
ciphertext: formData.get("ciphertext") as string,
key_version: parseInt(formData.get("version") as string, 10),
}
);
const modal = CopyableModal(i18next.t("transit_rewrap_result_modal_title"), res.ciphertext);
document.body.querySelector("#pageContent").appendChild(modal);
UIkit.modal(modal).show();
} catch (e) {
setErrorText(`API Error: ${e.message}`);
}
}
get titleSuffix(): string {
return i18next.t("transit_rewrap_suffix");
}
get name(): string {
return i18next.t("transit_rewrap_title");
}
}

View file

@ -41,6 +41,14 @@ export class TransitViewSecretPage extends Page {
iconText: i18next.t("transit_view_decrypt_icon_text"),
onclick: () => { changePage("TRANSIT_DECRYPT"); }
}),
Tile({
condition: transitKey.supports_decryption,
title: i18next.t("transit_view_rewrap_text"),
description: i18next.t("transit_view_rewrap_description"),
icon: "code",
iconText: i18next.t("transit_view_rewrap_icon_text"),
onclick: () => { changePage("TRANSIT_REWRAP"); }
}),
]
}));
}

View file

@ -133,6 +133,9 @@ module.exports = {
"transit_view_decrypt_text": "Decrypt",
"transit_view_decrypt_description": "Decrypt some cyphertext.",
"transit_view_decrypt_icon_text": "Decryption Icon",
"transit_view_rewrap_text": "Rewrap",
"transit_view_rewrap_description": "Rewrap ciphertext using a different key version.",
"transit_view_rewrap_icon_text": "Rewrap Icon",
// Transit Encrypt Page
"transit_encrypt_title": "Transit Encrypt",
@ -142,11 +145,20 @@ module.exports = {
"transit_encrypt_encrypt_btn": "Encrypt",
"transit_encrypt_encryption_result_modal_title": "Encryption Result",
// Transit decrypt Page
// Transit Decrypt Page
"transit_decrypt_title": "Transit Decrypt",
"transit_decrypt_suffix": " (decrypt)",
"transit_decrypt_input_placeholder": "Cyphertext",
"transit_decrypt_decode_checkbox": "Should the plaintext be base64 decoded?",
"transit_decrypt_decrypt_btn": "Decrypt",
"transit_decrypt_decryption_result_modal_title": "Decryption Result",
// Transit Rewrap Page
"transit_rewrap_title": "Transit Rewrap",
"transit_rewrap_suffix": " (rewrap)",
"transit_rewrap_version_option_text": "{{version_num}}",
"transit_rewrap_latest_version_option_text": "{{version_num}} (latest)",
"transit_rewrap_input_placeholder": "Cyphertext",
"transit_rewrap_rewrap_btn": "Rewrap",
"transit_rewrap_result_modal_title": "Rewrap Result",
}