From a8add31ff1318f8853885e0e675e126d0dfdde30 Mon Sep 17 00:00:00 2001 From: ChaotiCryptidz Date: Tue, 11 Jan 2022 14:41:33 +0000 Subject: [PATCH] Add KV secret version viewing again --- src/api/API.ts | 71 ++++++++-- src/pages.tsx | 12 +- .../pages/Secrets/KeyValue/KeyValueDelete.tsx | 12 +- .../Secrets/KeyValue/KeyValueVersions.tsx | 55 ++++++++ .../pages/Secrets/KeyValue/KeyValueView.tsx | 122 ++++++++++++++---- src/ui/pages/pageLinks.tsx | 12 +- 6 files changed, 243 insertions(+), 41 deletions(-) create mode 100644 src/ui/pages/Secrets/KeyValue/KeyValueVersions.tsx diff --git a/src/api/API.ts b/src/api/API.ts index 9db35e8..331cff7 100644 --- a/src/api/API.ts +++ b/src/api/API.ts @@ -18,7 +18,7 @@ import { SecretMetadataType } from "./types/secret"; import { Settings } from "../settings/Settings"; import { TokenInfo } from "./types/token"; import { UserType, UserTypeAPIResp } from "./types/user"; -import { removeDoubleSlash } from "../utils"; +import { getObjectKeys, removeDoubleSlash } from "../utils"; async function checkResponse(resp: Response): Promise { if (resp.ok) return; @@ -352,19 +352,67 @@ export class API { await checkResponse(resp); } - async deleteSecret(baseMount: string, secretPath: string[], name: string): Promise { + async deleteSecret( + baseMount: string, + secretPath: string[], + name: string, + version: string = "null", + ): Promise { let secretURL = ""; + let request; + const mountInfo = await this.getMount(baseMount); - if (mountInfo.options.version == "2") { - secretURL = `/v1/${baseMount}/metadata/${secretPath.join("/")}/${name}`; + const mountVersion = mountInfo.options.version; + + if (mountVersion == "2" && version != "null") { + secretURL = `/v1/${baseMount}/delete/${secretPath.join("/")}/${name}`; + secretURL = removeDoubleSlash(secretURL).replace(/\/$/, ""); + request = new Request(this.appendAPIURL(secretURL), { + method: "POST", + headers: { + ...this.getHeaders(), + "Content-Type": "application/json", + }, + body: JSON.stringify({ versions: [version] }), + }); } else { - secretURL = `/v1/${baseMount}/${secretPath.join("/")}/${name}`; + if (mountVersion == "2") { + secretURL = `/v1/${baseMount}/metadata/${secretPath.join("/")}/${name}`; + } else { + secretURL = `/v1/${baseMount}/${secretPath.join("/")}/${name}`; + } + secretURL = removeDoubleSlash(secretURL).replace(/\/$/, ""); + request = new Request(this.appendAPIURL(secretURL), { + method: "DELETE", + headers: this.getHeaders(), + }); } + const resp = await fetch(request); + await checkResponse(resp); + } + + async undeleteSecret( + baseMount: string, + secretPath: string[], + name: string, + version: string = "null", + ): Promise { + let secretURL = `/v1/${baseMount}/undelete/${secretPath.join("/")}/${name}`; secretURL = removeDoubleSlash(secretURL).replace(/\/$/, ""); + if (version == "null") { + const meta = await this.getSecretMetadata(baseMount, secretPath, name); + const versions = getObjectKeys(meta.versions); + version = String(versions[versions.length - 1]); + } + const request = new Request(this.appendAPIURL(secretURL), { - method: "DELETE", - headers: this.getHeaders(), + method: "POST", + headers: { + ...this.getHeaders(), + "Content-Type": "application/json", + }, + body: JSON.stringify({ versions: [version] }), }); const resp = await fetch(request); await checkResponse(resp); @@ -376,7 +424,7 @@ export class API { name: string, ): Promise> { const request = new Request( - this.appendAPIURL(`/v1/${baseMount}/${secretPath.join("")}/${name}`), + this.appendAPIURL(`/v1/${baseMount}/${secretPath.join("/")}/${name}`), { headers: this.getHeaders(), }, @@ -394,10 +442,12 @@ export class API { baseMount: string, secretPath: string[], name: string, + version: string = "null", ): Promise> { let secretURL = ""; - secretURL = `/v1/${baseMount}/data/${secretPath.join("")}/${name}`; + secretURL = `/v1/${baseMount}/data/${secretPath.join("/")}/${name}`; + if (version != "null") secretURL += `?version=${version}`; const request = new Request(this.appendAPIURL(secretURL), { headers: this.getHeaders(), @@ -414,10 +464,11 @@ export class API { baseMount: string, secretPath: string[], name: string, + version: string = "null", ): Promise> { const mountInfo = await this.getMount(baseMount); if (mountInfo.options.version == "2") { - return await this.getSecretKV2(baseMount, secretPath, name); + return await this.getSecretKV2(baseMount, secretPath, name, version); } else { return await this.getSecretKV1(baseMount, secretPath, name); } diff --git a/src/pages.tsx b/src/pages.tsx index 57281a8..e4377ad 100644 --- a/src/pages.tsx +++ b/src/pages.tsx @@ -43,6 +43,7 @@ import { UserPassUserEdit } from "./ui/pages/Access/Auth/userpass/UserPassUserEd import { UserPassUserNew } from "./ui/pages/Access/Auth/userpass/UserPassUserNew"; import { UserPassUserView } from "./ui/pages/Access/Auth/userpass/UserPassUserView"; import { UserPassUsersList } from "./ui/pages/Access/Auth/userpass/UserPassUsersList"; +import { KeyValueVersions } from "./ui/pages/Secrets/KeyValue/KeyValueVersions"; export const Main = () => ( @@ -65,7 +66,12 @@ export const Main = () => ( + @@ -75,7 +81,7 @@ export const Main = () => ( api={api} /> @@ -83,7 +89,7 @@ export const Main = () => ( - + diff --git a/src/ui/pages/Secrets/KeyValue/KeyValueDelete.tsx b/src/ui/pages/Secrets/KeyValue/KeyValueDelete.tsx index e199e31..014fd0d 100644 --- a/src/ui/pages/Secrets/KeyValue/KeyValueDelete.tsx +++ b/src/ui/pages/Secrets/KeyValue/KeyValueDelete.tsx @@ -2,12 +2,15 @@ import { Component } from "preact"; import { DefaultPageProps } from "../../../../types/DefaultPageProps"; import { SecretTitleElement } from "../SecretTitleElement"; import i18next from "i18next"; +import { route } from "preact-router"; +import { kvListURL, kvViewURL } from "../../pageLinks"; export class KeyValueDelete extends Component { render() { const baseMount = this.props.matches["baseMount"]; const secretPath = this.props.matches["secretPath"].split("/"); const item = this.props.matches["item"]; + const version = this.props.matches["version"]; return ( <> @@ -23,8 +26,13 @@ export class KeyValueDelete extends Component { - )} - {this.state.caps.includes("update") && ( + { + // Delete Button + !this.state.isDeleted && this.state.caps.includes("delete") && ( + + ) + } + {this.state.secretVersion == "null" && this.state.caps.includes("update") && ( )} + {!this.state.isDeleted && this.state.kvVersion == "2" && ( + + )} +

- {} + {!this.state.isDeleted && } + + {this.state.isDeleted && ( + <> +

{i18next.t("kv_secret_deleted_text")}

+ + + )} ); diff --git a/src/ui/pages/pageLinks.tsx b/src/ui/pages/pageLinks.tsx index b9cdd0b..5d49da8 100644 --- a/src/ui/pages/pageLinks.tsx +++ b/src/ui/pages/pageLinks.tsx @@ -10,16 +10,20 @@ export function kvNewURL(baseMount: string, secretPath?: string[]): string { return `/secrets/kv/new/${baseMount}` + (secretPath ? `/${secretPath.join("/")}` : ""); } -export function kvDeleteURL(baseMount: string, secretPath: string[], secret: string): string { - return `/secrets/kv/delete/${secret}/${baseMount}/${secretPath.join("/")}`; +export function kvDeleteURL(baseMount: string, secretPath: string[], secret: string, version: string = "null"): string { + return `/secrets/kv/delete/${secret}/${version}/${baseMount}/${secretPath.join("/")}`; } export function kvEditURL(baseMount: string, secretPath: string[], secret: string): string { return `/secrets/kv/edit/${secret}/${baseMount}/${secretPath.join("/")}`; } -export function kvViewURL(baseMount: string, secretPath: string[], secret: string): string { - return `/secrets/kv/view/${secret}/${baseMount}/${secretPath.join("/")}`; +export function kvVersionsURL(baseMount: string, secretPath: string[], secret: string): string { + return `/secrets/kv/versions/${secret}/${baseMount}/${secretPath.join("/")}`; +} + +export function kvViewURL(baseMount: string, secretPath: string[], secret: string, version: string = "null"): string { + return `/secrets/kv/view/${secret}/${version}/${baseMount}/${secretPath.join("/")}`; } export function kvListURL(baseMount: string, secretPath: string[]): string {