get all secrets urls working
This commit is contained in:
parent
6131a13331
commit
ee93d882c8
35
src/main.tsx
35
src/main.tsx
|
@ -30,9 +30,9 @@ import { Component, render } from "preact";
|
||||||
import { DeleteSecretsEngine } from "./ui/pages/Secrets/DeleteSecretsEngine";
|
import { DeleteSecretsEngine } from "./ui/pages/Secrets/DeleteSecretsEngine";
|
||||||
import { Home } from "./ui/pages/Home";
|
import { Home } from "./ui/pages/Home";
|
||||||
import { KeyValueDelete } from "./ui/pages/Secrets/KeyValue/KeyValueDelete";
|
import { KeyValueDelete } from "./ui/pages/Secrets/KeyValue/KeyValueDelete";
|
||||||
import { KeyValueSecret } from "./ui/pages/Secrets/KeyValue/KeyValueSecret";
|
|
||||||
import { KeyValueSecretEdit } from "./ui/pages/Secrets/KeyValue/KeyValueSecretsEdit";
|
|
||||||
import { KeyValueView } from "./ui/pages/Secrets/KeyValue/KeyValueView";
|
import { KeyValueView } from "./ui/pages/Secrets/KeyValue/KeyValueView";
|
||||||
|
import { KeyValueEdit } from "./ui/pages/Secrets/KeyValue/KeyValueEdit";
|
||||||
|
import { KeyValueList } from "./ui/pages/Secrets/KeyValue/KeyValueList";
|
||||||
import { Login } from "./ui/pages/Login";
|
import { Login } from "./ui/pages/Login";
|
||||||
import { Me } from "./ui/pages/Me";
|
import { Me } from "./ui/pages/Me";
|
||||||
import { NavBar } from "./ui/elements/NavBar";
|
import { NavBar } from "./ui/elements/NavBar";
|
||||||
|
@ -40,21 +40,25 @@ import { NewKVEngine } from "./ui/pages/Secrets/NewEngines/NewKVEngine";
|
||||||
import { NewSecretsEngine } from "./ui/pages/Secrets/NewSecretsEngine";
|
import { NewSecretsEngine } from "./ui/pages/Secrets/NewSecretsEngine";
|
||||||
import { NewTOTPEngine } from "./ui/pages/Secrets/NewEngines/NewTOTPEngine";
|
import { NewTOTPEngine } from "./ui/pages/Secrets/NewEngines/NewTOTPEngine";
|
||||||
import { NewTransitEngine } from "./ui/pages/Secrets/NewEngines/NewTransitEngine";
|
import { NewTransitEngine } from "./ui/pages/Secrets/NewEngines/NewTransitEngine";
|
||||||
import { NewTransitKey } from "./ui/pages/Secrets/Transit/NewTransitKey";
|
import { TransitNew } from "./ui/pages/Secrets/Transit/TransitNew";
|
||||||
import { PasswordGenerator } from "./ui/pages/PwGen";
|
import { PasswordGenerator } from "./ui/pages/PwGen";
|
||||||
import { Secrets } from "./ui/pages/Secrets/SecretsHome";
|
import { Secrets } from "./ui/pages/Secrets/SecretsHome";
|
||||||
import { SetLanguage } from "./ui/pages/SetLanguage";
|
import { SetLanguage } from "./ui/pages/SetLanguage";
|
||||||
import { SetVaultURL } from "./ui/pages/SetVaultURL";
|
import { SetVaultURL } from "./ui/pages/SetVaultURL";
|
||||||
import { TOTPDelete } from "./ui/pages/Secrets/TOTP/TOTPDelete";
|
import { TOTPDelete } from "./ui/pages/Secrets/TOTP/TOTPDelete";
|
||||||
import { TOTPNew } from "./ui/pages/Secrets/TOTP/TOTPNew";
|
import { TOTPNew } from "./ui/pages/Secrets/TOTP/TOTPNew";
|
||||||
import { TOTPView } from "./ui/pages/Secrets/TOTP/TOTPView";
|
import { TOTPList } from "./ui/pages/Secrets/TOTP/TOTPList";
|
||||||
|
import { TransitList } from "./ui/pages/Secrets/Transit/TransitList";
|
||||||
import { TransitView } from "./ui/pages/Secrets/Transit/TransitView";
|
import { TransitView } from "./ui/pages/Secrets/Transit/TransitView";
|
||||||
import { TransitViewSecret } from "./ui/pages/Secrets/Transit/TransitViewSecret";
|
|
||||||
import { Unseal } from "./ui/pages/Unseal";
|
import { Unseal } from "./ui/pages/Unseal";
|
||||||
import { pageState } from "./globalPageState";
|
import { pageState } from "./globalPageState";
|
||||||
import { playground } from "./playground";
|
import { playground } from "./playground";
|
||||||
import Router from "preact-router";
|
import Router from "preact-router";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { KeyValueNew } from "./ui/pages/Secrets/KeyValue/KeyValueNew";
|
||||||
|
import { TransitDecrypt } from "./ui/pages/Secrets/Transit/TransitDecrypt";
|
||||||
|
import { TransitEncrypt } from "./ui/pages/Secrets/Transit/TransitEncrypt";
|
||||||
|
import { TransitRewrap } from "./ui/pages/Secrets/Transit/TransitRewrap";
|
||||||
|
|
||||||
async function onLoad(): Promise<void> {
|
async function onLoad(): Promise<void> {
|
||||||
const Main = () => (
|
const Main = () => (
|
||||||
|
@ -75,18 +79,23 @@ async function onLoad(): Promise<void> {
|
||||||
<NewTOTPEngine path="/secrets/new_secrets_engine/totp" />
|
<NewTOTPEngine path="/secrets/new_secrets_engine/totp" />
|
||||||
<NewTransitEngine path="/secrets/new_secrets_engine/trasit" />
|
<NewTransitEngine path="/secrets/new_secrets_engine/trasit" />
|
||||||
|
|
||||||
<KeyValueView path="/secrets/kv/list/:baseMount/:secretPath*?" state={pageState} />
|
<KeyValueNew path="/secrets/kv/new/:baseMount/:secretPath*?" state={pageState} />
|
||||||
<KeyValueSecret path="/secrets/kv/view/:item/:baseMount/:secretPath+" state={pageState} />
|
<KeyValueList path="/secrets/kv/list/:baseMount/:secretPath*?" state={pageState} />
|
||||||
<KeyValueSecretEdit path="/secrets/kv/edit/:item/:baseMount/:secretPath+" state={pageState} />
|
<KeyValueView path="/secrets/kv/view/:item/:baseMount/:secretPath*?" state={pageState} />
|
||||||
<KeyValueDelete path="/secrets/kv/delete/:item/:baseMount/:secretPath+" state={pageState} />
|
<KeyValueEdit path="/secrets/kv/edit/:item/:baseMount/:secretPath*?" state={pageState} />
|
||||||
|
<KeyValueDelete path="/secrets/kv/delete/:item/:baseMount/:secretPath*?" state={pageState} />
|
||||||
|
|
||||||
<TOTPView path="/secrets/totp/list/:baseMount" state={pageState} />
|
<TOTPList path="/secrets/totp/list/:baseMount" state={pageState} />
|
||||||
<TOTPNew path="/secrets/totp/new/:baseMount" state={pageState} />
|
<TOTPNew path="/secrets/totp/new/:baseMount" state={pageState} />
|
||||||
<TOTPDelete path="/secrets/totp/delete/:baseMount/:item" state={pageState} />
|
<TOTPDelete path="/secrets/totp/delete/:baseMount/:item" state={pageState} />
|
||||||
|
|
||||||
<TransitView path="/secrets/transit/list/:baseMount" state={pageState} />
|
<TransitNew path="/secrets/transit/new/:baseMount" state={pageState} />
|
||||||
<TransitViewSecret path="/secrets/transit/view/:baseMount/:secretItem" state={pageState} />
|
<TransitList path="/secrets/transit/list/:baseMount" state={pageState} />
|
||||||
<NewTransitKey path="/secrets/transit/new/:baseMount" state={pageState} />
|
<TransitView path="/secrets/transit/view/:baseMount/:secretItem" state={pageState} />
|
||||||
|
<TransitEncrypt path="/secrets/transit/encrypt/:baseMount/:secretItem" state={pageState} />
|
||||||
|
<TransitDecrypt path="/secrets/transit/decrypt/:baseMount/:secretItem" state={pageState} />
|
||||||
|
<TransitRewrap path="/secrets/transit/rewrap/:baseMount/:secretItem" state={pageState} />
|
||||||
|
|
||||||
|
|
||||||
<div default>
|
<div default>
|
||||||
<p>PAGE NOT YET IMPLEMENTED</p>
|
<p>PAGE NOT YET IMPLEMENTED</p>
|
||||||
|
|
|
@ -104,7 +104,7 @@ export class KVEditor extends Component<KVEditProps, KVEditState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KeyValueSecretEdit extends Component<DefaultPageProps> {
|
export class KeyValueEdit extends Component<DefaultPageProps> {
|
||||||
render() {
|
render() {
|
||||||
const baseMount = this.props.matches["baseMount"];
|
const baseMount = this.props.matches["baseMount"];
|
||||||
const secretPath = this.props.matches["secretPath"].split("/");
|
const secretPath = this.props.matches["secretPath"].split("/");
|
209
src/ui/pages/Secrets/KeyValue/KeyValueList.tsx
Normal file
209
src/ui/pages/Secrets/KeyValue/KeyValueList.tsx
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
import { CapabilitiesType, getCapabilitiesPath } from "../../../../api/sys/getCapabilities";
|
||||||
|
import { Component, JSX, createRef, render } from "preact";
|
||||||
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
|
import { DoesNotExistError } from "../../../../types/internalErrors";
|
||||||
|
import { Page } from "../../../../types/Page";
|
||||||
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
|
import { delSecretsEngineURL, kvListURL, kvNewURL, kvViewURL } from "../../pageLinks";
|
||||||
|
import { getMount } from "../../../../api/sys/getMounts";
|
||||||
|
import { getSecrets } from "../../../../api/kv/getSecrets";
|
||||||
|
import { route } from "preact-router";
|
||||||
|
import { setErrorText } from "../../../../pageUtils";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
export type KVKeysListProps = DefaultPageProps & {
|
||||||
|
baseMount: string;
|
||||||
|
secretPath: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type KVKeysListState = {
|
||||||
|
dataLoaded: boolean;
|
||||||
|
keys: string[];
|
||||||
|
searchQuery: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function SecretsList(baseMount: string, secretPath: string[], secrets: string[]): JSX.Element[] {
|
||||||
|
return secrets.map((secret) => (
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
onClick={async () => {
|
||||||
|
console.log(baseMount, secretPath, secret);
|
||||||
|
if (secret.endsWith("/")) {
|
||||||
|
route(
|
||||||
|
kvListURL(
|
||||||
|
baseMount,
|
||||||
|
[...secretPath, secret.replace("/", "")].filter((e) => e.length > 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
route(kvViewURL(baseMount, secretPath, secret));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{secret}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
export class KVKeysList extends Component<KVKeysListProps, KVKeysListState> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
dataLoaded: false,
|
||||||
|
keys: [],
|
||||||
|
searchQuery: "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadData(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const keys = await getSecrets(this.props.baseMount, this.props.secretPath);
|
||||||
|
this.setState({
|
||||||
|
dataLoaded: true,
|
||||||
|
keys: keys,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
} catch (e: unknown) {
|
||||||
|
const error = e as Error;
|
||||||
|
if (error == DoesNotExistError) {
|
||||||
|
// getSecrets also 404's on no keys so dont go all the way back.
|
||||||
|
if (this.props.secretPath.length != 0) {
|
||||||
|
window.history.back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setErrorText(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
dataLoaded: true,
|
||||||
|
keys: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps: KVKeysListProps): void {
|
||||||
|
if (
|
||||||
|
prevProps.baseMount !== this.props.baseMount ||
|
||||||
|
prevProps.secretPath !== this.props.secretPath
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
dataLoaded: false,
|
||||||
|
});
|
||||||
|
void this.loadData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
void this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
searchBarRef = createRef();
|
||||||
|
|
||||||
|
render(): JSX.Element {
|
||||||
|
if (!this.state.dataLoaded) {
|
||||||
|
return <p>{i18next.t("content_loading")}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.keys == null) {
|
||||||
|
return <p>{i18next.t("kv_view_none_here_text")}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
ref={this.searchBarRef}
|
||||||
|
class="uk-input uk-form-width-medium uk-margin-bottom"
|
||||||
|
name="path"
|
||||||
|
placeholder={i18next.t("kv_view_search_input_text")}
|
||||||
|
onInput={async () => {
|
||||||
|
this.setState({
|
||||||
|
searchQuery: (this.searchBarRef.current as unknown as HTMLInputElement).value,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<ul class="uk-nav uk-nav-default">
|
||||||
|
{...((): JSX.Element[] => {
|
||||||
|
let secrets: string[] = this.state.keys;
|
||||||
|
if (this.state.searchQuery.length > 0) {
|
||||||
|
secrets = secrets.filter((secret) => secret.includes(this.state.searchQuery));
|
||||||
|
}
|
||||||
|
return SecretsList(this.props.baseMount, this.props.secretPath, secrets);
|
||||||
|
})()}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type KeyValueListState = {
|
||||||
|
pathCaps: string[];
|
||||||
|
mountCaps: string[];
|
||||||
|
mountType: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class KeyValueList extends Component<DefaultPageProps, KeyValueListState> {
|
||||||
|
async componentDidMount() {
|
||||||
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const secretPath = this.props.matches["secretPath"].split("/");
|
||||||
|
|
||||||
|
const mountsPath = "/sys/mounts/" + baseMount;
|
||||||
|
const currentPath = baseMount + secretPath.join();
|
||||||
|
const caps = await getCapabilitiesPath([mountsPath, currentPath]);
|
||||||
|
|
||||||
|
const mount = await getMount(baseMount);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
mountCaps: caps[mountsPath],
|
||||||
|
pathCaps: caps[currentPath],
|
||||||
|
mountType: mount.type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.state.pathCaps) return;
|
||||||
|
|
||||||
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const secretPath = this.props.matches["secretPath"].split("/");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SecretTitleElement
|
||||||
|
type="kv"
|
||||||
|
baseMount={baseMount}
|
||||||
|
secretPath={secretPath}
|
||||||
|
item={this.props.matches["item"]}
|
||||||
|
/>
|
||||||
|
<p>
|
||||||
|
{this.state.pathCaps.includes("create") && (
|
||||||
|
<button
|
||||||
|
class="uk-button uk-button-primary"
|
||||||
|
onClick={() => {
|
||||||
|
console.log(kvNewURL(baseMount, secretPath));
|
||||||
|
|
||||||
|
route(kvNewURL(baseMount, secretPath));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18next.t("kv_view_new_btn")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{secretPath.length == 0 && this.state.mountCaps.includes("delete") && (
|
||||||
|
<button
|
||||||
|
class="uk-button uk-button-danger"
|
||||||
|
onClick={async () => {
|
||||||
|
route(delSecretsEngineURL(baseMount));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18next.t("kv_view_delete_btn")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
{this.state.mountType == "cubbyhole" && <p>{i18next.t("kv_view_cubbyhole_text")}</p>}
|
||||||
|
<KVKeysList baseMount={baseMount} secretPath={secretPath} state={this.props.state} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ import { route } from "preact-router";
|
||||||
import { setErrorText } from "../../../../pageUtils";
|
import { setErrorText } from "../../../../pageUtils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export class KeyValueNewPage extends Component<DefaultPageProps> {
|
export class KeyValueNew extends Component<DefaultPageProps> {
|
||||||
render() {
|
render() {
|
||||||
const baseMount = this.props.matches["baseMount"];
|
const baseMount = this.props.matches["baseMount"];
|
||||||
const secretPath = (this.props.matches["secretPath"] || "").split("/");
|
const secretPath = (this.props.matches["secretPath"] || "").split("/");
|
||||||
|
|
|
@ -1,121 +0,0 @@
|
||||||
import { CodeBlock } from "../../../elements/CodeBlock";
|
|
||||||
import { Component, JSX, render } from "preact";
|
|
||||||
import { CopyableInputBox } from "../../../elements/CopyableInputBox";
|
|
||||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
|
||||||
import { Grid, GridSizes } from "../../../elements/Grid";
|
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
|
||||||
import { getCapabilities } from "../../../../api/sys/getCapabilities";
|
|
||||||
import { getSecret } from "../../../../api/kv/getSecret";
|
|
||||||
import { kvDeleteURL, kvEditURL } from "../../pageLinks";
|
|
||||||
import { route } from "preact-router";
|
|
||||||
import { sortedObjectMap } from "../../../../utils";
|
|
||||||
import i18next from "i18next";
|
|
||||||
|
|
||||||
export type KVSecretViewProps = {
|
|
||||||
kvData: Record<string, unknown>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class KVSecretVew extends Component<KVSecretViewProps, unknown> {
|
|
||||||
render(): JSX.Element {
|
|
||||||
const secretsMap = sortedObjectMap(this.props.kvData);
|
|
||||||
let isMultiLevelJSON = false;
|
|
||||||
|
|
||||||
for (const value of secretsMap.values()) {
|
|
||||||
if (typeof value == "object") isMultiLevelJSON = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMultiLevelJSON) {
|
|
||||||
const jsonText = JSON.stringify(Object.fromEntries(secretsMap), null, 4);
|
|
||||||
return <CodeBlock language="json" code={jsonText} />;
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{Array.from(secretsMap).map((data: [string, string]) => (
|
|
||||||
<Grid size={GridSizes.NORMAL}>
|
|
||||||
<CopyableInputBox text={data[0]} copyable />
|
|
||||||
<CopyableInputBox text={data[1]} copyable />
|
|
||||||
</Grid>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type KeyValueSecretState = {
|
|
||||||
baseMount: string;
|
|
||||||
secretPath: string[];
|
|
||||||
secretItem: string;
|
|
||||||
caps: string[];
|
|
||||||
secretInfo: Record<string, unknown>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class KeyValueSecret extends Component<DefaultPageProps, KeyValueSecretState> {
|
|
||||||
async componentDidMount() {
|
|
||||||
const baseMount = this.props.matches["baseMount"];
|
|
||||||
const secretPath = this.props.matches["secretPath"].split("/");
|
|
||||||
const secretItem = this.props.matches["item"];
|
|
||||||
|
|
||||||
const caps = (await getCapabilities(baseMount, secretPath, secretItem)).capabilities;
|
|
||||||
|
|
||||||
const secretPathAPI = secretPath.map((e) => e + "/");
|
|
||||||
// TODO: this is a big hacky, fix when redo how api arguments work
|
|
||||||
secretPathAPI[secretPathAPI.length - 1] = String(secretPathAPI[secretPathAPI.length - 1])
|
|
||||||
.replace("/", "")
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
const secretInfo = await getSecret(baseMount, secretPathAPI, secretItem);
|
|
||||||
this.setState({
|
|
||||||
baseMount,
|
|
||||||
secretPath,
|
|
||||||
secretItem,
|
|
||||||
caps,
|
|
||||||
secretInfo,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
render() {
|
|
||||||
if (!this.state.baseMount) return;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<SecretTitleElement
|
|
||||||
type="kv"
|
|
||||||
item={this.props.matches["item"]}
|
|
||||||
baseMount={this.state.baseMount}
|
|
||||||
secretPath={this.state.secretPath}
|
|
||||||
suffix={i18next.t("kv_sec_edit_suffix")}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<p id="buttonsBlock">
|
|
||||||
{this.state.caps.includes("delete") && (
|
|
||||||
<button
|
|
||||||
class="uk-button uk-button-danger"
|
|
||||||
onClick={async () => {
|
|
||||||
route(
|
|
||||||
kvDeleteURL(this.state.baseMount, this.state.secretPath, this.state.secretItem),
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18next.t("kv_secret_delete_btn")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{this.state.caps.includes("update") && (
|
|
||||||
<button
|
|
||||||
class="uk-button uk-button-primary"
|
|
||||||
onClick={async () => {
|
|
||||||
route(
|
|
||||||
kvEditURL(this.state.baseMount, this.state.secretPath, this.state.secretItem),
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18next.t("kv_secret_edit_btn")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{<KVSecretVew kvData={this.state.secretInfo} />}
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,210 +1,121 @@
|
||||||
import { CapabilitiesType, getCapabilitiesPath } from "../../../../api/sys/getCapabilities";
|
import { CodeBlock } from "../../../elements/CodeBlock";
|
||||||
import { Component, JSX, createRef, render } from "preact";
|
import { Component, JSX, render } from "preact";
|
||||||
|
import { CopyableInputBox } from "../../../elements/CopyableInputBox";
|
||||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
import { DoesNotExistError } from "../../../../types/internalErrors";
|
import { Grid, GridSizes } from "../../../elements/Grid";
|
||||||
import { Page } from "../../../../types/Page";
|
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
import { delSecretsEngineURL, kvListURL, kvNewURL, kvViewURL } from "../../pageLinks";
|
import { getCapabilities } from "../../../../api/sys/getCapabilities";
|
||||||
import { getMount } from "../../../../api/sys/getMounts";
|
import { getSecret } from "../../../../api/kv/getSecret";
|
||||||
import { getSecrets } from "../../../../api/kv/getSecrets";
|
import { kvDeleteURL, kvEditURL } from "../../pageLinks";
|
||||||
import { route } from "preact-router";
|
import { route } from "preact-router";
|
||||||
import { setErrorText } from "../../../../pageUtils";
|
import { sortedObjectMap } from "../../../../utils";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export type KVKeysListProps = DefaultPageProps & {
|
export type KVSecretViewProps = {
|
||||||
baseMount: string;
|
kvData: Record<string, unknown>;
|
||||||
secretPath: string[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type KVKeysListState = {
|
export class KVSecretVew extends Component<KVSecretViewProps, unknown> {
|
||||||
dataLoaded: boolean;
|
|
||||||
keys: string[];
|
|
||||||
searchQuery: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
function SecretsList(baseMount: string, secretPath: string[], secrets: string[]): JSX.Element[] {
|
|
||||||
return secrets.map((secret) => (
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
onClick={async () => {
|
|
||||||
console.log(baseMount, secretPath, secret);
|
|
||||||
if (secret.endsWith("/")) {
|
|
||||||
route(
|
|
||||||
kvListURL(
|
|
||||||
baseMount,
|
|
||||||
[...secretPath, secret.replace("/", "")].filter((e) => e.length > 0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
route(kvViewURL(baseMount, secretPath, secret));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{secret}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
export class KVKeysList extends Component<KVKeysListProps, KVKeysListState> {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.state = {
|
|
||||||
dataLoaded: false,
|
|
||||||
keys: [],
|
|
||||||
searchQuery: "",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async loadData(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const keys = await getSecrets(this.props.baseMount, this.props.secretPath);
|
|
||||||
this.setState({
|
|
||||||
dataLoaded: true,
|
|
||||||
keys: keys,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
} catch (e: unknown) {
|
|
||||||
const error = e as Error;
|
|
||||||
if (error == DoesNotExistError) {
|
|
||||||
// getSecrets also 404's on no keys so dont go all the way back.
|
|
||||||
if (this.props.secretPath.length != 0) {
|
|
||||||
window.history.back();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setErrorText(error.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
dataLoaded: true,
|
|
||||||
keys: null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps: KVKeysListProps): void {
|
|
||||||
if (
|
|
||||||
prevProps.baseMount !== this.props.baseMount ||
|
|
||||||
prevProps.secretPath !== this.props.secretPath
|
|
||||||
) {
|
|
||||||
this.setState({
|
|
||||||
dataLoaded: false,
|
|
||||||
});
|
|
||||||
void this.loadData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
void this.loadData();
|
|
||||||
}
|
|
||||||
|
|
||||||
searchBarRef = createRef();
|
|
||||||
|
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
if (!this.state.dataLoaded) {
|
const secretsMap = sortedObjectMap(this.props.kvData);
|
||||||
return <p>{i18next.t("content_loading")}</p>;
|
let isMultiLevelJSON = false;
|
||||||
}
|
|
||||||
|
for (const value of secretsMap.values()) {
|
||||||
if (this.state.keys == null) {
|
if (typeof value == "object") isMultiLevelJSON = true;
|
||||||
return <p>{i18next.t("kv_view_none_here_text")}</p>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isMultiLevelJSON) {
|
||||||
|
const jsonText = JSON.stringify(Object.fromEntries(secretsMap), null, 4);
|
||||||
|
return <CodeBlock language="json" code={jsonText} />;
|
||||||
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<input
|
{Array.from(secretsMap).map((data: [string, string]) => (
|
||||||
ref={this.searchBarRef}
|
<Grid size={GridSizes.NORMAL}>
|
||||||
class="uk-input uk-form-width-medium uk-margin-bottom"
|
<CopyableInputBox text={data[0]} copyable />
|
||||||
name="path"
|
<CopyableInputBox text={data[1]} copyable />
|
||||||
placeholder={i18next.t("kv_view_search_input_text")}
|
</Grid>
|
||||||
onInput={async () => {
|
))}
|
||||||
this.setState({
|
|
||||||
searchQuery: (this.searchBarRef.current as unknown as HTMLInputElement).value,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
<ul class="uk-nav uk-nav-default">
|
|
||||||
{...((): JSX.Element[] => {
|
|
||||||
let secrets: string[] = this.state.keys;
|
|
||||||
if (this.state.searchQuery.length > 0) {
|
|
||||||
secrets = secrets.filter((secret) => secret.includes(this.state.searchQuery));
|
|
||||||
}
|
|
||||||
return SecretsList(this.props.baseMount, this.props.secretPath, secrets);
|
|
||||||
})()}
|
|
||||||
</ul>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyValueViewState = {
|
type KeyValueViewState = {
|
||||||
pathCaps: string[];
|
baseMount: string;
|
||||||
mountCaps: string[];
|
secretPath: string[];
|
||||||
mountType: string;
|
secretItem: string;
|
||||||
|
caps: string[];
|
||||||
|
secretInfo: Record<string, unknown>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class KeyValueView extends Component<DefaultPageProps, KeyValueViewState> {
|
export class KeyValueView extends Component<DefaultPageProps, KeyValueViewState> {
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const baseMount = this.props.matches["baseMount"];
|
const baseMount = this.props.matches["baseMount"];
|
||||||
const secretPath = this.props.matches["secretPath"].split("/");
|
const secretPath = this.props.matches["secretPath"].split("/");
|
||||||
|
const secretItem = this.props.matches["item"];
|
||||||
|
|
||||||
const mountsPath = "/sys/mounts/" + baseMount;
|
const caps = (await getCapabilities(baseMount, secretPath, secretItem)).capabilities;
|
||||||
const currentPath = baseMount + secretPath.join();
|
|
||||||
const caps = await getCapabilitiesPath([mountsPath, currentPath]);
|
|
||||||
|
|
||||||
const mount = await getMount(baseMount);
|
const secretPathAPI = secretPath.map((e) => e + "/");
|
||||||
|
// TODO: this is a big hacky, fix when redo how api arguments work
|
||||||
|
secretPathAPI[secretPathAPI.length - 1] = String(secretPathAPI[secretPathAPI.length - 1])
|
||||||
|
.replace("/", "")
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
const secretInfo = await getSecret(baseMount, secretPathAPI, secretItem);
|
||||||
this.setState({
|
this.setState({
|
||||||
mountCaps: caps[mountsPath],
|
baseMount,
|
||||||
pathCaps: caps[currentPath],
|
secretPath,
|
||||||
mountType: mount.type,
|
secretItem,
|
||||||
|
caps,
|
||||||
|
secretInfo,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.state.pathCaps) return;
|
if (!this.state.baseMount) return;
|
||||||
|
|
||||||
const baseMount = this.props.matches["baseMount"];
|
|
||||||
const secretPath = this.props.matches["secretPath"].split("/");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SecretTitleElement
|
<SecretTitleElement
|
||||||
type="kv"
|
type="kv"
|
||||||
baseMount={baseMount}
|
|
||||||
secretPath={secretPath}
|
|
||||||
item={this.props.matches["item"]}
|
item={this.props.matches["item"]}
|
||||||
|
baseMount={this.state.baseMount}
|
||||||
|
secretPath={this.state.secretPath}
|
||||||
|
suffix={i18next.t("kv_sec_edit_suffix")}
|
||||||
/>
|
/>
|
||||||
<p>
|
<div>
|
||||||
{this.state.pathCaps.includes("create") && (
|
<p id="buttonsBlock">
|
||||||
<button
|
{this.state.caps.includes("delete") && (
|
||||||
class="uk-button uk-button-primary"
|
|
||||||
onClick={async () => {
|
|
||||||
route(kvNewURL(baseMount, secretPath.length > 0 ? secretPath : null));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18next.t("kv_view_new_btn")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{secretPath.length == 0 && this.state.mountCaps.includes("delete") && (
|
|
||||||
<button
|
<button
|
||||||
class="uk-button uk-button-danger"
|
class="uk-button uk-button-danger"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
route(delSecretsEngineURL(baseMount));
|
route(
|
||||||
|
kvDeleteURL(this.state.baseMount, this.state.secretPath, this.state.secretItem),
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{i18next.t("kv_view_delete_btn")}
|
{i18next.t("kv_secret_delete_btn")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{this.state.caps.includes("update") && (
|
||||||
|
<button
|
||||||
|
class="uk-button uk-button-primary"
|
||||||
|
onClick={async () => {
|
||||||
|
route(
|
||||||
|
kvEditURL(this.state.baseMount, this.state.secretPath, this.state.secretItem),
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18next.t("kv_secret_edit_btn")}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
{this.state.mountType == "cubbyhole" && <p>{i18next.t("kv_view_cubbyhole_text")}</p>}
|
|
||||||
<KVKeysList baseMount={baseMount} secretPath={secretPath} state={this.props.state} />
|
{<KVSecretVew kvData={this.state.secretInfo} />}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
get name(): string {
|
|
||||||
return i18next.t("kv_view_title");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,12 @@ import {
|
||||||
getCapabilitiesPath,
|
getCapabilitiesPath,
|
||||||
getCapsPath,
|
getCapsPath,
|
||||||
} from "../../../../api/sys/getCapabilities";
|
} from "../../../../api/sys/getCapabilities";
|
||||||
import { Component, JSX, render } from "preact";
|
import { Component, JSX } from "preact";
|
||||||
import { CopyableInputBox } from "../../../elements/CopyableInputBox";
|
import { CopyableInputBox } from "../../../elements/CopyableInputBox";
|
||||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
import { DoesNotExistError } from "../../../../types/internalErrors";
|
import { DoesNotExistError } from "../../../../types/internalErrors";
|
||||||
import { Grid, GridSizes } from "../../../elements/Grid";
|
import { Grid, GridSizes } from "../../../elements/Grid";
|
||||||
import { MarginInline } from "../../../elements/MarginInline";
|
import { MarginInline } from "../../../elements/MarginInline";
|
||||||
import { Page } from "../../../../types/Page";
|
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
import { delSecretsEngineURL, totpNewURL } from "../../pageLinks";
|
import { delSecretsEngineURL, totpNewURL } from "../../pageLinks";
|
||||||
import { getTOTPCode } from "../../../../api/totp/getTOTPCode";
|
import { getTOTPCode } from "../../../../api/totp/getTOTPCode";
|
||||||
|
@ -73,12 +72,12 @@ export class RefreshingTOTPGridItem extends Component<TOTPGridItemProps, { totpV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TOTPViewState = {
|
type TOTPListState = {
|
||||||
capabilities?: CapabilitiesType;
|
capabilities?: CapabilitiesType;
|
||||||
totpItems: TOTPGridItemProps[];
|
totpItems: TOTPGridItemProps[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export class TOTPView extends Component<DefaultPageProps, TOTPViewState> {
|
export class TOTPList extends Component<DefaultPageProps, TOTPListState> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.refresher = undefined;
|
this.refresher = undefined;
|
|
@ -3,26 +3,27 @@ import { FileUploadInput } from "../../../elements/FileUploadInput";
|
||||||
import { Form } from "../../../elements/Form";
|
import { Form } from "../../../elements/Form";
|
||||||
import { InputWithTitle } from "../../../elements/InputWithTitle";
|
import { InputWithTitle } from "../../../elements/InputWithTitle";
|
||||||
import { Margin } from "../../../elements/Margin";
|
import { Margin } from "../../../elements/Margin";
|
||||||
import { Page } from "../../../../types/Page";
|
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
import { fileToBase64 } from "../../../../htmlUtils";
|
import { fileToBase64 } from "../../../../htmlUtils";
|
||||||
import { render } from "preact";
|
import { Component, render } from "preact";
|
||||||
import { setErrorText } from "../../../../pageUtils";
|
import { setErrorText } from "../../../../pageUtils";
|
||||||
import { transitDecrypt } from "../../../../api/transit/transitDecrypt";
|
import { transitDecrypt } from "../../../../api/transit/transitDecrypt";
|
||||||
import UIkit from "uikit";
|
import UIkit from "uikit";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
|
|
||||||
export class TransitDecryptPage extends Page {
|
export class TransitDecrypt extends Component<DefaultPageProps> {
|
||||||
constructor() {
|
render() {
|
||||||
super();
|
const baseMount = this.props.matches["baseMount"];
|
||||||
}
|
const secretItem = this.props.matches["secretItem"];
|
||||||
|
return (
|
||||||
async goBack(): Promise<void> {
|
<>
|
||||||
await this.router.changePage("TRANSIT_VIEW_SECRET");
|
<SecretTitleElement
|
||||||
}
|
type="transit"
|
||||||
|
baseMount={baseMount}
|
||||||
async render(): Promise<void> {
|
item={secretItem}
|
||||||
render(
|
suffix={i18next.t("transit_decrypt_suffix")}
|
||||||
|
/>
|
||||||
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
||||||
<Margin>
|
<Margin>
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -42,12 +43,15 @@ export class TransitDecryptPage extends Page {
|
||||||
{i18next.t("transit_decrypt_decrypt_btn")}
|
{i18next.t("transit_decrypt_decrypt_btn")}
|
||||||
</button>
|
</button>
|
||||||
<div id="modalAttachmentPoint" />
|
<div id="modalAttachmentPoint" />
|
||||||
</Form>,
|
</Form>
|
||||||
this.router.pageContentElement,
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSubmit(data: FormData): Promise<void> {
|
async onSubmit(data: FormData): Promise<void> {
|
||||||
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const secretItem = this.props.matches["secretItem"];
|
||||||
|
|
||||||
const decodeBase64 = data.get("decodeBase64Checkbox") as string;
|
const decodeBase64 = data.get("decodeBase64Checkbox") as string;
|
||||||
|
|
||||||
let ciphertext = data.get("ciphertext") as string;
|
let ciphertext = data.get("ciphertext") as string;
|
||||||
|
@ -60,7 +64,7 @@ export class TransitDecryptPage extends Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await transitDecrypt(this.state.baseMount, this.state.secretItem, {
|
const res = await transitDecrypt(baseMount, secretItem, {
|
||||||
ciphertext: ciphertext,
|
ciphertext: ciphertext,
|
||||||
});
|
});
|
||||||
let plaintext = res.plaintext;
|
let plaintext = res.plaintext;
|
||||||
|
@ -81,15 +85,4 @@ export class TransitDecryptPage extends Page {
|
||||||
setErrorText(`API Error: ${error.message}`);
|
setErrorText(`API Error: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//async renderPageTitle(): Promise<void> {
|
|
||||||
// render(
|
|
||||||
// <SecretTitleElement page={this} suffix={i18next.t("transit_decrypt_suffix")} />,
|
|
||||||
// this.router.pageTitleElement,
|
|
||||||
// );
|
|
||||||
//}
|
|
||||||
|
|
||||||
get name(): string {
|
|
||||||
return i18next.t("transit_decrypt_title");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,26 +3,27 @@ import { FileUploadInput } from "../../../elements/FileUploadInput";
|
||||||
import { Form } from "../../../elements/Form";
|
import { Form } from "../../../elements/Form";
|
||||||
import { InputWithTitle } from "../../../elements/InputWithTitle";
|
import { InputWithTitle } from "../../../elements/InputWithTitle";
|
||||||
import { Margin } from "../../../elements/Margin";
|
import { Margin } from "../../../elements/Margin";
|
||||||
import { Page } from "../../../../types/Page";
|
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
import { fileToBase64 } from "../../../../htmlUtils";
|
import { fileToBase64 } from "../../../../htmlUtils";
|
||||||
import { render } from "preact";
|
import { Component, render } from "preact";
|
||||||
import { setErrorText } from "../../../../pageUtils";
|
import { setErrorText } from "../../../../pageUtils";
|
||||||
import { transitEncrypt } from "../../../../api/transit/transitEncrypt";
|
import { transitEncrypt } from "../../../../api/transit/transitEncrypt";
|
||||||
import UIkit from "uikit";
|
import UIkit from "uikit";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
|
|
||||||
export class TransitEncryptPage extends Page {
|
export class TransitEncrypt extends Component<DefaultPageProps> {
|
||||||
constructor() {
|
render() {
|
||||||
super();
|
const baseMount = this.props.matches["baseMount"];
|
||||||
}
|
const secretItem = this.props.matches["secretItem"];
|
||||||
|
return (
|
||||||
async goBack(): Promise<void> {
|
<>
|
||||||
await this.router.changePage("TRANSIT_VIEW_SECRET");
|
<SecretTitleElement
|
||||||
}
|
type="transit"
|
||||||
|
baseMount={baseMount}
|
||||||
async render(): Promise<void> {
|
item={secretItem}
|
||||||
render(
|
suffix={i18next.t("transit_encrypt_suffix")}
|
||||||
|
/>
|
||||||
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
||||||
<Margin>
|
<Margin>
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -42,12 +43,15 @@ export class TransitEncryptPage extends Page {
|
||||||
{i18next.t("transit_encrypt_encrypt_btn")}
|
{i18next.t("transit_encrypt_encrypt_btn")}
|
||||||
</button>
|
</button>
|
||||||
<div id="modalAttachmentPoint" />
|
<div id="modalAttachmentPoint" />
|
||||||
</Form>,
|
</Form>
|
||||||
this.router.pageContentElement,
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSubmit(data: FormData): Promise<void> {
|
async onSubmit(data: FormData): Promise<void> {
|
||||||
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const secretItem = this.props.matches["secretItem"];
|
||||||
|
|
||||||
const base64Checkbox = data.get("base64Checkbox") as string;
|
const base64Checkbox = data.get("base64Checkbox") as string;
|
||||||
|
|
||||||
let plaintext = data.get("plaintext") as string;
|
let plaintext = data.get("plaintext") as string;
|
||||||
|
@ -61,7 +65,7 @@ export class TransitEncryptPage extends Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await transitEncrypt(this.state.baseMount, this.state.secretItem, {
|
const res = await transitEncrypt(baseMount, secretItem, {
|
||||||
plaintext: plaintext,
|
plaintext: plaintext,
|
||||||
});
|
});
|
||||||
render(
|
render(
|
||||||
|
@ -78,15 +82,4 @@ export class TransitEncryptPage extends Page {
|
||||||
setErrorText(`API Error: ${error.message}`);
|
setErrorText(`API Error: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//async renderPageTitle(): Promise<void> {
|
|
||||||
// render(
|
|
||||||
// <SecretTitleElement page={this} suffix={i18next.t("transit_encrypt_suffix")} />,
|
|
||||||
// this.router.pageTitleElement,
|
|
||||||
// );
|
|
||||||
//}
|
|
||||||
|
|
||||||
get name(): string {
|
|
||||||
return i18next.t("transit_encrypt_title");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
119
src/ui/pages/Secrets/Transit/TransitList.tsx
Normal file
119
src/ui/pages/Secrets/Transit/TransitList.tsx
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
import { CapabilitiesType, getCapabilitiesPath } from "../../../../api/sys/getCapabilities";
|
||||||
|
import { Component, JSX, render } from "preact";
|
||||||
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
|
import { delSecretsEngineURL, transitNewSecretURL, transitViewSecretURL } from "../../pageLinks";
|
||||||
|
import { getTransitKeys } from "../../../../api/transit/getTransitKeys";
|
||||||
|
import { route } from "preact-router";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
type TransitViewListState = {
|
||||||
|
contentLoaded: boolean;
|
||||||
|
transitKeysList: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export class TransitViewListItem extends Component<{ baseMount: string }, TransitViewListState> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
contentLoaded: false,
|
||||||
|
transitKeysList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
timer: unknown;
|
||||||
|
|
||||||
|
getTransitKeys(): void {
|
||||||
|
void getTransitKeys(this.props.baseMount)
|
||||||
|
.then((keys) => {
|
||||||
|
this.setState({
|
||||||
|
contentLoaded: true,
|
||||||
|
transitKeysList: keys,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((_) => {
|
||||||
|
this.setState({
|
||||||
|
contentLoaded: true,
|
||||||
|
transitKeysList: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
this.getTransitKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): JSX.Element {
|
||||||
|
if (!this.state.contentLoaded) {
|
||||||
|
return <p>{i18next.t("content_loading")}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.transitKeysList.length == 0) {
|
||||||
|
return <p>{i18next.t("transit_view_none_here_text")}</p>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul class="uk-nav uk-nav-default">
|
||||||
|
{...this.state.transitKeysList.map((key) => (
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
onClick={async () => {
|
||||||
|
route(transitViewSecretURL(this.props.baseMount, key));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{key}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TransitList extends Component<DefaultPageProps, { caps: CapabilitiesType }> {
|
||||||
|
async componentDidMount() {
|
||||||
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const mountsPath = "/sys/mounts/" + baseMount;
|
||||||
|
|
||||||
|
const caps = await getCapabilitiesPath([mountsPath, baseMount]);
|
||||||
|
this.setState({ caps });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!this.state.caps) return;
|
||||||
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const mountsPath = "/sys/mounts/" + baseMount;
|
||||||
|
const mountCaps = this.state.caps[mountsPath];
|
||||||
|
const transitCaps = this.state.caps[baseMount];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SecretTitleElement type="transit" baseMount={baseMount} />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{transitCaps.includes("create") && (
|
||||||
|
<button
|
||||||
|
class="uk-button uk-button-primary"
|
||||||
|
onClick={async () => {
|
||||||
|
route(transitNewSecretURL(baseMount));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18next.t("transit_view_new_btn")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{mountCaps.includes("delete") && (
|
||||||
|
<button
|
||||||
|
class="uk-button uk-button-danger"
|
||||||
|
onClick={async () => {
|
||||||
|
route(delSecretsEngineURL(baseMount));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18next.t("transit_view_delete_btn")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<TransitViewListItem baseMount={baseMount} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ import { setErrorText } from "../../../../pageUtils";
|
||||||
import { transitViewSecretURL } from "../../pageLinks";
|
import { transitViewSecretURL } from "../../pageLinks";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
|
||||||
export class NewTransitKey extends Component<DefaultPageProps> {
|
export class TransitNew extends Component<DefaultPageProps> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
|
@ -1,33 +1,38 @@
|
||||||
import { CopyableModal } from "../../../elements/CopyableModal";
|
import { CopyableModal } from "../../../elements/CopyableModal";
|
||||||
import { Form } from "../../../elements/Form";
|
import { Form } from "../../../elements/Form";
|
||||||
import { Margin } from "../../../elements/Margin";
|
import { Margin } from "../../../elements/Margin";
|
||||||
import { Page } from "../../../../types/Page";
|
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
import { getTransitKey } from "../../../../api/transit/getTransitKey";
|
import { getTransitKey } from "../../../../api/transit/getTransitKey";
|
||||||
import { objectToMap } from "../../../../utils";
|
import { objectToMap } from "../../../../utils";
|
||||||
import { render } from "preact";
|
import { Component, render } from "preact";
|
||||||
import { setErrorText } from "../../../../pageUtils";
|
import { setErrorText } from "../../../../pageUtils";
|
||||||
import { transitRewrap } from "../../../../api/transit/transitRewrap";
|
import { transitRewrap } from "../../../../api/transit/transitRewrap";
|
||||||
import UIkit from "uikit";
|
import UIkit from "uikit";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
|
import { TransitKeyType } from "../../../../api/types/transit";
|
||||||
|
|
||||||
type versionOption = { version: string; label: string };
|
type versionOption = { version: string; label: string };
|
||||||
|
|
||||||
export class TransitRewrapPage extends Page {
|
export class TransitRewrap extends Component<DefaultPageProps, { transitKey: TransitKeyType }> {
|
||||||
constructor() {
|
async componentDidMount() {
|
||||||
super();
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const secretItem = this.props.matches["secretItem"];
|
||||||
|
this.setState({
|
||||||
|
transitKey: await getTransitKey(baseMount, secretItem)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async goBack(): Promise<void> {
|
render() {
|
||||||
await this.router.changePage("TRANSIT_VIEW_SECRET");
|
if (!this.state.transitKey) return;
|
||||||
}
|
|
||||||
|
|
||||||
async render(): Promise<void> {
|
const baseMount = this.props.matches["baseMount"];
|
||||||
const transitKey = await getTransitKey(this.state.baseMount, this.state.secretItem);
|
const secretItem = this.props.matches["secretItem"];
|
||||||
|
|
||||||
const stringVersions = Array.from(
|
const stringVersions = Array.from(
|
||||||
objectToMap(transitKey.keys).keys(),
|
objectToMap(this.state.transitKey.keys).keys(),
|
||||||
).reverse() as unknown as string[];
|
).reverse() as unknown as string[];
|
||||||
|
|
||||||
const versions = stringVersions.map((val): number => parseInt(val, 10));
|
const versions = stringVersions.map((val): number => parseInt(val, 10));
|
||||||
|
|
||||||
// get the selectable version options in the same
|
// get the selectable version options in the same
|
||||||
|
@ -45,7 +50,14 @@ export class TransitRewrapPage extends Page {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
render(
|
return (
|
||||||
|
<>
|
||||||
|
<SecretTitleElement
|
||||||
|
type="transit"
|
||||||
|
baseMount={baseMount}
|
||||||
|
item={secretItem}
|
||||||
|
suffix={i18next.t("transit_rewrap_suffix")}
|
||||||
|
/>
|
||||||
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
||||||
<Margin>
|
<Margin>
|
||||||
<select class="uk-select uk-width-1-2" name="version">
|
<select class="uk-select uk-width-1-2" name="version">
|
||||||
|
@ -68,14 +80,16 @@ export class TransitRewrapPage extends Page {
|
||||||
{i18next.t("transit_rewrap_rewrap_btn")}
|
{i18next.t("transit_rewrap_rewrap_btn")}
|
||||||
</button>
|
</button>
|
||||||
<div id="modalAttachmentPoint" />
|
<div id="modalAttachmentPoint" />
|
||||||
</Form>,
|
</Form>
|
||||||
this.router.pageContentElement,
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSubmit(data: FormData): Promise<void> {
|
async onSubmit(data: FormData): Promise<void> {
|
||||||
|
const baseMount = this.props.matches["baseMount"];
|
||||||
|
const secretItem = this.props.matches["secretItem"];
|
||||||
try {
|
try {
|
||||||
const res = await transitRewrap(this.state.baseMount, this.state.secretItem, {
|
const res = await transitRewrap(baseMount, secretItem, {
|
||||||
ciphertext: data.get("ciphertext") as string,
|
ciphertext: data.get("ciphertext") as string,
|
||||||
key_version: parseInt(data.get("version") as string, 10),
|
key_version: parseInt(data.get("version") as string, 10),
|
||||||
});
|
});
|
||||||
|
@ -93,15 +107,4 @@ export class TransitRewrapPage extends Page {
|
||||||
setErrorText(`API Error: ${error.message}`);
|
setErrorText(`API Error: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//async renderPageTitle(): Promise<void> {
|
|
||||||
// render(
|
|
||||||
// <SecretTitleElement page={this} suffix={i18next.t("transit_rewrap_suffix")} />,
|
|
||||||
// this.router.pageTitleElement,
|
|
||||||
// );
|
|
||||||
//}
|
|
||||||
|
|
||||||
get name(): string {
|
|
||||||
return i18next.t("transit_rewrap_title");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,118 +1,64 @@
|
||||||
import { CapabilitiesType, getCapabilitiesPath } from "../../../../api/sys/getCapabilities";
|
import { Component, render } from "preact";
|
||||||
import { Component, JSX, render } from "preact";
|
|
||||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||||
|
import { Grid, GridSizes } from "../../../elements/Grid";
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
import { SecretTitleElement } from "../SecretTitleElement";
|
||||||
import { delSecretsEngineURL, transitNewSecretURL, transitViewSecretURL } from "../../pageLinks";
|
import { Tile } from "../../../elements/Tile";
|
||||||
import { getTransitKeys } from "../../../../api/transit/getTransitKeys";
|
import { TransitKeyType } from "../../../../api/types/transit";
|
||||||
import { route } from "preact-router";
|
import { getTransitKey } from "../../../../api/transit/getTransitKey";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { route } from "preact-router";
|
||||||
|
import { transitDecryptSecretURL, transitEncryptSecretURL, transitRewrapSecretURL } from "../../pageLinks";
|
||||||
|
|
||||||
type TransitViewListState = {
|
export class TransitView extends Component<DefaultPageProps, { transitKey: TransitKeyType }> {
|
||||||
contentLoaded: boolean;
|
|
||||||
transitKeysList: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export class TransitViewListItem extends Component<{ baseMount: string }, TransitViewListState> {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.state = {
|
|
||||||
contentLoaded: false,
|
|
||||||
transitKeysList: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
timer: unknown;
|
|
||||||
|
|
||||||
getTransitKeys(): void {
|
|
||||||
void getTransitKeys(this.props.baseMount)
|
|
||||||
.then((keys) => {
|
|
||||||
this.setState({
|
|
||||||
contentLoaded: true,
|
|
||||||
transitKeysList: keys,
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((_) => {
|
|
||||||
this.setState({
|
|
||||||
contentLoaded: true,
|
|
||||||
transitKeysList: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount(): void {
|
|
||||||
this.getTransitKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
render(): JSX.Element {
|
|
||||||
if (!this.state.contentLoaded) {
|
|
||||||
return <p>{i18next.t("content_loading")}</p>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.state.transitKeysList.length == 0) {
|
|
||||||
return <p>{i18next.t("transit_view_none_here_text")}</p>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ul class="uk-nav uk-nav-default">
|
|
||||||
{...this.state.transitKeysList.map((key) => (
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
onClick={async () => {
|
|
||||||
route(transitViewSecretURL(this.props.baseMount, key));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{key}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TransitView extends Component<DefaultPageProps, { caps: CapabilitiesType }> {
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
const baseMount = this.props.matches["baseMount"];
|
const baseMount = this.props.matches["baseMount"];
|
||||||
const mountsPath = "/sys/mounts/" + baseMount;
|
const secretItem = this.props.matches["secretItem"];
|
||||||
|
const transitKey = await getTransitKey(baseMount, secretItem);
|
||||||
const caps = await getCapabilitiesPath([mountsPath, baseMount]);
|
this.setState({ transitKey });
|
||||||
this.setState({ caps });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.state.caps) return;
|
if (!this.state.transitKey) return;
|
||||||
const baseMount = this.props.matches["baseMount"];
|
const baseMount = this.props.matches["baseMount"];
|
||||||
const mountsPath = "/sys/mounts/" + baseMount;
|
const secretItem = this.props.matches["secretItem"];
|
||||||
const mountCaps = this.state.caps[mountsPath];
|
const transitKey = this.state.transitKey;
|
||||||
const transitCaps = this.state.caps[baseMount];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SecretTitleElement type="transit" baseMount={baseMount} />
|
<SecretTitleElement
|
||||||
|
type="transit"
|
||||||
<p>
|
baseMount={baseMount}
|
||||||
{transitCaps.includes("create") && (
|
item={secretItem}
|
||||||
<button
|
/>
|
||||||
class="uk-button uk-button-primary"
|
<Grid size={GridSizes.MATCHING_TWO_ROWS}>
|
||||||
onClick={async () => {
|
{transitKey.supports_encryption && (
|
||||||
route(transitNewSecretURL(baseMount));
|
<Tile
|
||||||
}}
|
title={i18next.t("transit_view_encrypt_text")}
|
||||||
>
|
description={i18next.t("transit_view_encrypt_description")}
|
||||||
{i18next.t("transit_view_new_btn")}
|
icon="lock"
|
||||||
</button>
|
iconText={i18next.t("transit_view_encrypt_icon_text")}
|
||||||
|
onclick={async () => route(transitEncryptSecretURL(baseMount, secretItem))}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{mountCaps.includes("delete") && (
|
{transitKey.supports_decryption && (
|
||||||
<button
|
<Tile
|
||||||
class="uk-button uk-button-danger"
|
title={i18next.t("transit_view_decrypt_text")}
|
||||||
onClick={async () => {
|
description={i18next.t("transit_view_decrypt_description")}
|
||||||
route(delSecretsEngineURL(baseMount));
|
icon="mail"
|
||||||
}}
|
iconText={i18next.t("transit_view_decrypt_icon_text")}
|
||||||
>
|
onclick={() => route(transitDecryptSecretURL(baseMount, secretItem))}
|
||||||
{i18next.t("transit_view_delete_btn")}
|
/>
|
||||||
</button>
|
|
||||||
)}
|
)}
|
||||||
</p>
|
{transitKey.supports_decryption && (
|
||||||
<TransitViewListItem baseMount={baseMount} />
|
<Tile
|
||||||
|
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={async () => route(transitRewrapSecretURL(baseMount, secretItem))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
import { Component, render } from "preact";
|
|
||||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
|
||||||
import { Grid, GridSizes } from "../../../elements/Grid";
|
|
||||||
import { Page } from "../../../../types/Page";
|
|
||||||
import { SecretTitleElement } from "../SecretTitleElement";
|
|
||||||
import { Tile } from "../../../elements/Tile";
|
|
||||||
import { TransitKeyType } from "../../../../api/types/transit";
|
|
||||||
import { getTransitKey } from "../../../../api/transit/getTransitKey";
|
|
||||||
import i18next from "i18next";
|
|
||||||
|
|
||||||
export class TransitViewSecret extends Component<DefaultPageProps, { transitKey: TransitKeyType }> {
|
|
||||||
async componentDidMount() {
|
|
||||||
const baseMount = this.props.matches["baseMount"];
|
|
||||||
const secretItem = this.props.matches["secretItem"];
|
|
||||||
const transitKey = await getTransitKey(baseMount, secretItem);
|
|
||||||
this.setState({ transitKey });
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (!this.state.transitKey) return;
|
|
||||||
const baseMount = this.props.matches["baseMount"];
|
|
||||||
const secretItem = this.props.matches["secretItem"];
|
|
||||||
const transitKey = this.state.transitKey;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Grid size={GridSizes.MATCHING_TWO_ROWS}>
|
|
||||||
{transitKey.supports_encryption && (
|
|
||||||
<Tile
|
|
||||||
title={i18next.t("transit_view_encrypt_text")}
|
|
||||||
description={i18next.t("transit_view_encrypt_description")}
|
|
||||||
icon="lock"
|
|
||||||
iconText={i18next.t("transit_view_encrypt_icon_text")}
|
|
||||||
onclick={async () => {} /*await this.router.changePage("TRANSIT_ENCRYPT")*/}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{transitKey.supports_decryption && (
|
|
||||||
<Tile
|
|
||||||
title={i18next.t("transit_view_decrypt_text")}
|
|
||||||
description={i18next.t("transit_view_decrypt_description")}
|
|
||||||
icon="mail"
|
|
||||||
iconText={i18next.t("transit_view_decrypt_icon_text")}
|
|
||||||
onclick={async () => {} /*await this.router.changePage("TRANSIT_DECRYPT")*/}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{transitKey.supports_decryption && (
|
|
||||||
<Tile
|
|
||||||
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={async () => {} /*await this.router.changePage("TRANSIT_REWRAP")*/}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Grid>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ export function delSecretsEngineURL(baseMount: string): string {
|
||||||
// Secrets / Key Value
|
// Secrets / Key Value
|
||||||
|
|
||||||
export function kvNewURL(baseMount: string, secretPath?: string[]): string {
|
export function kvNewURL(baseMount: string, secretPath?: string[]): string {
|
||||||
return `/secrets/kv/new/${baseMount}` + secretPath ? `/${secretPath.join("/")}` : "";
|
return `/secrets/kv/new/${baseMount}` + (secretPath ? `/${secretPath.join("/")}` : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function kvDeleteURL(baseMount: string, secretPath: string[], secret: string): string {
|
export function kvDeleteURL(baseMount: string, secretPath: string[], secret: string): string {
|
||||||
|
@ -47,8 +47,24 @@ export function transitNewSecretURL(baseMount: string): string {
|
||||||
return `/secrets/transit/new/${baseMount}`;
|
return `/secrets/transit/new/${baseMount}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function transitListSecretURL(baseMount: string, secret: string): string {
|
||||||
|
return `/secrets/transit/list/${baseMount}/${secret}`;
|
||||||
|
}
|
||||||
|
|
||||||
export function transitViewSecretURL(baseMount: string, secret: string): string {
|
export function transitViewSecretURL(baseMount: string, secret: string): string {
|
||||||
return `/secrets/transit/view/${baseMount}/${secret}`;
|
return `/secrets/transit/view/${baseMount}/${secret}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function transitEncryptSecretURL(baseMount: string, secret: string): string {
|
||||||
|
return `/secrets/transit/encrypt/${baseMount}/${secret}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transitDecryptSecretURL(baseMount: string, secret: string): string {
|
||||||
|
return `/secrets/transit/decrypt/${baseMount}/${secret}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transitRewrapSecretURL(baseMount: string, secret: string): string {
|
||||||
|
return `/secrets/transit/rewrap/${baseMount}/${secret}`;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue