From dd162205faa6990fbbb228ea0d1e2acf89b7e599 Mon Sep 17 00:00:00 2001
From: Ephraim Duncan <55143799+ephraimduncan@users.noreply.github.com>
Date: Sun, 8 Dec 2024 03:17:58 +0000
Subject: [PATCH] fix: prevent accidental signatures (#1515)


---
.devcontainer/devcontainer.json | 10 +-
.../documents/[id]/document-page-view.tsx | 2 +-
.../d/[token]/sign-direct-template.tsx | 12 ++-
.../src/app/(signing)/sign/[token]/form.tsx | 30 +++++-
.../app/(signing)/sign/[token]/provider.tsx | 5 +
.../sign/[token]/signature-field.tsx | 37 ++++---
.../app/embed/direct/[[...url]]/client.tsx | 29 +++++-
.../src/app/embed/sign/[[...url]]/client.tsx | 31 +++++-
.../e2e/document-auth/action-auth.spec.ts | 16 +--
.../document-flow/stepper-component.spec.ts | 13 ++-
.../include-document-certificate.spec.ts | 12 +--
packages/app-tests/e2e/user/auth-flow.spec.ts | 5 +-
.../app-tests/e2e/user/update-name.spec.ts | 10 +-
packages/lib/translations/de/common.po | 22 ++---
packages/lib/translations/de/web.po | 97 ++++++++++---------
packages/lib/translations/en/common.po | 22 ++---
packages/lib/translations/en/web.po | 97 ++++++++++---------
packages/lib/translations/es/common.po | 22 ++---
packages/lib/translations/es/web.po | 97 ++++++++++---------
packages/lib/translations/fr/common.po | 22 ++---
packages/lib/translations/fr/web.po | 97 ++++++++++---------
.../document-flow/add-signature.tsx | 13 ++-
.../signature-pad/signature-pad.tsx | 34 ++++++-
23 files changed, 443 insertions(+), 292 deletions(-)
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 3471f4f88..790c1ab0b 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -10,13 +10,7 @@
"ghcr.io/devcontainers/features/node:1": {}
},
"onCreateCommand": "./.devcontainer/on-create.sh",
- "forwardPorts": [
- 3000,
- 54320,
- 9000,
- 2500,
- 1100
- ],
+ "forwardPorts": [3000, 54320, 9000, 2500, 1100],
"customizations": {
"vscode": {
"extensions": [
@@ -35,4 +29,4 @@
]
}
}
-}
\ No newline at end of file
+}
diff --git a/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx b/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx
index f05d148f7..ddc49b1cf 100644
--- a/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx
+++ b/apps/web/src/app/(dashboard)/documents/[id]/document-page-view.tsx
@@ -221,7 +221,7 @@ export const DocumentPageView = async ({ params, team }: DocumentPageViewProps)
-
+
{match(document.status)
.with(DocumentStatus.COMPLETED, () => (
This document has been signed by all recipients
diff --git a/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx b/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx
index bf9b671c4..f39863f43 100644
--- a/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx
+++ b/apps/web/src/app/(recipient)/d/[token]/sign-direct-template.tsx
@@ -1,7 +1,6 @@
import { useMemo, useState } from 'react';
import { Trans } from '@lingui/macro';
-import { useLingui } from '@lingui/react';
import { DateTime } from 'luxon';
import { match } from 'ts-pattern';
@@ -72,9 +71,8 @@ export const SignDirectTemplateForm = ({
template,
onSubmit,
}: SignDirectTemplateFormProps) => {
- const { _ } = useLingui();
-
- const { fullName, signature, setFullName, setSignature } = useRequiredSigningContext();
+ const { fullName, signature, signatureValid, setFullName, setSignature } =
+ useRequiredSigningContext();
const [localFields, setLocalFields] = useState(directRecipientFields);
const [validateUninsertedFields, setValidateUninsertedFields] = useState(false);
@@ -135,6 +133,8 @@ export const SignDirectTemplateForm = ({
);
};
+ const hasSignatureField = localFields.some((field) => field.type === FieldType.SIGNATURE);
+
const uninsertedFields = useMemo(() => {
return sortFieldsByPosition(localFields.filter((field) => !field.inserted));
}, [localFields]);
@@ -147,6 +147,10 @@ export const SignDirectTemplateForm = ({
const handleSubmit = async () => {
setValidateUninsertedFields(true);
+ if (hasSignatureField && !signatureValid) {
+ return;
+ }
+
const isFieldsValid = validateFieldsInserted(localFields);
if (!isFieldsValid) {
diff --git a/apps/web/src/app/(signing)/sign/[token]/form.tsx b/apps/web/src/app/(signing)/sign/[token]/form.tsx
index 8085234db..17a33dff3 100644
--- a/apps/web/src/app/(signing)/sign/[token]/form.tsx
+++ b/apps/web/src/app/(signing)/sign/[token]/form.tsx
@@ -12,7 +12,7 @@ import { useAnalytics } from '@documenso/lib/client-only/hooks/use-analytics';
import type { DocumentAndSender } from '@documenso/lib/server-only/document/get-document-by-token';
import type { TRecipientActionAuth } from '@documenso/lib/types/document-auth';
import { sortFieldsByPosition, validateFieldsInserted } from '@documenso/lib/utils/fields';
-import { type Field, type Recipient, RecipientRole } from '@documenso/prisma/client';
+import { type Field, FieldType, type Recipient, RecipientRole } from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import { FieldToolTip } from '@documenso/ui/components/field/field-tooltip';
import { cn } from '@documenso/ui/lib/utils';
@@ -44,7 +44,8 @@ export const SigningForm = ({
const analytics = useAnalytics();
const { data: session } = useSession();
- const { fullName, signature, setFullName, setSignature } = useRequiredSigningContext();
+ const { fullName, signature, setFullName, setSignature, signatureValid, setSignatureValid } =
+ useRequiredSigningContext();
const [validateUninsertedFields, setValidateUninsertedFields] = useState(false);
@@ -56,6 +57,8 @@ export const SigningForm = ({
// Keep the loading state going if successful since the redirect may take some time.
const isSubmitting = formState.isSubmitting || formState.isSubmitSuccessful;
+ const hasSignatureField = fields.some((field) => field.type === FieldType.SIGNATURE);
+
const uninsertedFields = useMemo(() => {
return sortFieldsByPosition(fields.filter((field) => !field.inserted));
}, [fields]);
@@ -68,6 +71,10 @@ export const SigningForm = ({
const onFormSubmit = async () => {
setValidateUninsertedFields(true);
+ if (hasSignatureField && !signatureValid) {
+ return;
+ }
+
const isFieldsValid = validateFieldsInserted(fields);
if (!isFieldsValid) {
@@ -142,7 +149,7 @@ export const SigningForm = ({
@@ -307,7 +322,7 @@ export const SignatureField = ({