1
0
Fork 0

Implement deleting of TOTP codes. Closes #2.

This commit is contained in:
Kitteh 2021-05-22 15:40:03 +01:00
parent 4d04070446
commit 1ccb432cbc
5 changed files with 93 additions and 2 deletions

View file

@ -26,6 +26,7 @@ import { PwGenPage } from "./pages/PwGen";
import { SecretsHomePage } from "./pages/Secrets/SecretsHome"; import { SecretsHomePage } from "./pages/Secrets/SecretsHome";
import { SetLanguagePage } from "./pages/SetLanguage"; import { SetLanguagePage } from "./pages/SetLanguage";
import { SetVaultURLPage } from "./pages/SetVaultURL"; import { SetVaultURLPage } from "./pages/SetVaultURL";
import { TOTPDeletePage } from "./pages/Secrets/TOTP/TOTPDelete";
import { TOTPViewPage } from "./pages/Secrets/TOTP/TOTPView"; import { TOTPViewPage } from "./pages/Secrets/TOTP/TOTPView";
import { TransitDecryptPage } from "./pages/Secrets/Transit/TransitDecrypt"; import { TransitDecryptPage } from "./pages/Secrets/Transit/TransitDecrypt";
import { TransitEncryptPage } from "./pages/Secrets/Transit/TransitEncrypt"; import { TransitEncryptPage } from "./pages/Secrets/Transit/TransitEncrypt";
@ -58,6 +59,7 @@ export const allPages: pagesList = {
ME: new MePage(), ME: new MePage(),
TOTP: new TOTPViewPage(), TOTP: new TOTPViewPage(),
NEW_TOTP: new NewTOTPPage(), NEW_TOTP: new NewTOTPPage(),
TOTP_DELETE: new TOTPDeletePage(),
LOGIN: new LoginPage(), LOGIN: new LoginPage(),
SET_VAULT_URL: new SetVaultURLPage(), SET_VAULT_URL: new SetVaultURLPage(),
UNSEAL: new UnsealPage(), UNSEAL: new UnsealPage(),

View file

@ -0,0 +1,15 @@
import { appendAPIURL, getHeaders } from "../apiUtils";
export async function deleteTOTP(baseMount: string, name: string): Promise<void> {
const request = new Request(appendAPIURL(`/v1/${baseMount}/keys/${name}`), {
method: "DELETE",
headers: getHeaders(),
});
const resp = await fetch(request);
if (!resp.ok) {
const data = (await resp.json()) as { errors?: string[] };
if ("errors" in data) {
throw new Error(data.errors[0]);
}
}
}

View file

@ -0,0 +1,45 @@
import { Page } from "../../../types/Page";
import { SecretTitleElement } from "../SecretTitleElement";
import { deleteTOTP } from "../../../api/totp/deleteTOTP";
import { render } from "preact";
import i18next from "i18next";
export class TOTPDeletePage extends Page {
constructor() {
super();
}
async cleanup(): Promise<void> {
this.state.secretItem = "";
}
async goBack(): Promise<void> {
this.state.secretItem = "";
await this.router.changePage("TOTP");
}
async render(): Promise<void> {
render(
<div>
<h5>{i18next.t("totp_delete_text")}</h5>
<button
class="uk-button uk-button-danger"
onClick={async () => {
await deleteTOTP(this.state.baseMount, this.state.secretItem);
await this.goBack();
}}
>
{i18next.t("kv_delete_btn")}
</button>
</div>,
this.router.pageContentElement,
);
}
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("totp_delete_suffix"));
}
get name(): string {
return i18next.t("totp_delete_title");
}
}

View file

@ -1,7 +1,10 @@
import { Component, JSX, render } from "preact"; import { Component, JSX, render } from "preact";
import { CopyableInputBox } from "../../../elements/ReactCopyableInputBox"; import { CopyableInputBox } from "../../../elements/ReactCopyableInputBox";
import { DoesNotExistError } from "../../../types/internalErrors"; import { DoesNotExistError } from "../../../types/internalErrors";
import { MarginInline } from "../../../elements/ReactMarginInline";
import { Page } from "../../../types/Page"; import { Page } from "../../../types/Page";
import { PageRouter } from "z-pagerouter";
import { PageState } from "../../../PageState";
import { SecretTitleElement } from "../SecretTitleElement"; import { SecretTitleElement } from "../SecretTitleElement";
import { getTOTPCode } from "../../../api/totp/getTOTPCode"; import { getTOTPCode } from "../../../api/totp/getTOTPCode";
import { getTOTPKeys } from "../../../api/totp/getTOTPKeys"; import { getTOTPKeys } from "../../../api/totp/getTOTPKeys";
@ -9,7 +12,7 @@ import { setErrorText } from "../../../pageUtils";
import i18next from "i18next"; import i18next from "i18next";
export class RefreshingTOTPGridItem extends Component< export class RefreshingTOTPGridItem extends Component<
{ baseMount: string; totpKey: string }, { baseMount: string; totpKey: string; router: PageRouter },
{ totpValue: string } { totpValue: string }
> { > {
constructor() { constructor() {
@ -36,6 +39,20 @@ export class RefreshingTOTPGridItem extends Component<
<div class="uk-grid uk-grid-small uk-text-left" uk-grid> <div class="uk-grid uk-grid-small uk-text-left" uk-grid>
<CopyableInputBox text={this.props.totpKey} copyable /> <CopyableInputBox text={this.props.totpKey} copyable />
<CopyableInputBox text={this.state.totpValue} copyable /> <CopyableInputBox text={this.state.totpValue} copyable />
<div>
<MarginInline>
<button
class="uk-button uk-button-danger"
onClick={async () => {
const state = this.props.router.state as PageState;
state.secretItem = this.props.totpKey;
await this.props.router.changePage("TOTP_DELETE");
}}
>
{i18next.t("totp_view_delete_btn")}
</button>
</MarginInline>
</div>
</div> </div>
); );
} }
@ -54,6 +71,7 @@ export class TOTPViewPage extends Page {
} }
async render(): Promise<void> { async render(): Promise<void> {
this.state.secretItem = "";
render( render(
<div> <div>
<button <button
@ -72,7 +90,11 @@ export class TOTPViewPage extends Page {
try { try {
const elem = await Promise.all( const elem = await Promise.all(
Array.from(await getTOTPKeys(this.state.baseMount)).map(async (key) => ( Array.from(await getTOTPKeys(this.state.baseMount)).map(async (key) => (
<RefreshingTOTPGridItem baseMount={this.state.baseMount} totpKey={key} /> <RefreshingTOTPGridItem
baseMount={this.state.baseMount}
totpKey={key}
router={this.router}
/>
)), )),
); );
return elem; return elem;

View file

@ -146,6 +146,7 @@ module.exports = {
// TOTP View Page // TOTP View Page
totp_view_title: "TOTP", totp_view_title: "TOTP",
totp_view_new_btn: "New", totp_view_new_btn: "New",
totp_view_delete_btn: "Delete",
totp_view_loading: "Loading TOTP Codes..", totp_view_loading: "Loading TOTP Codes..",
totp_view_empty: "You seem to have no TOTP codes here, would you like to create one?", totp_view_empty: "You seem to have no TOTP codes here, would you like to create one?",
totp_view_loading_box: "Loading..", totp_view_loading_box: "Loading..",
@ -160,6 +161,12 @@ module.exports = {
totp_new_key_input: "Key", totp_new_key_input: "Key",
totp_new_add_btn: "Add TOTP Key", totp_new_add_btn: "Add TOTP Key",
// TOTP Delete Page
totp_delete_title: "Delete TOTP Key",
totp_delete_suffix: " (delete)",
totp_delete_text: "Are you sure you want to delete this TOTP secret?",
totp_delete_button: "Delete",
// Transit View Page // Transit View Page
transit_view_title: "Transit View", transit_view_title: "Transit View",
transit_view_none_here_text: transit_view_none_here_text: