1
0
Fork 0
VaultUI/src/pages/Unseal.ts
2021-05-12 18:26:32 +01:00

195 lines
5.3 KiB
TypeScript

import { MarginInline } from "../elements/MarginInline";
import { Page } from "../types/Page";
import { QRScanner, QRScannerType } from "../elements/QRScanner";
import { SealStatusType, getSealStatus } from "../api/sys/getSealStatus";
import { changePage, setErrorText, setPageContent } from "../pageUtils";
import { makeElement } from "../htmlUtils";
import { submitUnsealKey } from "../api/sys/submitUnsealKey";
import i18next from "i18next";
const UnsealInputModes = {
FORM_INPUT: "FORM_INPUT",
QR_INPUT: "QR_INPUT",
};
export class UnsealPage extends Page {
constructor() {
super();
this.mode = UnsealInputModes.FORM_INPUT;
}
mode: string;
refresher: number;
qrScanner: QRScannerType;
unsealProgress: HTMLProgressElement;
unsealProgressText: HTMLParagraphElement;
unsealInputContent: HTMLElement;
unsealKeyForm: HTMLFormElement;
async cleanup(): Promise<void> {
this.deinitWebcam();
clearInterval(this.refresher);
}
deinitWebcam(): void {
try {
this.qrScanner.deinit();
} catch (_) {
// Do Nothing
}
}
makeRefresher(): void {
const id = setInterval(() => {
void (this as UnsealPage).doRefresh().then(() => {});
return;
}, 1000);
this.refresher = id as unknown as number;
}
async doRefresh(): Promise<void> {
const status = await getSealStatus();
await this.updateSealProgress(status);
}
async render(): Promise<void> {
this.unsealProgress = makeElement({
tag: "progress",
class: "uk-progress",
attributes: { value: "0", max: "0" },
}) as HTMLProgressElement;
this.unsealProgressText = makeElement({
tag: "p",
text: i18next.t("unseal_keys_progress", {
progress: "0",
keys_needed: "0",
}),
}) as HTMLParagraphElement;
this.unsealInputContent = makeElement({
tag: "div",
});
setPageContent(
makeElement({
tag: "div",
children: [
this.unsealProgress,
makeElement({
tag: "p",
id: "errorText",
class: ["uk-text-danger", "uk-margin-top"],
}),
this.unsealProgressText,
this.unsealInputContent,
],
}),
);
this.switchInputMode(this.mode);
await this.updateSealProgress(await getSealStatus());
this.makeRefresher();
}
setButtons(method: string): void {
const newMethod: string =
method == UnsealInputModes.FORM_INPUT
? UnsealInputModes.QR_INPUT
: UnsealInputModes.FORM_INPUT;
const buttonText: string =
newMethod == UnsealInputModes.FORM_INPUT
? i18next.t("unseal_input_btn")
: i18next.t("unseal_qr_btn");
this.unsealInputContent.appendChild(
makeElement({
tag: "button",
class: ["uk-button", "uk-button-primary"],
text: buttonText,
onclick: () => {
this.switchInputMode(newMethod);
},
}),
);
}
switchInputMode(method: string): void {
this.deinitWebcam();
this.unsealInputContent.querySelectorAll("*").forEach((n) => n.remove());
if (method == UnsealInputModes.FORM_INPUT) this.makeUnsealForm();
if (method == UnsealInputModes.QR_INPUT) void this.makeQRInput();
this.setButtons(method);
}
makeUnsealForm(): void {
this.unsealKeyForm = makeElement({
tag: "form",
children: [
MarginInline(
makeElement({
tag: "input",
class: ["uk-input", "uk-form-width-medium"],
attributes: {
required: "true",
type: "password",
placeholder: i18next.t("key_input_placeholder"),
name: "key",
},
}),
),
MarginInline(
makeElement({
tag: "button",
class: ["uk-button", "uk-button-primary"],
text: i18next.t("submit_key_btn"),
}),
),
],
}) as HTMLFormElement;
this.unsealInputContent.appendChild(this.unsealKeyForm);
this.unsealKeyForm.addEventListener("submit", (e: Event) => {
e.preventDefault();
void this.handleKeySubmit();
});
}
async makeQRInput(): Promise<void> {
this.qrScanner = await QRScanner(async (code: string) => {
await this.submitKey(code);
});
this.unsealInputContent.appendChild(this.qrScanner);
}
async updateSealProgress(data: SealStatusType): Promise<void> {
const progress = data.progress;
const keysNeeded = data.t;
const text = this.unsealProgressText;
text.innerText = i18next.t("unseal_keys_progress", {
progress: String(progress),
keys_needed: String(keysNeeded),
});
const progressBar = this.unsealProgress;
progressBar.value = progress;
progressBar.max = keysNeeded;
if (!data.sealed) {
progressBar.value = keysNeeded;
await changePage("HOME");
}
}
async submitKey(key: string): Promise<void> {
try {
await submitUnsealKey(key);
await this.updateSealProgress(await getSealStatus());
} catch (e: unknown) {
const error = e as Error;
setErrorText(error.message);
}
}
async handleKeySubmit(): Promise<void> {
const formData = new FormData(this.unsealKeyForm);
await this.submitKey(formData.get("key") as string);
}
get name(): string {
return i18next.t("unseal_vault_text");
}
}