Merge branch 'feat/passkey' into feat/document-passkey-test

This commit is contained in:
David Nguyen
2024-03-17 15:14:32 +08:00
4 changed files with 26 additions and 6 deletions

View File

@ -11,6 +11,7 @@ import { match } from 'ts-pattern';
import { UAParser } from 'ua-parser-js'; import { UAParser } from 'ua-parser-js';
import { z } from 'zod'; import { z } from 'zod';
import { MAXIMUM_PASSKEYS } from '@documenso/lib/constants/auth';
import { AppError } from '@documenso/lib/errors/app-error'; import { AppError } from '@documenso/lib/errors/app-error';
import { trpc } from '@documenso/trpc/react'; import { trpc } from '@documenso/trpc/react';
import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert'; import { Alert, AlertDescription, AlertTitle } from '@documenso/ui/primitives/alert';
@ -179,7 +180,7 @@ export const CreatePasskeyDialog = ({ trigger, ...props }: CreatePasskeyDialogPr
<AlertDescription className="mt-2"> <AlertDescription className="mt-2">
If you do not want to use the authenticator prompted, you can close it, which will If you do not want to use the authenticator prompted, you can close it, which will
then display the next avaliable authenticator. then display the next available authenticator.
</AlertDescription> </AlertDescription>
</Alert> </Alert>
@ -189,6 +190,11 @@ export const CreatePasskeyDialog = ({ trigger, ...props }: CreatePasskeyDialogPr
.with('ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED', () => ( .with('ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED', () => (
<AlertDescription>This passkey has already been registered.</AlertDescription> <AlertDescription>This passkey has already been registered.</AlertDescription>
)) ))
.with('TOO_MANY_PASSKEYS', () => (
<AlertDescription>
You cannot have more than {MAXIMUM_PASSKEYS} passkeys.
</AlertDescription>
))
.with('InvalidStateError', () => ( .with('InvalidStateError', () => (
<> <>
<AlertTitle className="text-sm"> <AlertTitle className="text-sm">

View File

@ -32,3 +32,8 @@ export const USER_SECURITY_AUDIT_LOG_MAP: { [key in UserSecurityAuditLogType]: s
* The duration to wait for a passkey to be verified in MS. * The duration to wait for a passkey to be verified in MS.
*/ */
export const PASSKEY_TIMEOUT = 60000; export const PASSKEY_TIMEOUT = 60000;
/**
* The maximum number of passkeys are user can have.
*/
export const MAXIMUM_PASSKEYS = 50;

View File

@ -4,6 +4,7 @@ import type { RegistrationResponseJSON } from '@simplewebauthn/types';
import { prisma } from '@documenso/prisma'; import { prisma } from '@documenso/prisma';
import { UserSecurityAuditLogType } from '@documenso/prisma/client'; import { UserSecurityAuditLogType } from '@documenso/prisma/client';
import { MAXIMUM_PASSKEYS } from '../../constants/auth';
import { AppError, AppErrorCode } from '../../errors/app-error'; import { AppError, AppErrorCode } from '../../errors/app-error';
import type { RequestMetadata } from '../../universal/extract-request-metadata'; import type { RequestMetadata } from '../../universal/extract-request-metadata';
import { getAuthenticatorRegistrationOptions } from '../../utils/authenticator'; import { getAuthenticatorRegistrationOptions } from '../../utils/authenticator';
@ -21,12 +22,23 @@ export const createPasskey = async ({
verificationResponse, verificationResponse,
requestMetadata, requestMetadata,
}: CreatePasskeyOptions) => { }: CreatePasskeyOptions) => {
await prisma.user.findFirstOrThrow({ const { _count } = await prisma.user.findFirstOrThrow({
where: { where: {
id: userId, id: userId,
}, },
include: {
_count: {
select: {
passkeys: true,
},
},
},
}); });
if (_count.passkeys >= MAXIMUM_PASSKEYS) {
throw new AppError('TOO_MANY_PASSKEYS');
}
const verificationToken = await prisma.verificationToken.findFirst({ const verificationToken = await prisma.verificationToken.findFirst({
where: { where: {
userId, userId,

View File

@ -110,10 +110,7 @@ export const authRouter = router({
} catch (err) { } catch (err) {
console.error(err); console.error(err);
throw new TRPCError({ throw AppError.parseErrorToTRPCError(err);
code: 'BAD_REQUEST',
message: 'We were unable to create this passkey. Please try again later.',
});
} }
}), }),