feat: hide expiry condition to end user & fix decrement condition in knex

This commit is contained in:
ShubhamPalriwala
2024-05-31 10:58:49 +05:30
parent 862e0437e7
commit e7d32b5f2d
6 changed files with 33 additions and 122 deletions

View File

@@ -128,7 +128,7 @@ export const ormify = <DbOps extends object, Tname extends keyof Tables>(db: Kne
}
if ($decr) {
Object.entries($decr).forEach(([incrementField, incrementValue]) => {
void query.increment(incrementField, incrementValue);
void query.decrement(incrementField, incrementValue);
});
}
const [docs] = await query;

View File

@@ -62,9 +62,7 @@ export const secretSharingServiceFactory = ({
await secretSharingDAL.deleteById(sharedSecretId);
return;
}
await secretSharingDAL.updateById(sharedSecretId, {
expiresAfterViews: sharedSecret.expiresAfterViews - 1
});
await secretSharingDAL.updateById(sharedSecretId, { $decr: { expiresAfterViews: 1 } });
}
return sharedSecret;
};

View File

@@ -24,8 +24,6 @@ export const useGetActiveSharedSecretByIdAndHashedHex = (id: string, hashedHex:
encryptedValue: data.encryptedValue,
iv: data.iv,
tag: data.tag,
expiresAt: data.expiresAt,
expiresAfterViews: data.expiresAfterViews
};
}
});

View File

@@ -19,8 +19,6 @@ export type TViewSharedSecretResponse = {
encryptedValue: string;
iv: string;
tag: string;
expiresAt?: Date;
expiresAfterViews?: number;
};
export type TDeleteSharedSecretRequest = {

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useEffect, useMemo } from "react";
import Head from "next/head";
import Image from "next/image";
import { useRouter } from "next/router";
@@ -39,45 +39,10 @@ export const ShareSecretPublicPage = () => {
return "";
}, [data, publicKey]);
const [timeLeft, setTimeLeft] = useState("");
const [isUrlCopied, , setIsUrlCopied] = useTimedReset<boolean>({
initialState: false
});
const millisecondsPerDay = 1000 * 60 * 60 * 24;
const millisecondsPerHour = 1000 * 60 * 60;
const millisecondsPerMinute = 1000 * 60;
useEffect(() => {
const updateTimer = () => {
if (data) {
if (data.expiresAt) {
const expirationTime = new Date(data.expiresAt).getTime();
const currentTime = new Date().getTime();
const timeDifference = expirationTime - currentTime;
if (timeDifference < 0) {
setTimeLeft("Expired");
} else {
const hoursRemaining = Math.floor(
(timeDifference % millisecondsPerDay) / millisecondsPerHour
);
const minutesRemaining = Math.floor(
(timeDifference % millisecondsPerHour) / millisecondsPerMinute
);
const secondsRemaining = Math.floor((timeDifference % millisecondsPerMinute) / 1000);
setTimeLeft(`${hoursRemaining}h ${minutesRemaining}m ${secondsRemaining}s`);
}
} else if (data.expiresAfterViews) {
setTimeLeft(`${data.expiresAfterViews - 1} more views`);
}
}
};
const timer = setInterval(updateTimer, 1000);
return () => clearInterval(timer);
}, [data?.expiresAt]);
useEffect(() => {
if (isUrlCopied) {
setTimeout(() => setIsUrlCopied(false), 2000);
@@ -106,14 +71,12 @@ export const ShareSecretPublicPage = () => {
<DragonMainImage />
<div className="m-4 flex flex-1 flex-col items-center justify-start md:m-0">
<p className="mt-8 mb-2 text-xl font-semibold text-mineshaft-100 md:mt-20">
Secret Details
Shared Secret
</p>
<div className="mb-16 rounded-lg border border-mineshaft-600 bg-mineshaft-900 md:p-8">
<div className="mb-4 rounded-lg md:p-2">
<SecretTable
isLoading={isLoading}
sharedSecret={data}
decryptedSecret={decryptedSecret}
timeLeft={timeLeft}
isUrlCopied={isUrlCopied}
copyUrlToClipboard={copyUrlToClipboard}
/>

View File

@@ -1,90 +1,44 @@
import { faCheck, faCopy, faKey } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
EmptyState,
IconButton,
SecretInput,
Table,
TableContainer,
TBody,
Td,
Th,
THead,
Tr
} from "@app/components/v2";
import { TViewSharedSecretResponse } from "@app/hooks/api/secretSharing";
import { EmptyState, IconButton, SecretInput, Td, Tr } from "@app/components/v2";
type Props = {
isLoading: boolean;
sharedSecret?: TViewSharedSecretResponse;
decryptedSecret: string;
timeLeft: string;
isUrlCopied: boolean;
copyUrlToClipboard: () => void;
};
export const SecretTable = ({
isLoading,
sharedSecret,
decryptedSecret,
timeLeft,
isUrlCopied,
copyUrlToClipboard
}: Props) => {
return (
<TableContainer>
<Table>
<THead>
<Tr>
<Th>Secret</Th>
<Th>Valid Until</Th>
</Tr>
</THead>
<TBody>
{!isLoading && sharedSecret && decryptedSecret && (
<Tr key={sharedSecret.encryptedValue}>
<Td>
<div className="flex items-center md:space-x-2">
<div className="max-w-[20rem] flex-1 break-words">
<SecretInput isVisible value={decryptedSecret} readOnly />
</div>
<IconButton
ariaLabel="copy to clipboard"
onClick={copyUrlToClipboard}
className="rounded p-2 hover:bg-gray-700"
size="xs"
>
<FontAwesomeIcon icon={isUrlCopied ? faCheck : faCopy} />
</IconButton>
</div>
</Td>
<Td>{timeLeft}</Td>
</Tr>
)}
{isLoading && (
<Tr>
<Td colSpan={4} className="bg-mineshaft-800 text-center text-bunker-400">
Loading...
</Td>
</Tr>
)}
{!isLoading && !sharedSecret && (
<Tr>
<Td colSpan={4} className="bg-mineshaft-800 text-center text-bunker-400">
<EmptyState title="No such secret is shared yet!" icon={faKey} />
</Td>
</Tr>
)}
{!isLoading && sharedSecret && !decryptedSecret && (
<Tr>
<Td colSpan={4} className="bg-mineshaft-800 text-center text-bunker-400">
<EmptyState title="Invalid URL to fetch the Secret!" icon={faKey} />
</Td>
</Tr>
)}
</TBody>
</Table>
</TableContainer>
);
};
}: Props) => (
<div className="flex items-center rounded border border-solid border-mineshaft-700 bg-mineshaft-800 p-4">
{isLoading && <div className="bg-mineshaft-800 text-center text-bunker-400">Loading...</div>}
{!isLoading && !decryptedSecret && (
<Tr>
<Td colSpan={4} className="bg-mineshaft-800 text-center text-bunker-400">
<EmptyState title="Secret has either expired or does not exist!" icon={faKey} />
</Td>
</Tr>
)}
{!isLoading && decryptedSecret && (
<>
<div className="max-w-[20rem] flex-1 break-words pr-4">
<SecretInput isVisible value={decryptedSecret} readOnly />
</div>
<IconButton
ariaLabel="copy to clipboard"
onClick={copyUrlToClipboard}
className="rounded p-2 hover:bg-gray-700"
size="xs"
>
<FontAwesomeIcon icon={isUrlCopied ? faCheck : faCopy} />
</IconButton>
</>
)}
</div>
);