Files
documenso/apps/web/src/app/(signing)/sign/[token]/document-action-auth-dialog.tsx
David Nguyen cbe6270494 feat: add passkey and 2FA document action auth options (#1065)
## Description

Add the following document action auth options:
- 2FA
- Passkey

If the user does not have the required auth setup, we onboard them
directly.

## Changes made

Note: Added secondaryId to the VerificationToken schema

## Testing Performed

Tested locally, pending preview tests

## Checklist

- [X] I have tested these changes locally and they work as expected.
- [X] I have added/updated tests that prove the effectiveness of these
changes.
- [X] I have followed the project's coding style guidelines.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Introduced components for 2FA, account, and passkey authentication
during document signing.
- Added "Require passkey" option to document settings and signer
authentication settings.
- Enhanced form submission and loading states for improved user
experience.
- **Refactor**
- Optimized authentication components to efficiently support multiple
authentication methods.
- **Chores**
- Updated and renamed functions and components for clarity and
consistency across the authentication system.
- Refined sorting options and database schema to support new
authentication features.
- **Bug Fixes**
- Adjusted SignInForm to verify browser support for WebAuthn before
proceeding.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2024-03-31 15:49:12 +08:00

91 lines
2.7 KiB
TypeScript

import { P, match } from 'ts-pattern';
import {
DocumentAuth,
type TRecipientActionAuth,
type TRecipientActionAuthTypes,
} from '@documenso/lib/types/document-auth';
import type { FieldType } from '@documenso/prisma/client';
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from '@documenso/ui/primitives/dialog';
import { DocumentActionAuth2FA } from './document-action-auth-2fa';
import { DocumentActionAuthAccount } from './document-action-auth-account';
import { DocumentActionAuthPasskey } from './document-action-auth-passkey';
import { useRequiredDocumentAuthContext } from './document-auth-provider';
export type DocumentActionAuthDialogProps = {
title?: string;
documentAuthType: TRecipientActionAuthTypes;
description?: string;
actionTarget: FieldType | 'DOCUMENT';
open: boolean;
onOpenChange: (value: boolean) => void;
/**
* The callback to run when the reauth form is filled out.
*/
onReauthFormSubmit: (values?: TRecipientActionAuth) => Promise<void> | void;
};
export const DocumentActionAuthDialog = ({
title,
description,
documentAuthType,
open,
onOpenChange,
onReauthFormSubmit,
}: DocumentActionAuthDialogProps) => {
const { recipient, user, isCurrentlyAuthenticating } = useRequiredDocumentAuthContext();
const handleOnOpenChange = (value: boolean) => {
if (isCurrentlyAuthenticating) {
return;
}
onOpenChange(value);
};
return (
<Dialog open={open} onOpenChange={handleOnOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>{title || 'Sign field'}</DialogTitle>
<DialogDescription>
{description || 'Reauthentication is required to sign this field'}
</DialogDescription>
</DialogHeader>
{match({ documentAuthType, user })
.with(
{ documentAuthType: DocumentAuth.ACCOUNT },
{ user: P.when((user) => !user || user.email !== recipient.email) }, // Assume all current auth methods requires them to be logged in.
() => <DocumentActionAuthAccount onOpenChange={onOpenChange} />,
)
.with({ documentAuthType: DocumentAuth.PASSKEY }, () => (
<DocumentActionAuthPasskey
open={open}
onOpenChange={onOpenChange}
onReauthFormSubmit={onReauthFormSubmit}
/>
))
.with({ documentAuthType: DocumentAuth.TWO_FACTOR_AUTH }, () => (
<DocumentActionAuth2FA
open={open}
onOpenChange={onOpenChange}
onReauthFormSubmit={onReauthFormSubmit}
/>
))
.with({ documentAuthType: DocumentAuth.EXPLICIT_NONE }, () => null)
.exhaustive()}
</DialogContent>
</Dialog>
);
};