From 0401793d38a89facdea5531a6afa5b751304a6f5 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 19 May 2025 10:48:58 -0400 Subject: [PATCH] Changed "token" param to "hash" and used hex encoding for URL --- .../server/routes/v1/secret-sharing-router.ts | 4 ++-- .../secret-sharing/secret-sharing-service.ts | 18 +++++++++--------- .../secret-sharing/secret-sharing-types.ts | 2 +- .../src/hooks/api/secretSharing/queries.ts | 10 +++++----- .../ViewSharedSecretByIDPage.tsx | 6 +++--- .../public/ViewSharedSecretByIDPage/route.tsx | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/backend/src/server/routes/v1/secret-sharing-router.ts b/backend/src/server/routes/v1/secret-sharing-router.ts index 71fb9bc68..e712ee138 100644 --- a/backend/src/server/routes/v1/secret-sharing-router.ts +++ b/backend/src/server/routes/v1/secret-sharing-router.ts @@ -64,7 +64,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) => hashedHex: z.string().min(1).optional(), password: z.string().optional(), email: z.string().optional(), - token: z.string().optional() + hash: z.string().optional() }), response: { 200: z.object({ @@ -92,7 +92,7 @@ export const registerSecretSharingRouter = async (server: FastifyZodProvider) => password: req.body.password, orgId: req.permission?.orgId, email: req.body.email, - token: req.body.token + hash: req.body.hash }); if (sharedSecret.secret?.orgId) { diff --git a/backend/src/services/secret-sharing/secret-sharing-service.ts b/backend/src/services/secret-sharing/secret-sharing-service.ts index ec7fa287a..e56b10e46 100644 --- a/backend/src/services/secret-sharing/secret-sharing-service.ts +++ b/backend/src/services/secret-sharing/secret-sharing-service.ts @@ -118,7 +118,7 @@ export const secretSharingServiceFactory = ({ } } - // Generate salt for signing email tokens (if emails are provided) + // Generate salt for signing email hashes (if emails are provided) salt = crypto.randomBytes(32).toString("hex"); encryptedSalt = encryptWithRoot(Buffer.from(salt)); } @@ -159,7 +159,7 @@ export const secretSharingServiceFactory = ({ for await (const email of emails) { try { const hmac = crypto.createHmac("sha256", salt).update(email); - const token = hmac.digest("base64"); + const hash = hmac.digest("hex"); // Only show the username to emails which are part of the organization const respondentUsername = orgEmails.includes(email) ? user.username : undefined; @@ -170,7 +170,7 @@ export const secretSharingServiceFactory = ({ substitutions: { name, respondentUsername, - secretRequestUrl: `${appCfg.SITE_URL}/shared/secret/${idToReturn}?email=${encodeURIComponent(email)}&token=${token}` + secretRequestUrl: `${appCfg.SITE_URL}/shared/secret/${idToReturn}?email=${encodeURIComponent(email)}&hash=${hash}` }, template: SmtpTemplates.SecretRequestCompleted }); @@ -460,7 +460,7 @@ export const secretSharingServiceFactory = ({ orgId, password, email, - token + hash }: TGetActiveSharedSecretByIdDTO) => { const sharedSecret = isUuidV4(sharedSecretId) ? await secretSharingDAL.findOne({ @@ -512,22 +512,22 @@ export const secretSharingServiceFactory = ({ if (sharedSecret.authorizedEmails && sharedSecret.encryptedSalt) { // Verify both params were passed - if (!email || !token) { + if (!email || !hash) { throw new BadRequestError({ - message: "This secret is email protected. Parameters must include email and token." + message: "This secret is email protected. Parameters must include email and hash." }); // Verify that email is authorized to view shared secret } else if (!(sharedSecret.authorizedEmails as string[]).includes(email)) { throw new UnauthorizedError({ message: "Email not authorized to view secret" }); - // Verify that token matches + // Verify that hash matches } else { const salt = decryptWithRoot(sharedSecret.encryptedSalt).toString(); const hmac = crypto.createHmac("sha256", salt).update(email); - const rebuiltToken = hmac.digest("base64"); + const rebuiltHash = hmac.digest("hex"); - if (rebuiltToken !== token) { + if (rebuiltHash !== hash) { throw new UnauthorizedError({ message: "Email not authorized to view secret" }); } } diff --git a/backend/src/services/secret-sharing/secret-sharing-types.ts b/backend/src/services/secret-sharing/secret-sharing-types.ts index eae6a48fa..049dbb913 100644 --- a/backend/src/services/secret-sharing/secret-sharing-types.ts +++ b/backend/src/services/secret-sharing/secret-sharing-types.ts @@ -41,7 +41,7 @@ export type TGetActiveSharedSecretByIdDTO = { // For secrets shared with specific emails email?: string; - token?: string; + hash?: string; }; export type TValidateActiveSharedSecretDTO = TGetActiveSharedSecretByIdDTO & { diff --git a/frontend/src/hooks/api/secretSharing/queries.ts b/frontend/src/hooks/api/secretSharing/queries.ts index 0e8c59947..cfd505ff0 100644 --- a/frontend/src/hooks/api/secretSharing/queries.ts +++ b/frontend/src/hooks/api/secretSharing/queries.ts @@ -16,7 +16,7 @@ export const secretSharingKeys = { hashedHex: string | null; password?: string; email?: string; - token?: string; + hash?: string; }) => ["shared-secret", arg], getSecretRequestById: (arg: { id: string }) => ["secret-request", arg] as const }; @@ -75,7 +75,7 @@ export const useGetActiveSharedSecretById = ({ hashedHex, password, email, - token + hash }: { sharedSecretId: string; hashedHex: string | null; @@ -83,7 +83,7 @@ export const useGetActiveSharedSecretById = ({ // For secrets shared to specific emails (optional) email?: string; - token?: string; + hash?: string; }) => { return useQuery({ queryKey: secretSharingKeys.getSecretById({ @@ -91,7 +91,7 @@ export const useGetActiveSharedSecretById = ({ hashedHex, password, email, - token + hash }), queryFn: async () => { const { data } = await apiRequest.post( @@ -100,7 +100,7 @@ export const useGetActiveSharedSecretById = ({ ...(hashedHex && { hashedHex }), password, email, - token + hash } ); diff --git a/frontend/src/pages/public/ViewSharedSecretByIDPage/ViewSharedSecretByIDPage.tsx b/frontend/src/pages/public/ViewSharedSecretByIDPage/ViewSharedSecretByIDPage.tsx index 4c83b0357..389aee68f 100644 --- a/frontend/src/pages/public/ViewSharedSecretByIDPage/ViewSharedSecretByIDPage.tsx +++ b/frontend/src/pages/public/ViewSharedSecretByIDPage/ViewSharedSecretByIDPage.tsx @@ -42,9 +42,9 @@ export const ViewSharedSecretByIDPage = () => { from: ROUTE_PATHS.Public.ViewSharedSecretByIDPage.id, select: (el) => el.email }); - const token = useSearch({ + const hash = useSearch({ from: ROUTE_PATHS.Public.ViewSharedSecretByIDPage.id, - select: (el) => el.token + select: (el) => el.hash }); const [password, setPassword] = useState(); const { hashedHex, key } = extractDetailsFromUrl(urlEncodedKey); @@ -59,7 +59,7 @@ export const ViewSharedSecretByIDPage = () => { hashedHex, password, email, - token + hash }); const navigate = useNavigate(); diff --git a/frontend/src/pages/public/ViewSharedSecretByIDPage/route.tsx b/frontend/src/pages/public/ViewSharedSecretByIDPage/route.tsx index a1bc4009c..7cbcb59a2 100644 --- a/frontend/src/pages/public/ViewSharedSecretByIDPage/route.tsx +++ b/frontend/src/pages/public/ViewSharedSecretByIDPage/route.tsx @@ -9,7 +9,7 @@ import { ViewSharedSecretByIDPage } from "./ViewSharedSecretByIDPage"; const SharedSecretByIDPageQuerySchema = z.object({ key: z.string().catch(""), email: z.string().optional(), - token: z.string().optional() + hash: z.string().optional() }); export const Route = createFileRoute("/shared/secret/$secretId")({