mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 12:04:03 +00:00
Continue secret sharing
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { useGetActiveSharedSecretById } from "@app/hooks/api/secretSharing";
|
||||
|
||||
import { SecretContainer, SecretErrorContainer } from "./components";
|
||||
|
||||
export const ViewSecretPublicPage = () => {
|
||||
const router = useRouter();
|
||||
const { id, key: urlEncodedPublicKey } = router.query;
|
||||
const key = decodeURIComponent(urlEncodedPublicKey as string);
|
||||
|
||||
const { data: secret, error } = useGetActiveSharedSecretById(id as string);
|
||||
|
||||
return (
|
||||
<div className="flex h-screen flex-col justify-between bg-gradient-to-tr from-mineshaft-700 to-bunker-800 text-gray-200 dark:[color-scheme:dark]">
|
||||
<div />
|
||||
<div className="mx-auto w-full max-w-lg">
|
||||
<div className="mb-8 text-center">
|
||||
<h1 className="bg-gradient-to-b from-white to-bunker-200 bg-clip-text px-4 text-center text-3xl font-medium text-transparent">
|
||||
View Shared Secret
|
||||
</h1>
|
||||
<p className="text-md">
|
||||
Powered by{" "}
|
||||
<a
|
||||
href="https://github.com/infisical/infisical"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-bold bg-gradient-to-tr from-yellow-500 to-primary-500 bg-clip-text text-transparent"
|
||||
>
|
||||
Infisical →
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
{secret && key && <SecretContainer secret={secret} secretKey={key} />}
|
||||
{error && <SecretErrorContainer />}
|
||||
</div>
|
||||
<div className="w-full bg-mineshaft-600 p-2">
|
||||
<p className="text-center text-sm text-mineshaft-300">
|
||||
© 2024{" "}
|
||||
<a className="text-primary" href="https://infisical.com">
|
||||
Infisical
|
||||
</a>
|
||||
. All rights reserved.
|
||||
<br />
|
||||
156 2nd st, 3rd Floor, San Francisco, California, 94105, United States. 🇺🇸
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
faArrowRight,
|
||||
faCheck,
|
||||
faCopy,
|
||||
faEye,
|
||||
faEyeSlash
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { decryptSymmetric } from "@app/components/utilities/cryptography/crypto";
|
||||
import { Button, IconButton } from "@app/components/v2";
|
||||
import { useTimedReset, useToggle } from "@app/hooks";
|
||||
import { TViewSharedSecretResponse } from "@app/hooks/api/secretSharing";
|
||||
|
||||
type Props = {
|
||||
secret: TViewSharedSecretResponse;
|
||||
secretKey: string;
|
||||
};
|
||||
|
||||
// note: implementation currently doesn't account
|
||||
// for in-org (authenticated) secret sharing
|
||||
export const SecretContainer = ({ secret, secretKey: key }: Props) => {
|
||||
const [isVisible, setIsVisible] = useToggle(false);
|
||||
const [, isCopyingSecret, setCopyTextSecret] = useTimedReset<string>({
|
||||
initialState: "Copy to clipboard"
|
||||
});
|
||||
|
||||
const decryptedSecret = useMemo(() => {
|
||||
if (secret && secret.encryptedValue && key) {
|
||||
const res = decryptSymmetric({
|
||||
ciphertext: secret.encryptedValue,
|
||||
iv: secret.iv,
|
||||
tag: secret.tag,
|
||||
key
|
||||
});
|
||||
return res;
|
||||
}
|
||||
return "";
|
||||
}, [secret, key]);
|
||||
|
||||
const hiddenSecret = decryptedSecret ? "*".repeat(decryptedSecret.length) : "";
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-800 p-4">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2>Shared Secret</h2>
|
||||
<div className="flex">
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
colorSchema="secondary"
|
||||
className="group relative"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(decryptedSecret);
|
||||
setCopyTextSecret("Copied");
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={isCopyingSecret ? faCheck : faCopy} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
colorSchema="secondary"
|
||||
className="group relative ml-2"
|
||||
onClick={() => setIsVisible.toggle()}
|
||||
>
|
||||
<FontAwesomeIcon icon={isVisible ? faEyeSlash : faEye} />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between rounded-md bg-white/[0.07] p-2 text-base text-gray-400">
|
||||
<p className="whitespace-pre-wrap break-all">
|
||||
{isVisible ? decryptedSecret : hiddenSecret}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
className="mt-4 w-full bg-mineshaft-700 py-3 text-bunker-200"
|
||||
colorSchema="primary"
|
||||
variant="outline_bg"
|
||||
size="sm"
|
||||
onClick={() => window.open("https://app.infisical.com/share-secret", "_blank")}
|
||||
rightIcon={<FontAwesomeIcon icon={faArrowRight} className="pl-2" />}
|
||||
>
|
||||
Share your own secret
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import { faKey } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
export const SecretErrorContainer = () => {
|
||||
return (
|
||||
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-800 p-4">
|
||||
<div className="text-center">
|
||||
<FontAwesomeIcon icon={faKey} size="2x" />
|
||||
<p className="mt-4">The secret you are looking is missing or has expired</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,2 @@
|
||||
export { SecretContainer } from "./SecretContainer";
|
||||
export { SecretErrorContainer } from "./SecretErrorContainer";
|
||||
@@ -0,0 +1 @@
|
||||
export { ViewSecretPublicPage } from "./ViewSecretPublicPage";
|
||||
Reference in New Issue
Block a user