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 { Home } from "./ui/pages/Home";
|
||||
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 { KeyValueEdit } from "./ui/pages/Secrets/KeyValue/KeyValueEdit";
|
||||
import { KeyValueList } from "./ui/pages/Secrets/KeyValue/KeyValueList";
|
||||
import { Login } from "./ui/pages/Login";
|
||||
import { Me } from "./ui/pages/Me";
|
||||
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 { NewTOTPEngine } from "./ui/pages/Secrets/NewEngines/NewTOTPEngine";
|
||||
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 { Secrets } from "./ui/pages/Secrets/SecretsHome";
|
||||
import { SetLanguage } from "./ui/pages/SetLanguage";
|
||||
import { SetVaultURL } from "./ui/pages/SetVaultURL";
|
||||
import { TOTPDelete } from "./ui/pages/Secrets/TOTP/TOTPDelete";
|
||||
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 { TransitViewSecret } from "./ui/pages/Secrets/Transit/TransitViewSecret";
|
||||
import { Unseal } from "./ui/pages/Unseal";
|
||||
import { pageState } from "./globalPageState";
|
||||
import { playground } from "./playground";
|
||||
import Router from "preact-router";
|
||||
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> {
|
||||
const Main = () => (
|
||||
|
@ -75,18 +79,23 @@ async function onLoad(): Promise<void> {
|
|||
<NewTOTPEngine path="/secrets/new_secrets_engine/totp" />
|
||||
<NewTransitEngine path="/secrets/new_secrets_engine/trasit" />
|
||||
|
||||
<KeyValueView path="/secrets/kv/list/:baseMount/:secretPath*?" state={pageState} />
|
||||
<KeyValueSecret path="/secrets/kv/view/:item/:baseMount/:secretPath+" state={pageState} />
|
||||
<KeyValueSecretEdit path="/secrets/kv/edit/:item/:baseMount/:secretPath+" state={pageState} />
|
||||
<KeyValueDelete path="/secrets/kv/delete/:item/:baseMount/:secretPath+" state={pageState} />
|
||||
<KeyValueNew path="/secrets/kv/new/:baseMount/:secretPath*?" state={pageState} />
|
||||
<KeyValueList path="/secrets/kv/list/:baseMount/:secretPath*?" state={pageState} />
|
||||
<KeyValueView path="/secrets/kv/view/: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} />
|
||||
<TOTPDelete path="/secrets/totp/delete/:baseMount/:item" state={pageState} />
|
||||
|
||||
<TransitView path="/secrets/transit/list/:baseMount" state={pageState} />
|
||||
<TransitViewSecret path="/secrets/transit/view/:baseMount/:secretItem" state={pageState} />
|
||||
<NewTransitKey path="/secrets/transit/new/:baseMount" state={pageState} />
|
||||
<TransitNew path="/secrets/transit/new/:baseMount" state={pageState} />
|
||||
<TransitList path="/secrets/transit/list/: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>
|
||||
<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() {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
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 i18next from "i18next";
|
||||
|
||||
export class KeyValueNewPage extends Component<DefaultPageProps> {
|
||||
export class KeyValueNew extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
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 { Component, JSX, createRef, render } from "preact";
|
||||
import { CodeBlock } from "../../../elements/CodeBlock";
|
||||
import { Component, JSX, render } from "preact";
|
||||
import { CopyableInputBox } from "../../../elements/CopyableInputBox";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { DoesNotExistError } from "../../../../types/internalErrors";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { Grid, GridSizes } from "../../../elements/Grid";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { delSecretsEngineURL, kvListURL, kvNewURL, kvViewURL } from "../../pageLinks";
|
||||
import { getMount } from "../../../../api/sys/getMounts";
|
||||
import { getSecrets } from "../../../../api/kv/getSecrets";
|
||||
import { getCapabilities } from "../../../../api/sys/getCapabilities";
|
||||
import { getSecret } from "../../../../api/kv/getSecret";
|
||||
import { kvDeleteURL, kvEditURL } from "../../pageLinks";
|
||||
import { route } from "preact-router";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import { sortedObjectMap } from "../../../../utils";
|
||||
import i18next from "i18next";
|
||||
|
||||
export type KVKeysListProps = DefaultPageProps & {
|
||||
baseMount: string;
|
||||
secretPath: string[];
|
||||
export type KVSecretViewProps = {
|
||||
kvData: Record<string, unknown>;
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
export class KVSecretVew extends Component<KVSecretViewProps, unknown> {
|
||||
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>;
|
||||
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 (
|
||||
<>
|
||||
<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>
|
||||
{Array.from(secretsMap).map((data: [string, string]) => (
|
||||
<Grid size={GridSizes.NORMAL}>
|
||||
<CopyableInputBox text={data[0]} copyable />
|
||||
<CopyableInputBox text={data[1]} copyable />
|
||||
</Grid>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type KeyValueViewState = {
|
||||
pathCaps: string[];
|
||||
mountCaps: string[];
|
||||
mountType: string;
|
||||
baseMount: string;
|
||||
secretPath: string[];
|
||||
secretItem: string;
|
||||
caps: string[];
|
||||
secretInfo: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export class KeyValueView extends Component<DefaultPageProps, KeyValueViewState> {
|
||||
async componentDidMount() {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const secretPath = this.props.matches["secretPath"].split("/");
|
||||
const secretItem = this.props.matches["item"];
|
||||
|
||||
const mountsPath = "/sys/mounts/" + baseMount;
|
||||
const currentPath = baseMount + secretPath.join();
|
||||
const caps = await getCapabilitiesPath([mountsPath, currentPath]);
|
||||
const caps = (await getCapabilities(baseMount, secretPath, secretItem)).capabilities;
|
||||
|
||||
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({
|
||||
mountCaps: caps[mountsPath],
|
||||
pathCaps: caps[currentPath],
|
||||
mountType: mount.type,
|
||||
baseMount,
|
||||
secretPath,
|
||||
secretItem,
|
||||
caps,
|
||||
secretInfo,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.pathCaps) return;
|
||||
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const secretPath = this.props.matches["secretPath"].split("/");
|
||||
if (!this.state.baseMount) return;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement
|
||||
type="kv"
|
||||
baseMount={baseMount}
|
||||
secretPath={secretPath}
|
||||
item={this.props.matches["item"]}
|
||||
baseMount={this.state.baseMount}
|
||||
secretPath={this.state.secretPath}
|
||||
suffix={i18next.t("kv_sec_edit_suffix")}
|
||||
/>
|
||||
<p>
|
||||
{this.state.pathCaps.includes("create") && (
|
||||
<button
|
||||
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") && (
|
||||
<div>
|
||||
<p id="buttonsBlock">
|
||||
{this.state.caps.includes("delete") && (
|
||||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
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>
|
||||
)}
|
||||
</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,
|
||||
getCapsPath,
|
||||
} from "../../../../api/sys/getCapabilities";
|
||||
import { Component, JSX, render } from "preact";
|
||||
import { Component, JSX } from "preact";
|
||||
import { CopyableInputBox } from "../../../elements/CopyableInputBox";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { DoesNotExistError } from "../../../../types/internalErrors";
|
||||
import { Grid, GridSizes } from "../../../elements/Grid";
|
||||
import { MarginInline } from "../../../elements/MarginInline";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { delSecretsEngineURL, totpNewURL } from "../../pageLinks";
|
||||
import { getTOTPCode } from "../../../../api/totp/getTOTPCode";
|
||||
|
@ -73,12 +72,12 @@ export class RefreshingTOTPGridItem extends Component<TOTPGridItemProps, { totpV
|
|||
}
|
||||
}
|
||||
|
||||
type TOTPViewState = {
|
||||
type TOTPListState = {
|
||||
capabilities?: CapabilitiesType;
|
||||
totpItems: TOTPGridItemProps[];
|
||||
};
|
||||
|
||||
export class TOTPView extends Component<DefaultPageProps, TOTPViewState> {
|
||||
export class TOTPList extends Component<DefaultPageProps, TOTPListState> {
|
||||
constructor() {
|
||||
super();
|
||||
this.refresher = undefined;
|
|
@ -3,26 +3,27 @@ import { FileUploadInput } from "../../../elements/FileUploadInput";
|
|||
import { Form } from "../../../elements/Form";
|
||||
import { InputWithTitle } from "../../../elements/InputWithTitle";
|
||||
import { Margin } from "../../../elements/Margin";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { fileToBase64 } from "../../../../htmlUtils";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import { transitDecrypt } from "../../../../api/transit/transitDecrypt";
|
||||
import UIkit from "uikit";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
|
||||
export class TransitDecryptPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("TRANSIT_VIEW_SECRET");
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class TransitDecrypt extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const secretItem = this.props.matches["secretItem"];
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement
|
||||
type="transit"
|
||||
baseMount={baseMount}
|
||||
item={secretItem}
|
||||
suffix={i18next.t("transit_decrypt_suffix")}
|
||||
/>
|
||||
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
||||
<Margin>
|
||||
<textarea
|
||||
|
@ -42,12 +43,15 @@ export class TransitDecryptPage extends Page {
|
|||
{i18next.t("transit_decrypt_decrypt_btn")}
|
||||
</button>
|
||||
<div id="modalAttachmentPoint" />
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
let ciphertext = data.get("ciphertext") as string;
|
||||
|
@ -60,7 +64,7 @@ export class TransitDecryptPage extends Page {
|
|||
}
|
||||
|
||||
try {
|
||||
const res = await transitDecrypt(this.state.baseMount, this.state.secretItem, {
|
||||
const res = await transitDecrypt(baseMount, secretItem, {
|
||||
ciphertext: ciphertext,
|
||||
});
|
||||
let plaintext = res.plaintext;
|
||||
|
@ -81,15 +85,4 @@ export class TransitDecryptPage extends Page {
|
|||
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 { InputWithTitle } from "../../../elements/InputWithTitle";
|
||||
import { Margin } from "../../../elements/Margin";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { fileToBase64 } from "../../../../htmlUtils";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import { transitEncrypt } from "../../../../api/transit/transitEncrypt";
|
||||
import UIkit from "uikit";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
|
||||
export class TransitEncryptPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("TRANSIT_VIEW_SECRET");
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class TransitEncrypt extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const secretItem = this.props.matches["secretItem"];
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement
|
||||
type="transit"
|
||||
baseMount={baseMount}
|
||||
item={secretItem}
|
||||
suffix={i18next.t("transit_encrypt_suffix")}
|
||||
/>
|
||||
<Form onSubmit={async (data) => await this.onSubmit(data)}>
|
||||
<Margin>
|
||||
<textarea
|
||||
|
@ -42,12 +43,15 @@ export class TransitEncryptPage extends Page {
|
|||
{i18next.t("transit_encrypt_encrypt_btn")}
|
||||
</button>
|
||||
<div id="modalAttachmentPoint" />
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
let plaintext = data.get("plaintext") as string;
|
||||
|
@ -61,7 +65,7 @@ export class TransitEncryptPage extends Page {
|
|||
}
|
||||
|
||||
try {
|
||||
const res = await transitEncrypt(this.state.baseMount, this.state.secretItem, {
|
||||
const res = await transitEncrypt(baseMount, secretItem, {
|
||||
plaintext: plaintext,
|
||||
});
|
||||
render(
|
||||
|
@ -78,15 +82,4 @@ export class TransitEncryptPage extends Page {
|
|||
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 i18next from "i18next";
|
||||
|
||||
export class NewTransitKey extends Component<DefaultPageProps> {
|
||||
export class TransitNew extends Component<DefaultPageProps> {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
|
@ -1,33 +1,38 @@
|
|||
import { CopyableModal } from "../../../elements/CopyableModal";
|
||||
import { Form } from "../../../elements/Form";
|
||||
import { Margin } from "../../../elements/Margin";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { getTransitKey } from "../../../../api/transit/getTransitKey";
|
||||
import { objectToMap } from "../../../../utils";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import { transitRewrap } from "../../../../api/transit/transitRewrap";
|
||||
import UIkit from "uikit";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { TransitKeyType } from "../../../../api/types/transit";
|
||||
|
||||
type versionOption = { version: string; label: string };
|
||||
|
||||
export class TransitRewrapPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
export class TransitRewrap extends Component<DefaultPageProps, { transitKey: TransitKeyType }> {
|
||||
async componentDidMount() {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const secretItem = this.props.matches["secretItem"];
|
||||
this.setState({
|
||||
transitKey: await getTransitKey(baseMount, secretItem)
|
||||
})
|
||||
}
|
||||
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("TRANSIT_VIEW_SECRET");
|
||||
}
|
||||
render() {
|
||||
if (!this.state.transitKey) return;
|
||||
|
||||
async render(): Promise<void> {
|
||||
const transitKey = await getTransitKey(this.state.baseMount, this.state.secretItem);
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const secretItem = this.props.matches["secretItem"];
|
||||
|
||||
const stringVersions = Array.from(
|
||||
objectToMap(transitKey.keys).keys(),
|
||||
objectToMap(this.state.transitKey.keys).keys(),
|
||||
).reverse() as unknown as string[];
|
||||
|
||||
const versions = stringVersions.map((val): number => parseInt(val, 10));
|
||||
|
||||
// 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)}>
|
||||
<Margin>
|
||||
<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")}
|
||||
</button>
|
||||
<div id="modalAttachmentPoint" />
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
async onSubmit(data: FormData): Promise<void> {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const secretItem = this.props.matches["secretItem"];
|
||||
try {
|
||||
const res = await transitRewrap(this.state.baseMount, this.state.secretItem, {
|
||||
const res = await transitRewrap(baseMount, secretItem, {
|
||||
ciphertext: data.get("ciphertext") as string,
|
||||
key_version: parseInt(data.get("version") as string, 10),
|
||||
});
|
||||
|
@ -93,15 +107,4 @@ export class TransitRewrapPage extends Page {
|
|||
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, JSX, render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { Grid, GridSizes } from "../../../elements/Grid";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { delSecretsEngineURL, transitNewSecretURL, transitViewSecretURL } from "../../pageLinks";
|
||||
import { getTransitKeys } from "../../../../api/transit/getTransitKeys";
|
||||
import { route } from "preact-router";
|
||||
import { Tile } from "../../../elements/Tile";
|
||||
import { TransitKeyType } from "../../../../api/types/transit";
|
||||
import { getTransitKey } from "../../../../api/transit/getTransitKey";
|
||||
import i18next from "i18next";
|
||||
import { route } from "preact-router";
|
||||
import { transitDecryptSecretURL, transitEncryptSecretURL, transitRewrapSecretURL } from "../../pageLinks";
|
||||
|
||||
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 TransitView extends Component<DefaultPageProps, { caps: CapabilitiesType }> {
|
||||
export class TransitView extends Component<DefaultPageProps, { transitKey: TransitKeyType }> {
|
||||
async componentDidMount() {
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const mountsPath = "/sys/mounts/" + baseMount;
|
||||
|
||||
const caps = await getCapabilitiesPath([mountsPath, baseMount]);
|
||||
this.setState({ caps });
|
||||
const secretItem = this.props.matches["secretItem"];
|
||||
const transitKey = await getTransitKey(baseMount, secretItem);
|
||||
this.setState({ transitKey });
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.caps) return;
|
||||
if (!this.state.transitKey) return;
|
||||
const baseMount = this.props.matches["baseMount"];
|
||||
const mountsPath = "/sys/mounts/" + baseMount;
|
||||
const mountCaps = this.state.caps[mountsPath];
|
||||
const transitCaps = this.state.caps[baseMount];
|
||||
const secretItem = this.props.matches["secretItem"];
|
||||
const transitKey = this.state.transitKey;
|
||||
|
||||
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>
|
||||
<SecretTitleElement
|
||||
type="transit"
|
||||
baseMount={baseMount}
|
||||
item={secretItem}
|
||||
/>
|
||||
<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 () => route(transitEncryptSecretURL(baseMount, secretItem))}
|
||||
/>
|
||||
)}
|
||||
{mountCaps.includes("delete") && (
|
||||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
onClick={async () => {
|
||||
route(delSecretsEngineURL(baseMount));
|
||||
}}
|
||||
>
|
||||
{i18next.t("transit_view_delete_btn")}
|
||||
</button>
|
||||
{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={() => route(transitDecryptSecretURL(baseMount, secretItem))}
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
<TransitViewListItem baseMount={baseMount} />
|
||||
{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 () => 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
|
||||
|
||||
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 {
|
||||
|
@ -47,8 +47,24 @@ export function transitNewSecretURL(baseMount: string): string {
|
|||
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 {
|
||||
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