Adjustments to secret sharing styling

This commit is contained in:
Tuan Dang
2024-07-27 07:31:30 -07:00
parent 0fa6b7a08a
commit a30e3874cd
10 changed files with 114 additions and 271 deletions
@@ -95,7 +95,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
tag: z.string(), tag: z.string(),
hashedHex: z.string(), hashedHex: z.string(),
expiresAt: z.string(), expiresAt: z.string(),
expiresAfterViews: z.number() expiresAfterViews: z.number().optional()
}), }),
response: { response: {
200: z.object({ 200: z.object({
@@ -110,7 +110,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
iv, iv,
tag, tag,
hashedHex, hashedHex,
expiresAt: new Date(expiresAt), expiresAt,
expiresAfterViews, expiresAfterViews,
accessType: SecretSharingAccessType.Anyone accessType: SecretSharingAccessType.Anyone
}); });
@@ -131,7 +131,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
tag: z.string(), tag: z.string(),
hashedHex: z.string(), hashedHex: z.string(),
expiresAt: z.string(), expiresAt: z.string(),
expiresAfterViews: z.number(), expiresAfterViews: z.number().optional(),
accessType: z.nativeEnum(SecretSharingAccessType).default(SecretSharingAccessType.Organization) accessType: z.nativeEnum(SecretSharingAccessType).default(SecretSharingAccessType.Organization)
}), }),
response: { response: {
@@ -153,7 +153,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) =>
iv, iv,
tag, tag,
hashedHex, hashedHex,
expiresAt: new Date(expiresAt), expiresAt,
expiresAfterViews, expiresAfterViews,
accessType: req.body.accessType accessType: req.body.accessType
}); });
@@ -64,12 +64,13 @@ export const secretSharingServiceFactory = ({
iv, iv,
tag, tag,
hashedHex, hashedHex,
expiresAt, expiresAt: new Date(expiresAt),
expiresAfterViews, expiresAfterViews,
userId: actorId, userId: actorId,
orgId, orgId,
accessType accessType
}); });
return { id: newSharedSecret.id }; return { id: newSharedSecret.id };
}; };
@@ -97,7 +98,7 @@ export const secretSharingServiceFactory = ({
iv, iv,
tag, tag,
hashedHex, hashedHex,
expiresAt, expiresAt: new Date(expiresAt),
expiresAfterViews, expiresAfterViews,
accessType accessType
}); });
@@ -16,8 +16,8 @@ export type TCreatePublicSharedSecretDTO = {
iv: string; iv: string;
tag: string; tag: string;
hashedHex: string; hashedHex: string;
expiresAt: Date; expiresAt: string;
expiresAfterViews: number; expiresAfterViews?: number;
accessType: SecretSharingAccessType; accessType: SecretSharingAccessType;
}; };
@@ -12,7 +12,7 @@ export type TCreateSharedSecretRequest = {
tag: string; tag: string;
hashedHex: string; hashedHex: string;
expiresAt: Date; expiresAt: Date;
expiresAfterViews: number; expiresAfterViews?: number;
accessType: SecretSharingAccessType; accessType: SecretSharingAccessType;
}; };
@@ -31,4 +31,4 @@ export type TDeleteSharedSecretRequest = {
export enum SecretSharingAccessType { export enum SecretSharingAccessType {
Anyone = "anyone", Anyone = "anyone",
Organization = "organization" Organization = "organization"
} }
@@ -7,19 +7,38 @@ import * as yup from "yup";
import { createNotification } from "@app/components/notifications"; import { createNotification } from "@app/components/notifications";
import { encryptSymmetric } from "@app/components/utilities/cryptography/crypto"; import { encryptSymmetric } from "@app/components/utilities/cryptography/crypto";
import { Button, Checkbox, FormControl, Input, ModalClose, Select, SelectItem } from "@app/components/v2"; import { Button, FormControl, ModalClose, Select, SelectItem } from "@app/components/v2";
import { SecretSharingAccessType, useCreatePublicSharedSecret, useCreateSharedSecret } from "@app/hooks/api/secretSharing"; import {
SecretSharingAccessType,
useCreatePublicSharedSecret,
useCreateSharedSecret
} from "@app/hooks/api/secretSharing";
const schema = yup.object({ const schema = yup.object({
value: yup.string().max(10000).required().label("Shared Secret Value"), value: yup.string().max(10000).required().label("Shared Secret Value"),
expiresAfterSingleView: yup.boolean().required().label("Expires After Views"), expiresAfterViews: yup.string().required().label("Expires After Views"),
expiresInValue: yup.number().min(1).required().label("Expiration Value"), expiresInValue: yup.string().min(1).required().label("Expiration Value"),
expiresInUnit: yup.string().required().label("Expiration Unit"),
accessType: yup.string().required().label("General Access") accessType: yup.string().required().label("General Access")
}); });
export type FormData = yup.InferType<typeof schema>; export type FormData = yup.InferType<typeof schema>;
// values in ms
const expiresInOptions = [
{ label: "5 min", value: 5 * 60 * 1000 },
{ label: "30 min", value: 30 * 60 * 1000 },
{ label: "1 hour", value: 60 * 60 * 1000 },
{ label: "1 day", value: 24 * 60 * 60 * 1000 },
{ label: "7 days", value: 7 * 24 * 60 * 60 * 1000 },
{ label: "14 days", value: 14 * 24 * 60 * 60 * 1000 },
{ label: "30 days", value: 30 * 24 * 60 * 60 * 1000 }
];
const viewLimitOptions = [
{ label: "1", value: 1 },
{ label: "Unlimited", value: -1 }
];
export const AddShareSecretForm = ({ export const AddShareSecretForm = ({
isPublic, isPublic,
inModal, inModal,
@@ -49,36 +68,15 @@ export const AddShareSecretForm = ({
const privateSharedSecretCreator = useCreateSharedSecret(); const privateSharedSecretCreator = useCreateSharedSecret();
const createSharedSecret = isPublic ? publicSharedSecretCreator : privateSharedSecretCreator; const createSharedSecret = isPublic ? publicSharedSecretCreator : privateSharedSecretCreator;
const expirationUnitsAndActions = [
{
unit: "Minutes",
action: (expiresAt: Date, expiresInValue: number) =>
expiresAt.setMinutes(expiresAt.getMinutes() + expiresInValue)
},
{
unit: "Hours",
action: (expiresAt: Date, expiresInValue: number) =>
expiresAt.setHours(expiresAt.getHours() + expiresInValue)
},
{
unit: "Days",
action: (expiresAt: Date, expiresInValue: number) =>
expiresAt.setDate(expiresAt.getDate() + expiresInValue)
},
{
unit: "Weeks",
action: (expiresAt: Date, expiresInValue: number) =>
expiresAt.setDate(expiresAt.getDate() + expiresInValue * 7)
}
];
const onFormSubmit = async ({ const onFormSubmit = async ({
value, value,
expiresInValue, expiresInValue,
expiresInUnit, expiresAfterViews,
expiresAfterSingleView,
accessType accessType
}: FormData) => { }: FormData) => {
try { try {
const expiresAt = new Date(new Date().getTime() + Number(expiresInValue));
const key = crypto.randomBytes(16).toString("hex"); const key = crypto.randomBytes(16).toString("hex");
const hashedHex = crypto.createHash("sha256").update(key).digest("hex"); const hashedHex = crypto.createHash("sha256").update(key).digest("hex");
const { ciphertext, iv, tag } = encryptSymmetric({ const { ciphertext, iv, tag } = encryptSymmetric({
@@ -86,21 +84,13 @@ export const AddShareSecretForm = ({
key key
}); });
const expiresAt = new Date();
const updateExpiresAt = expirationUnitsAndActions.find(
(item) => item.unit === expiresInUnit
)?.action;
if (updateExpiresAt && expiresInValue) {
updateExpiresAt(expiresAt, expiresInValue);
}
const { id } = await createSharedSecret.mutateAsync({ const { id } = await createSharedSecret.mutateAsync({
encryptedValue: ciphertext, encryptedValue: ciphertext,
iv, iv,
tag, tag,
hashedHex, hashedHex,
expiresAt, expiresAt,
expiresAfterViews: expiresAfterSingleView ? 1 : 1000, expiresAfterViews: expiresAfterViews === "-1" ? undefined : Number(expiresAfterViews),
accessType: accessType as SecretSharingAccessType accessType: accessType as SecretSharingAccessType
}); });
@@ -132,9 +122,14 @@ export const AddShareSecretForm = ({
} }
}; };
return ( return (
<form className="flex w-full flex-col items-center px-4 sm:px-0" onSubmit={handleSubmit(onFormSubmit)}> <form
className="flex w-full max-w-7xl flex-col items-center"
onSubmit={handleSubmit(onFormSubmit)}
>
<div <div
className={`w-full ${!inModal && "rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6"}`} className={`w-full ${
!inModal && "rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4"
}`}
> >
<div> <div>
<Controller <Controller
@@ -142,7 +137,7 @@ export const AddShareSecretForm = ({
name="value" name="value"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Shared Secret" label="Your Secret"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
className="mb-2" className="mb-2"
@@ -157,90 +152,48 @@ export const AddShareSecretForm = ({
)} )}
/> />
</div> </div>
<div className="flex w-full flex-col md:flex-row justify-stretch"> <Controller
<div className="flex justify-start"> control={control}
<div className="flex justify-start"> name="expiresInValue"
<div className="flex w-full justify-center pr-2"> defaultValue="3600000"
<Controller render={({ field: { onChange, ...field }, fieldState: { error } }) => (
control={control} <FormControl label="Expires In" errorText={error?.message} isError={Boolean(error)}>
name="expiresInValue" <Select
defaultValue={1} defaultValue={field.value}
render={({ field, fieldState: { error } }) => ( {...field}
<FormControl onValueChange={(e) => onChange(e)}
label="Expires after Time" className="w-full"
isError={Boolean(error)} >
errorText="Please enter a valid time duration" {expiresInOptions.map(({ label, value }) => (
className="w-32" <SelectItem value={String(value || "")} key={label}>
> {label}
<Input {...field} type="number" min={0} /> </SelectItem>
</FormControl> ))}
)} </Select>
/> </FormControl>
</div> )}
<div className="flex justify-center"> />
<Controller <Controller
control={control} control={control}
name="expiresInUnit" name="expiresAfterViews"
defaultValue={expirationUnitsAndActions[1].unit} defaultValue="-1"
render={({ field: { onChange, ...field }, fieldState: { error } }) => ( render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl label="Unit" errorText={error?.message} isError={Boolean(error)}> <FormControl label="Max Views" errorText={error?.message} isError={Boolean(error)}>
<Select <Select
defaultValue={field.value} defaultValue={field.value}
{...field} {...field}
onValueChange={(e) => onChange(e)} onValueChange={(e) => onChange(e)}
className="w-full border border-mineshaft-600" className="w-full"
> >
{expirationUnitsAndActions.map(({ unit }) => ( {viewLimitOptions.map(({ label, value }) => (
<SelectItem value={unit} key={unit}> <SelectItem value={String(value || "")} key={label}>
{unit} {label}
</SelectItem> </SelectItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>
)} )}
/> />
</div>
</div>
</div>
<div className="sm:w-1/7 mx-auto items-center justify-center hidden md:flex">
<p className="mt-2 text-sm text-gray-400">AND</p>
</div>
<div className="items-center pb-4 md:pb-0 md:pt-2 flex">
<Controller
control={control}
name="expiresAfterViews"
defaultValue={1}
render={({ field, fieldState: { error } }) => (
<FormControl
className="mb-4 w-full hidden"
label="Expires after Views"
isError={Boolean(error)}
errorText="Please enter a valid number of views"
>
<Input {...field} type="number" min={1} />
</FormControl>
)}
/>
<div className="bg-mineshaft-900 py-2 h-max rounded-md border border-mineshaft-600 px-4">
<Controller
control={control}
name="expiresAfterSingleView"
defaultValue={false}
render={({ field: { onBlur, value, onChange } }) => (
<Checkbox
id="is-single-view"
isChecked={value}
onCheckedChange={onChange}
isDisabled={false}
onBlur={onBlur}
>
Can be viewed only 1 time
</Checkbox>
)}
/>
</div>
</div>
</div>
{!isPublic && ( {!isPublic && (
<Controller <Controller
control={control} control={control}
@@ -248,10 +201,7 @@ export const AddShareSecretForm = ({
defaultValue="organization" defaultValue="organization"
render={({ field: { onChange, ...field } }) => ( render={({ field: { onChange, ...field } }) => (
<FormControl label="General Access"> <FormControl label="General Access">
<Select <Select {...field} onValueChange={(e) => onChange(e)} className="w-full">
{...field}
onValueChange={(e) => onChange(e)}
>
<SelectItem value="organization">People within your organization</SelectItem> <SelectItem value="organization">People within your organization</SelectItem>
<SelectItem value="anyone">Anyone</SelectItem> <SelectItem value="anyone">Anyone</SelectItem>
</Select> </Select>
@@ -261,7 +211,7 @@ export const AddShareSecretForm = ({
)} )}
<div className={`flex items-center space-x-4 pt-2 ${!inModal && ""}`}> <div className={`flex items-center space-x-4 pt-2 ${!inModal && ""}`}>
<Button className="mr-0" type="submit" isDisabled={isSubmitting} isLoading={isSubmitting}> <Button className="mr-0" type="submit" isDisabled={isSubmitting} isLoading={isSubmitting}>
{inModal ? "Create" : "Share Secret"} {inModal ? "Create" : "Create secret link"}
</Button> </Button>
{inModal && ( {inModal && (
<ModalClose asChild> <ModalClose asChild>
@@ -12,9 +12,8 @@ import { ViewAndCopySharedSecret } from "./ViewAndCopySharedSecret";
const schema = yup.object({ const schema = yup.object({
value: yup.string().max(10000).required().label("Shared Secret Value"), value: yup.string().max(10000).required().label("Shared Secret Value"),
expiresAfterViews: yup.number().min(1).required().label("Expires After Views"), expiresInValue: yup.string().required().label("Expiration Value"),
expiresInValue: yup.number().min(1).required().label("Expiration Value"), expiresAfterViews: yup.string().required().label("Expires After Views")
expiresInUnit: yup.string().required().label("Expiration Unit")
}); });
export type FormData = yup.InferType<typeof schema>; export type FormData = yup.InferType<typeof schema>;
@@ -46,9 +46,8 @@ export const ShareSecretSection = () => {
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" /> <meta property="og:image" content="/images/message.png" />
</Head> </Head>
<div className="mb-2 flex justify-between"> <div className="mb-4 flex justify-between">
<p className="text-xl font-semibold text-mineshaft-100">Shared Secrets</p> <p className="text-xl font-semibold text-mineshaft-100">Shared Secrets</p>
<Button <Button
colorSchema="primary" colorSchema="primary"
leftIcon={<FontAwesomeIcon icon={faPlus} />} leftIcon={<FontAwesomeIcon icon={faPlus} />}
@@ -1,77 +1,14 @@
import { useEffect, useState } from "react"; import { faTrash } from "@fortawesome/free-solid-svg-icons";
import { faTrashCan } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
import { IconButton, Td, Tr } from "@app/components/v2"; import { IconButton, Td, Tr } from "@app/components/v2";
import { TSharedSecret } from "@app/hooks/api/secretSharing"; import { TSharedSecret } from "@app/hooks/api/secretSharing";
import { UsePopUpState } from "@app/hooks/usePopUp"; import { UsePopUpState } from "@app/hooks/usePopUp";
const formatDate = (date: Date): string => (date ? new Date(date).toUTCString() : "");
const isExpired = (expiresAt: Date | number | undefined): boolean => {
if (typeof expiresAt === "number") {
return expiresAt <= 0;
}
if (expiresAt instanceof Date) {
return new Date(expiresAt) < new Date();
}
return false;
};
const getValidityStatusText = (expiresAt: Date): string =>
isExpired(expiresAt) ? "Expired " : "Valid for ";
const timeAgo = (inputDate: Date, currentDate: Date): string => {
const now = new Date(currentDate).getTime();
const date = new Date(inputDate).getTime();
const elapsedMilliseconds = now - date;
const elapsedSeconds = Math.abs(Math.floor(elapsedMilliseconds / 1000));
const elapsedMinutes = Math.abs(Math.floor(elapsedSeconds / 60));
const elapsedHours = Math.abs(Math.floor(elapsedMinutes / 60));
const elapsedDays = Math.abs(Math.floor(elapsedHours / 24));
const elapsedWeeks = Math.abs(Math.floor(elapsedDays / 7));
const elapsedMonths = Math.abs(Math.floor(elapsedDays / 30));
const elapsedYears = Math.abs(Math.floor(elapsedDays / 365));
if (elapsedYears > 0) {
return `${elapsedYears} year${elapsedYears === 1 ? "" : "s"} ${
elapsedMilliseconds >= 0 ? "ago" : "from now"
}`;
}
if (elapsedMonths > 0) {
return `${elapsedMonths} month${elapsedMonths === 1 ? "" : "s"} ${
elapsedMilliseconds >= 0 ? "ago" : "from now"
}`;
}
if (elapsedWeeks > 0) {
return `${elapsedWeeks} week${elapsedWeeks === 1 ? "" : "s"} ${
elapsedMilliseconds >= 0 ? "ago" : "from now"
}`;
}
if (elapsedDays > 0) {
return `${elapsedDays} day${elapsedDays === 1 ? "" : "s"} ${
elapsedMilliseconds >= 0 ? "ago" : "from now"
}`;
}
if (elapsedHours > 0) {
return `${elapsedHours} hour${elapsedHours === 1 ? "" : "s"} ${
elapsedMilliseconds >= 0 ? "ago" : "from now"
}`;
}
if (elapsedMinutes > 0) {
return `${elapsedMinutes} minute${elapsedMinutes === 1 ? "" : "s"} ${
elapsedMilliseconds >= 0 ? "ago" : "from now"
}`;
}
return `${elapsedSeconds} second${elapsedSeconds === 1 ? "" : "s"} ${
elapsedMilliseconds >= 0 ? "ago" : "from now"
}`;
};
export const ShareSecretsRow = ({ export const ShareSecretsRow = ({
row, row,
handlePopUpOpen, handlePopUpOpen
onSecretExpiration
}: { }: {
row: TSharedSecret; row: TSharedSecret;
handlePopUpOpen: ( handlePopUpOpen: (
@@ -84,44 +21,13 @@ export const ShareSecretsRow = ({
id: string; id: string;
} }
) => void; ) => void;
onSecretExpiration: (expiredSecretId: string) => void;
}) => { }) => {
const [currentTime, setCurrentTime] = useState(new Date());
useEffect(() => {
const intervalId = setInterval(() => {
setCurrentTime(new Date());
}, 1000);
return () => clearInterval(intervalId);
}, []);
useEffect(() => {
if (isExpired(row.expiresAt || row.expiresAfterViews)) {
onSecretExpiration(row.id);
}
}, [isExpired(row.expiresAt || row.expiresAfterViews)]);
return ( return (
<Tr key={row.id}> <Tr key={row.id} className="h-10">
<Td>{`${row.encryptedValue.substring(0, 5)}...`}</Td> <Td>{`${row.encryptedValue.substring(0, 5)}...`}</Td>
<Td> <Td>{format(new Date(row.createdAt), "yyyy-MM-dd - HH:mm a")}</Td>
<p className="text-sm text-yellow-400">{timeAgo(row.createdAt, currentTime)}</p> <Td>{format(new Date(row.expiresAt), "yyyy-MM-dd - HH:mm a")}</Td>
<p className="text-xs text-gray-500">{formatDate(row.createdAt)}</p> <Td>{row.expiresAfterViews ? row.expiresAfterViews : "-"}</Td>
</Td>
<Td>
<>
<p className={`text-sm ${isExpired(row.expiresAt) ? "text-red-500" : "text-green-500"}`}>
{getValidityStatusText(row.expiresAt!) + timeAgo(row.expiresAt!, currentTime)}
</p>
<p className="text-xs text-gray-500">{formatDate(row.expiresAt!)}</p>
</>
</Td>
<Td>
<p className={`text-sm ${row.expiresAfterViews <= 0 ? "text-red-500" : "text-green-500"}`}>
{row.expiresAfterViews}
</p>
</Td>
<Td> <Td>
<IconButton <IconButton
onClick={() => onClick={() =>
@@ -130,10 +36,10 @@ export const ShareSecretsRow = ({
id: row.id id: row.id
}) })
} }
colorSchema="danger" variant="plain"
ariaLabel="delete" ariaLabel="delete"
> >
<FontAwesomeIcon icon={faTrashCan} /> <FontAwesomeIcon icon={faTrash} />
</IconButton> </IconButton>
</Td> </Td>
</Tr> </Tr>
@@ -31,38 +31,25 @@ type Props = {
export const ShareSecretsTable = ({ handlePopUpOpen }: Props) => { export const ShareSecretsTable = ({ handlePopUpOpen }: Props) => {
const { isLoading, data = [] } = useGetSharedSecrets(); const { isLoading, data = [] } = useGetSharedSecrets();
let tableData = data.filter(
(secret) => new Date(secret.expiresAt) > new Date() && secret.expiresAfterViews > 0
);
const handleSecretExpiration = () => {
tableData = data.filter(
(secret) => new Date(secret.expiresAt) > new Date() && secret.expiresAfterViews > 0
);
};
return ( return (
<TableContainer> <TableContainer>
<Table> <Table>
<THead> <THead>
<Tr> <Tr>
<Th>Encrypted Secret</Th> <Th>Created</Th> <Th>Valid Until</Th> <Th>Views Left</Th> <Th>Encrypted Secret</Th>
<Th aria-label="button" /> <Th>Created</Th>
<Th>Valid Until</Th>
<Th>Views Left</Th>
<Th aria-label="button" className="w-5" />
</Tr> </Tr>
</THead> </THead>
<TBody> <TBody>
{isLoading && <TableSkeleton columns={4} innerKey="shared-secrets" />} {isLoading && <TableSkeleton columns={4} innerKey="shared-secrets" />}
{!isLoading && {!isLoading &&
tableData && data?.map((row) => (
tableData.map((row) => ( <ShareSecretsRow key={row.id} row={row} handlePopUpOpen={handlePopUpOpen} />
<ShareSecretsRow
key={row.id}
row={row}
handlePopUpOpen={handlePopUpOpen}
onSecretExpiration={handleSecretExpiration}
/>
))} ))}
{!isLoading && tableData && tableData?.length === 0 && ( {!isLoading && data?.length === 0 && (
<Tr> <Tr>
<Td colSpan={4} className="bg-mineshaft-800 text-center text-bunker-400"> <Td colSpan={4} className="bg-mineshaft-800 text-center text-bunker-400">
<EmptyState title="No secrets shared yet" icon={faKey} /> <EmptyState title="No secrets shared yet" icon={faKey} />
@@ -14,6 +14,8 @@ import { useGetActiveSharedSecretByIdAndHashedHex } from "@app/hooks/api/secretS
import { AddShareSecretModal } from "../ShareSecretPage/components/AddShareSecretModal"; import { AddShareSecretModal } from "../ShareSecretPage/components/AddShareSecretModal";
import { SecretTable } from "./components"; import { SecretTable } from "./components";
// note: isNewSession: controls if the user is sharing a new secret or viewing a shared secret
export const ShareSecretPublicPage = ({ isNewSession }: { isNewSession: boolean }) => { export const ShareSecretPublicPage = ({ isNewSession }: { isNewSession: boolean }) => {
const router = useRouter(); const router = useRouter();
const { id, key: urlEncodedPublicKey } = router.query; const { id, key: urlEncodedPublicKey } = router.query;
@@ -55,7 +57,7 @@ export const ShareSecretPublicPage = ({ isNewSession }: { isNewSession: boolean
return ( return (
<div className="flex h-screen flex-col overflow-y-auto bg-gradient-to-tr from-mineshaft-700 to-bunker-800 text-gray-200 dark:[color-scheme:dark]"> <div className="flex h-screen flex-col overflow-y-auto bg-gradient-to-tr from-mineshaft-700 to-bunker-800 text-gray-200 dark:[color-scheme:dark]">
<Head> <Head>
<title>Secret Shared | Infisical</title> <title>Infisical | Secret Sharing</title>
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<div className="flex w-full flex-grow items-center justify-center dark:[color-scheme:dark]"> <div className="flex w-full flex-grow items-center justify-center dark:[color-scheme:dark]">
@@ -94,7 +96,6 @@ export const ShareSecretPublicPage = ({ isNewSession }: { isNewSession: boolean
/> />
)} )}
</div> </div>
{isNewSession && ( {isNewSession && (
<div className="px-0 sm:px-6"> <div className="px-0 sm:px-6">
<AddShareSecretModal <AddShareSecretModal