From ceaa2e87838b2d13fa1320b2e745c7710601f0b6 Mon Sep 17 00:00:00 2001 From: Kitteh Date: Thu, 13 May 2021 06:22:54 +0100 Subject: [PATCH] Add the ability to create new TOTP engines. --- src/allPages.ts | 6 ++- src/api/sys/newMount.ts | 21 ++++---- src/pages/Home.ts | 20 ++++---- src/pages/NewEngines/NewKVEngine.ts | 9 ++-- src/pages/NewEngines/NewTOTPEngine.ts | 70 +++++++++++++++++++++++++++ src/pages/NewSecretsEngine.ts | 9 +++- src/translations/en.js | 8 ++- 7 files changed, 113 insertions(+), 30 deletions(-) create mode 100644 src/pages/NewEngines/NewTOTPEngine.ts diff --git a/src/allPages.ts b/src/allPages.ts index 2097c95..bec37ab 100644 --- a/src/allPages.ts +++ b/src/allPages.ts @@ -7,6 +7,9 @@ import { KeyValueVersionsPage } from "./pages/KeyValue/KeyValueVersions"; import { KeyValueViewPage } from "./pages/KeyValue/KeyValueView"; import { LoginPage } from "./pages/Login"; import { MePage } from "./pages/Me"; +import { NewKVEnginePage } from "./pages/NewEngines/NewKVEngine"; +import { NewSecretsEnginePage } from "./pages/NewSecretsEngine"; +import { NewTOTPEnginePage } from "./pages/NewEngines/NewTOTPEngine"; import { NewTOTPPage } from "./pages/TOTP/NewTOTP"; import { Page } from "./types/Page"; import { PwGenPage } from "./pages/PwGen"; @@ -19,8 +22,6 @@ import { TransitRewrapPage } from "./pages/Transit/TransitRewrap"; import { TransitViewPage } from "./pages/Transit/TransitView"; import { TransitViewSecretPage } from "./pages/Transit/TransitViewSecret"; import { UnsealPage } from "./pages/Unseal"; -import { NewSecretsEnginePage } from "./pages/NewSecretsEngine"; -import { NewKVEnginePage } from "./pages/NewEngines/NewKVEngine"; type pagesList = { [key: string]: Page; @@ -49,4 +50,5 @@ export const allPages: pagesList = { PW_GEN: new PwGenPage(), NEW_SECRETS_ENGINE: new NewSecretsEnginePage(), NEW_KV_ENGINE: new NewKVEnginePage(), + NEW_TOTP_ENGINE: new NewTOTPEnginePage(), }; diff --git a/src/api/sys/newMount.ts b/src/api/sys/newMount.ts index 2951bba..c91b12b 100644 --- a/src/api/sys/newMount.ts +++ b/src/api/sys/newMount.ts @@ -6,21 +6,18 @@ type NewMountParams = { type: string; options?: { version: string; - } -} + }; +}; export async function newMount(parms: NewMountParams): Promise { - const request = new Request( - appendAPIURL(removeDoubleSlash(`/v1/sys/mounts/${parms.name}`)), - { - method: "POST", - headers: { - "Content-Type": "application/json", - ...getHeaders(), - }, - body: JSON.stringify(parms), + const request = new Request(appendAPIURL(removeDoubleSlash(`/v1/sys/mounts/${parms.name}`)), { + method: "POST", + headers: { + "Content-Type": "application/json", + ...getHeaders(), }, - ); + body: JSON.stringify(parms), + }); const resp = await fetch(request); if (!resp.ok) { const data = (await resp.json()) as { errors?: string[] }; diff --git a/src/pages/Home.ts b/src/pages/Home.ts index 7c45c65..a8ba99a 100644 --- a/src/pages/Home.ts +++ b/src/pages/Home.ts @@ -1,12 +1,12 @@ import { MountType, getMounts } from "../api/sys/getMounts"; import { Page } from "../types/Page"; import { changePage, prePageChecks, setErrorText, setPageContent } from "../pageUtils"; +import { getCapabilitiesPath } from "../api/sys/getCapabilities"; import { lookupSelf } from "../api/sys/lookupSelf"; import { makeElement } from "../htmlUtils"; import { pageState } from "../globalPageState"; import { sortedObjectMap } from "../utils"; import i18next from "i18next"; -import { getCapabilitiesPath } from "../api/sys/getCapabilities"; export class HomePage extends Page { constructor() { @@ -64,14 +64,16 @@ export class HomePage extends Page { const mountsCapabilities = await getCapabilitiesPath("/sys/mounts"); if (mountsCapabilities.includes("sudo") && mountsCapabilities.includes("create")) { - textList.appendChild(makeElement({ - tag: "button", - text: i18next.t("home_new_secrets_engine_button"), - class: ["uk-button", "uk-button-primary", "uk-margin-top"], - onclick: async () => { - await changePage("NEW_SECRETS_ENGINE"); - }, - })); + textList.appendChild( + makeElement({ + tag: "button", + text: i18next.t("home_new_secrets_engine_button"), + class: ["uk-button", "uk-button-primary", "uk-margin-top"], + onclick: async () => { + await changePage("NEW_SECRETS_ENGINE"); + }, + }), + ); } pageState.currentBaseMount = ""; diff --git a/src/pages/NewEngines/NewKVEngine.ts b/src/pages/NewEngines/NewKVEngine.ts index b5f5362..260930a 100644 --- a/src/pages/NewEngines/NewKVEngine.ts +++ b/src/pages/NewEngines/NewKVEngine.ts @@ -3,10 +3,9 @@ import { Option } from "../../elements/Option"; import { Page } from "../../types/Page"; import { changePage, setErrorText, setPageContent } from "../../pageUtils"; import { makeElement } from "../../htmlUtils"; +import { newMount } from "../../api/sys/newMount"; import { pageState } from "../../globalPageState"; -import { reloadNavBar } from "../../elements/NavBar"; import i18next from "i18next"; -import {newMount} from "../../api/sys/newMount"; export class NewKVEnginePage extends Page { constructor() { @@ -38,7 +37,7 @@ export class NewKVEnginePage extends Page { children: [ Option(i18next.t("new_kv_engine_version_2"), "2"), Option(i18next.t("new_kv_engine_version_1"), "1"), - ] + ], }), ), makeElement({ @@ -71,8 +70,8 @@ export class NewKVEnginePage extends Page { name: name, type: "kv", options: { - version: version - } + version: version, + }, }); pageState.currentMountType = "kv-v" + version; pageState.currentBaseMount = name + "/"; diff --git a/src/pages/NewEngines/NewTOTPEngine.ts b/src/pages/NewEngines/NewTOTPEngine.ts new file mode 100644 index 0000000..3f95239 --- /dev/null +++ b/src/pages/NewEngines/NewTOTPEngine.ts @@ -0,0 +1,70 @@ +import { Margin } from "../../elements/Margin"; +import { Page } from "../../types/Page"; +import { changePage, setErrorText, setPageContent } from "../../pageUtils"; +import { makeElement } from "../../htmlUtils"; +import { newMount } from "../../api/sys/newMount"; +import { pageState } from "../../globalPageState"; +import i18next from "i18next"; + +export class NewTOTPEnginePage extends Page { + constructor() { + super(); + } + async render(): Promise { + const newEngineForm = makeElement({ + tag: "form", + children: [ + Margin( + makeElement({ + tag: "input", + class: ["uk-input", "uk-form-width-medium"], + attributes: { + required: "true", + type: "text", + placeholder: i18next.t("new_totp_engine_name_input"), + name: "name", + }, + }), + ), + makeElement({ + tag: "p", + id: "errorText", + class: "uk-text-danger", + }), + makeElement({ + tag: "button", + class: ["uk-button", "uk-button-primary"], + text: i18next.t("new_totp_engine_create_btn"), + attributes: { + type: "submit", + }, + }), + ], + }) as HTMLFormElement; + + setPageContent(newEngineForm); + + newEngineForm.addEventListener("submit", async function (e) { + e.preventDefault(); + const formData = new FormData(newEngineForm); + + const name = formData.get("name") as string; + + try { + await newMount({ + name: name, + type: "totp", + }); + pageState.currentMountType = "totp"; + pageState.currentBaseMount = name + "/"; + await changePage("TOTP"); + } catch (e) { + const error = e as Error; + setErrorText(error.message); + } + }); + } + get name(): string { + return i18next.t("new_totp_engine_title"); + } +} diff --git a/src/pages/NewSecretsEngine.ts b/src/pages/NewSecretsEngine.ts index 3c91554..340f49a 100644 --- a/src/pages/NewSecretsEngine.ts +++ b/src/pages/NewSecretsEngine.ts @@ -1,6 +1,6 @@ import { Page } from "../types/Page"; import { Tile } from "../elements/Tile"; -import { changePage, setPageContent, setTitleElement } from "../pageUtils"; +import { changePage, setPageContent } from "../pageUtils"; import { makeElement } from "../htmlUtils"; import i18next from "i18next"; @@ -23,6 +23,13 @@ export class NewSecretsEnginePage extends Page { void changePage("NEW_KV_ENGINE"); }, }), + Tile({ + title: i18next.t("new_secrets_engine_totp_title"), + description: i18next.t("new_secrets_engine_totp_description"), + onclick: () => { + void changePage("NEW_TOTP_ENGINE"); + }, + }), ], }), ); diff --git a/src/translations/en.js b/src/translations/en.js index 9821672..0ed5d5e 100644 --- a/src/translations/en.js +++ b/src/translations/en.js @@ -41,8 +41,10 @@ module.exports = { // New Secrets Engine Page new_secrets_engine_title: "New Secrets Engine", - new_secrets_engine_kv_title: "Key/Value Storage", + new_secrets_engine_kv_title: "Key/Value", new_secrets_engine_kv_description: "For storing key/value mapped secrets.", + new_secrets_engine_totp_title: "TOTP", + new_secrets_engine_totp_description: "For handing Time-based One Time Pass (TOTP) codes.", // New KV Engine Page new_kv_engine_title: "New Key/Value Engine", @@ -51,6 +53,10 @@ module.exports = { new_kv_engine_version_2: "Version 2", new_kv_engine_create_btn: "Create", + // New KV Engine Page + new_totp_engine_title: "New TOTP Engine", + new_totp_engine_name_input: "Name", + new_totp_engine_create_btn: "Create", // Unseal Page unseal_vault_text: "Unseal the Vault",