1
0
Fork 0

add a copy totp button on kv pages with __vaultui_totp_path

This commit is contained in:
Chaos 2022-11-23 16:45:04 +00:00
parent 760e16c371
commit 506fdbd1cb
No known key found for this signature in database
3 changed files with 56 additions and 8 deletions

View file

@ -10,6 +10,7 @@ VaultUI is a user interface for [Hashicorp Vault](https://www.hashicorp.com/prod
- Managing versions of secrets in v2 mounts. - Managing versions of secrets in v2 mounts.
- Editing and Viewing Key/Value secrets in JSON, JSON5, Yaml, etc with default settings for both. - Editing and Viewing Key/Value secrets in JSON, JSON5, Yaml, etc with default settings for both.
- Search bar for easily finding a secret on mobile. - Search bar for easily finding a secret on mobile.
- Can add a `__vaultui_totp_path` attribute (example: `__vaultui_totp_path: "totp/gitlab"`) to KV secrets to add a link for viewing of affiliated TOTP paths.
### TOTP ### TOTP
- Can view and delete TOTP codes. - Can view and delete TOTP codes.
- Ability to scan a QR code, input a URI or input a key for adding TOTP codes. - Ability to scan a QR code, input a URI or input a key for adding TOTP codes.

View file

@ -167,7 +167,8 @@ module.exports = {
kv_secret_delete_all_btn: "Delete All Versions", kv_secret_delete_all_btn: "Delete All Versions",
kv_secret_delete_version_btn: "Delete Version {{ version }}", kv_secret_delete_version_btn: "Delete Version {{ version }}",
kv_secret_versions_btn: "Versions", kv_secret_versions_btn: "Versions",
kv_secret_view_totp_btn: "View TOTP", kv_secret_view_totp_btn: "View TOTP Entry",
kv_secret_copy_totp_btn: "Copy Current TOTP Code",
kv_secret_syntax: "Syntax", kv_secret_syntax: "Syntax",
// Key Value Secret Editor Page // Key Value Secret Editor Page

View file

@ -1,3 +1,4 @@
import { API } from "../../../../api/API";
import { Button } from "../../../elements/Button"; import { Button } from "../../../elements/Button";
import { CodeBlock } from "../../../elements/CodeBlock"; import { CodeBlock } from "../../../elements/CodeBlock";
import { Component, JSX, createRef } from "preact"; import { Component, JSX, createRef } from "preact";
@ -9,10 +10,12 @@ import { InputWithTitle } from "../../../elements/InputWithTitle";
import { SecretTitleElement } from "../SecretTitleElement"; import { SecretTitleElement } from "../SecretTitleElement";
import { Select, SelectOption } from "../../../elements/forms/Select"; import { Select, SelectOption } from "../../../elements/forms/Select";
import { SupportedLanguages, dumpData, toPrismCode } from "../../../../utils/dataInterchange"; import { SupportedLanguages, dumpData, toPrismCode } from "../../../../utils/dataInterchange";
import { addClipboardNotifications } from "../../../../utils/clipboardNotifs";
import { kvDeleteURL, kvEditURL, kvVersionsURL, totpListURL } from "../../pageLinks"; import { kvDeleteURL, kvEditURL, kvVersionsURL, totpListURL } from "../../pageLinks";
import { sendErrorNotification } from "../../../elements/ErrorMessage"; import { sendErrorNotification } from "../../../elements/ErrorMessage";
import { sortedObjectMap } from "../../../../utils"; import { sortedObjectMap } from "../../../../utils";
import { splitKVPath } from "./kvPathUtils"; import { splitKVPath } from "./kvPathUtils";
import ClipboardJS from "clipboard";
import i18next from "i18next"; import i18next from "i18next";
type KVSecretViewDataProps = DefaultPageProps & { data: Map<string, unknown> }; type KVSecretViewDataProps = DefaultPageProps & { data: Map<string, unknown> };
@ -49,6 +52,46 @@ export class KVSecretCodeVew extends Component<KVSecretViewDataProps, { syntax:
} }
} }
class CopyTOTPButton extends Component<
{ baseMount: string; totpKey: string; api: API },
{ code: string }
> {
buttonRef = createRef<HTMLButtonElement>();
timer: unknown;
updateTOTPCode(): void {
void this.props.api.getTOTPCode(this.props.baseMount, this.props.totpKey).then((code) => {
this.setState({ code });
});
}
componentDidMount(): void {
this.updateTOTPCode();
this.timer = setInterval(() => {
this.updateTOTPCode();
}, 3000);
const clipboard = new ClipboardJS(this.buttonRef.current);
addClipboardNotifications(clipboard, 600);
}
componentWillUnmount(): void {
clearInterval(this.timer as number);
}
render(): JSX.Element {
return (
<Button
buttonRef={this.buttonRef}
text={i18next.t("kv_secret_copy_totp_btn")}
color="primary"
data-clipboard-text={this.state.code}
/>
);
}
}
export class KVSecretNormalVew extends Component<KVSecretViewDataProps> { export class KVSecretNormalVew extends Component<KVSecretViewDataProps> {
render() { render() {
return ( return (
@ -70,19 +113,22 @@ export class KVSecretNormalVew extends Component<KVSecretViewDataProps> {
</Grid> </Grid>
); );
})} })}
<br />
{(() => { {(() => {
if (this.props.data.has("__vaultui_totp_path")) { if (this.props.data.has("__vaultui_totp_path")) {
const value = this.props.data.get("__vaultui_totp_path") as string; const value = this.props.data.get("__vaultui_totp_path") as string;
const baseMount = value.split("/")[0]; const baseMount = value.split("/")[0];
const secretItem = value.split("/")[1]; const totpKey = value.split("/")[1];
return ( return (
<Button <p>
text={i18next.t("kv_secret_view_totp_btn")} <CopyTOTPButton api={this.props.api} baseMount={baseMount} totpKey={totpKey} />
color="primary" <Button
route={totpListURL(baseMount, secretItem)} text={i18next.t("kv_secret_view_totp_btn")}
/> color="secondary"
route={totpListURL(baseMount, totpKey)}
/>
</p>
); );
} }
})()} })()}