Compare commits
4 Commits
v1.7.0-rc.
...
v1.7.0-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f4972d63b | ||
|
|
4c13176c52 | ||
|
|
d599ab0630 | ||
|
|
9e714d607e |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/marketing",
|
"name": "@documenso/marketing",
|
||||||
"version": "1.7.0-rc.1",
|
"version": "1.7.0-rc.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/web",
|
"name": "@documenso/web",
|
||||||
"version": "1.7.0-rc.1",
|
"version": "1.7.0-rc.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { trpc } from '@documenso/trpc/react';
|
|||||||
import { Button } from '@documenso/ui/primitives/button';
|
import { Button } from '@documenso/ui/primitives/button';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogClose,
|
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogFooter,
|
DialogFooter,
|
||||||
@@ -28,13 +27,16 @@ import {
|
|||||||
FormControl,
|
FormControl,
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from '@documenso/ui/primitives/form/form';
|
} from '@documenso/ui/primitives/form/form';
|
||||||
|
import { Input } from '@documenso/ui/primitives/input';
|
||||||
import { PinInput, PinInputGroup, PinInputSlot } from '@documenso/ui/primitives/pin-input';
|
import { PinInput, PinInputGroup, PinInputSlot } from '@documenso/ui/primitives/pin-input';
|
||||||
import { useToast } from '@documenso/ui/primitives/use-toast';
|
import { useToast } from '@documenso/ui/primitives/use-toast';
|
||||||
|
|
||||||
export const ZDisable2FAForm = z.object({
|
export const ZDisable2FAForm = z.object({
|
||||||
token: z.string(),
|
totpCode: z.string().trim().optional(),
|
||||||
|
backupCode: z.string().trim().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TDisable2FAForm = z.infer<typeof ZDisable2FAForm>;
|
export type TDisable2FAForm = z.infer<typeof ZDisable2FAForm>;
|
||||||
@@ -46,21 +48,43 @@ export const DisableAuthenticatorAppDialog = () => {
|
|||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [twoFactorDisableMethod, setTwoFactorDisableMethod] = useState<'totp' | 'backup'>('totp');
|
||||||
|
|
||||||
const { mutateAsync: disable2FA } = trpc.twoFactorAuthentication.disable.useMutation();
|
const { mutateAsync: disable2FA } = trpc.twoFactorAuthentication.disable.useMutation();
|
||||||
|
|
||||||
const disable2FAForm = useForm<TDisable2FAForm>({
|
const disable2FAForm = useForm<TDisable2FAForm>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
token: '',
|
totpCode: '',
|
||||||
|
backupCode: '',
|
||||||
},
|
},
|
||||||
resolver: zodResolver(ZDisable2FAForm),
|
resolver: zodResolver(ZDisable2FAForm),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const onCloseTwoFactorDisableDialog = () => {
|
||||||
|
disable2FAForm.reset();
|
||||||
|
|
||||||
|
setIsOpen(!isOpen);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onToggleTwoFactorDisableMethodClick = () => {
|
||||||
|
const method = twoFactorDisableMethod === 'totp' ? 'backup' : 'totp';
|
||||||
|
|
||||||
|
if (method === 'totp') {
|
||||||
|
disable2FAForm.setValue('backupCode', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method === 'backup') {
|
||||||
|
disable2FAForm.setValue('totpCode', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
setTwoFactorDisableMethod(method);
|
||||||
|
};
|
||||||
|
|
||||||
const { isSubmitting: isDisable2FASubmitting } = disable2FAForm.formState;
|
const { isSubmitting: isDisable2FASubmitting } = disable2FAForm.formState;
|
||||||
|
|
||||||
const onDisable2FAFormSubmit = async ({ token }: TDisable2FAForm) => {
|
const onDisable2FAFormSubmit = async ({ totpCode, backupCode }: TDisable2FAForm) => {
|
||||||
try {
|
try {
|
||||||
await disable2FA({ token });
|
await disable2FA({ totpCode, backupCode });
|
||||||
|
|
||||||
toast({
|
toast({
|
||||||
title: _(msg`Two-factor authentication disabled`),
|
title: _(msg`Two-factor authentication disabled`),
|
||||||
@@ -70,7 +94,7 @@ export const DisableAuthenticatorAppDialog = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
flushSync(() => {
|
flushSync(() => {
|
||||||
setIsOpen(false);
|
onCloseTwoFactorDisableDialog();
|
||||||
});
|
});
|
||||||
|
|
||||||
router.refresh();
|
router.refresh();
|
||||||
@@ -86,7 +110,7 @@ export const DisableAuthenticatorAppDialog = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={onCloseTwoFactorDisableDialog}>
|
||||||
<DialogTrigger asChild={true}>
|
<DialogTrigger asChild={true}>
|
||||||
<Button className="flex-shrink-0" variant="destructive">
|
<Button className="flex-shrink-0" variant="destructive">
|
||||||
<Trans>Disable 2FA</Trans>
|
<Trans>Disable 2FA</Trans>
|
||||||
@@ -110,33 +134,59 @@ export const DisableAuthenticatorAppDialog = () => {
|
|||||||
<Form {...disable2FAForm}>
|
<Form {...disable2FAForm}>
|
||||||
<form onSubmit={disable2FAForm.handleSubmit(onDisable2FAFormSubmit)}>
|
<form onSubmit={disable2FAForm.handleSubmit(onDisable2FAFormSubmit)}>
|
||||||
<fieldset className="flex flex-col gap-y-4" disabled={isDisable2FASubmitting}>
|
<fieldset className="flex flex-col gap-y-4" disabled={isDisable2FASubmitting}>
|
||||||
<FormField
|
{twoFactorDisableMethod === 'totp' && (
|
||||||
name="token"
|
<FormField
|
||||||
control={disable2FAForm.control}
|
name="totpCode"
|
||||||
render={({ field }) => (
|
control={disable2FAForm.control}
|
||||||
<FormItem>
|
render={({ field }) => (
|
||||||
<FormControl>
|
<FormItem>
|
||||||
<PinInput {...field} value={field.value ?? ''} maxLength={6}>
|
<FormControl>
|
||||||
{Array(6)
|
<PinInput {...field} value={field.value ?? ''} maxLength={6}>
|
||||||
.fill(null)
|
{Array(6)
|
||||||
.map((_, i) => (
|
.fill(null)
|
||||||
<PinInputGroup key={i}>
|
.map((_, i) => (
|
||||||
<PinInputSlot index={i} />
|
<PinInputGroup key={i}>
|
||||||
</PinInputGroup>
|
<PinInputSlot index={i} />
|
||||||
))}
|
</PinInputGroup>
|
||||||
</PinInput>
|
))}
|
||||||
</FormControl>
|
</PinInput>
|
||||||
<FormMessage />
|
</FormControl>
|
||||||
</FormItem>
|
<FormMessage />
|
||||||
)}
|
</FormItem>
|
||||||
/>
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{twoFactorDisableMethod === 'backup' && (
|
||||||
|
<FormField
|
||||||
|
control={disable2FAForm.control}
|
||||||
|
name="backupCode"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
<Trans>Backup Code</Trans>
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input type="text" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<DialogClose asChild>
|
<Button
|
||||||
<Button type="button" variant="secondary">
|
type="button"
|
||||||
<Trans>Cancel</Trans>
|
variant="secondary"
|
||||||
</Button>
|
onClick={onToggleTwoFactorDisableMethodClick}
|
||||||
</DialogClose>
|
>
|
||||||
|
{twoFactorDisableMethod === 'totp' ? (
|
||||||
|
<Trans>Use Backup Code</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans>Use Authenticator</Trans>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
|
||||||
<Button type="submit" variant="destructive" loading={isDisable2FASubmitting}>
|
<Button type="submit" variant="destructive" loading={isDisable2FASubmitting}>
|
||||||
<Trans>Disable 2FA</Trans>
|
<Trans>Disable 2FA</Trans>
|
||||||
|
|||||||
8
package-lock.json
generated
8
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@documenso/root",
|
"name": "@documenso/root",
|
||||||
"version": "1.7.0-rc.1",
|
"version": "1.7.0-rc.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@documenso/root",
|
"name": "@documenso/root",
|
||||||
"version": "1.7.0-rc.1",
|
"version": "1.7.0-rc.3",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"apps/*",
|
"apps/*",
|
||||||
"packages/*"
|
"packages/*"
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
},
|
},
|
||||||
"apps/marketing": {
|
"apps/marketing": {
|
||||||
"name": "@documenso/marketing",
|
"name": "@documenso/marketing",
|
||||||
"version": "1.7.0-rc.1",
|
"version": "1.7.0-rc.3",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@documenso/assets": "*",
|
"@documenso/assets": "*",
|
||||||
@@ -424,7 +424,7 @@
|
|||||||
},
|
},
|
||||||
"apps/web": {
|
"apps/web": {
|
||||||
"name": "@documenso/web",
|
"name": "@documenso/web",
|
||||||
"version": "1.7.0-rc.1",
|
"version": "1.7.0-rc.3",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@documenso/api": "*",
|
"@documenso/api": "*",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.7.0-rc.1",
|
"version": "1.7.0-rc.3",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "turbo run build",
|
"build": "turbo run build",
|
||||||
"build:web": "turbo run build --filter=@documenso/web",
|
"build:web": "turbo run build --filter=@documenso/web",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
ZSendDocumentForSigningMutationSchema,
|
ZSendDocumentForSigningMutationSchema,
|
||||||
ZSuccessfulDeleteTemplateResponseSchema,
|
ZSuccessfulDeleteTemplateResponseSchema,
|
||||||
ZSuccessfulDocumentResponseSchema,
|
ZSuccessfulDocumentResponseSchema,
|
||||||
|
ZSuccessfulFieldCreationResponseSchema,
|
||||||
ZSuccessfulFieldResponseSchema,
|
ZSuccessfulFieldResponseSchema,
|
||||||
ZSuccessfulGetDocumentResponseSchema,
|
ZSuccessfulGetDocumentResponseSchema,
|
||||||
ZSuccessfulGetTemplateResponseSchema,
|
ZSuccessfulGetTemplateResponseSchema,
|
||||||
@@ -236,7 +237,7 @@ export const ApiContractV1 = c.router(
|
|||||||
path: '/api/v1/documents/:id/fields',
|
path: '/api/v1/documents/:id/fields',
|
||||||
body: ZCreateFieldMutationSchema,
|
body: ZCreateFieldMutationSchema,
|
||||||
responses: {
|
responses: {
|
||||||
200: ZSuccessfulFieldResponseSchema,
|
200: ZSuccessfulFieldCreationResponseSchema,
|
||||||
400: ZUnsuccessfulResponseSchema,
|
400: ZUnsuccessfulResponseSchema,
|
||||||
401: ZUnsuccessfulResponseSchema,
|
401: ZUnsuccessfulResponseSchema,
|
||||||
404: ZUnsuccessfulResponseSchema,
|
404: ZUnsuccessfulResponseSchema,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createNextRoute } from '@ts-rest/next';
|
import { createNextRoute } from '@ts-rest/next';
|
||||||
|
import { match } from 'ts-pattern';
|
||||||
|
|
||||||
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
|
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
|
||||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||||
@@ -15,7 +16,6 @@ import { getDocumentById } from '@documenso/lib/server-only/document/get-documen
|
|||||||
import { resendDocument } from '@documenso/lib/server-only/document/resend-document';
|
import { resendDocument } from '@documenso/lib/server-only/document/resend-document';
|
||||||
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
||||||
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
|
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
|
||||||
import { createField } from '@documenso/lib/server-only/field/create-field';
|
|
||||||
import { deleteField } from '@documenso/lib/server-only/field/delete-field';
|
import { deleteField } from '@documenso/lib/server-only/field/delete-field';
|
||||||
import { getFieldById } from '@documenso/lib/server-only/field/get-field-by-id';
|
import { getFieldById } from '@documenso/lib/server-only/field/get-field-by-id';
|
||||||
import { updateField } from '@documenso/lib/server-only/field/update-field';
|
import { updateField } from '@documenso/lib/server-only/field/update-field';
|
||||||
@@ -32,6 +32,13 @@ import { deleteTemplate } from '@documenso/lib/server-only/template/delete-templ
|
|||||||
import { findTemplates } from '@documenso/lib/server-only/template/find-templates';
|
import { findTemplates } from '@documenso/lib/server-only/template/find-templates';
|
||||||
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
import { getTemplateById } from '@documenso/lib/server-only/template/get-template-by-id';
|
||||||
import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
||||||
|
import {
|
||||||
|
ZCheckboxFieldMeta,
|
||||||
|
ZDropdownFieldMeta,
|
||||||
|
ZNumberFieldMeta,
|
||||||
|
ZRadioFieldMeta,
|
||||||
|
ZTextFieldMeta,
|
||||||
|
} from '@documenso/lib/types/field-meta';
|
||||||
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
import { extractNextApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||||
import { getFile } from '@documenso/lib/universal/upload/get-file';
|
import { getFile } from '@documenso/lib/universal/upload/get-file';
|
||||||
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
|
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
|
||||||
@@ -39,6 +46,8 @@ import {
|
|||||||
getPresignGetUrl,
|
getPresignGetUrl,
|
||||||
getPresignPostUrl,
|
getPresignPostUrl,
|
||||||
} from '@documenso/lib/universal/upload/server-actions';
|
} from '@documenso/lib/universal/upload/server-actions';
|
||||||
|
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
|
||||||
|
import { prisma } from '@documenso/prisma';
|
||||||
import { DocumentDataType, DocumentStatus, SigningStatus } from '@documenso/prisma/client';
|
import { DocumentDataType, DocumentStatus, SigningStatus } from '@documenso/prisma/client';
|
||||||
|
|
||||||
import { ApiContractV1 } from './contract';
|
import { ApiContractV1 } from './contract';
|
||||||
@@ -870,100 +879,167 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
|||||||
|
|
||||||
createField: authenticatedMiddleware(async (args, user, team) => {
|
createField: authenticatedMiddleware(async (args, user, team) => {
|
||||||
const { id: documentId } = args.params;
|
const { id: documentId } = args.params;
|
||||||
const { recipientId, type, pageNumber, pageWidth, pageHeight, pageX, pageY, fieldMeta } =
|
const fields = Array.isArray(args.body) ? args.body : [args.body];
|
||||||
args.body;
|
|
||||||
|
|
||||||
if (pageNumber <= 0) {
|
const document = await prisma.document.findFirst({
|
||||||
return {
|
select: { id: true, status: true },
|
||||||
status: 400,
|
where: {
|
||||||
body: {
|
id: Number(documentId),
|
||||||
message: 'Invalid page number',
|
...(team?.id
|
||||||
},
|
? {
|
||||||
};
|
team: {
|
||||||
}
|
id: team.id,
|
||||||
|
members: { some: { userId: user.id } },
|
||||||
const document = await getDocumentById({
|
},
|
||||||
id: Number(documentId),
|
}
|
||||||
userId: user.id,
|
: {
|
||||||
teamId: team?.id,
|
userId: user.id,
|
||||||
|
teamId: null,
|
||||||
|
}),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!document) {
|
if (!document) {
|
||||||
return {
|
return {
|
||||||
status: 404,
|
status: 404,
|
||||||
body: {
|
body: { message: 'Document not found' },
|
||||||
message: 'Document not found',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (document.status === DocumentStatus.COMPLETED) {
|
if (document.status === DocumentStatus.COMPLETED) {
|
||||||
return {
|
return {
|
||||||
status: 400,
|
status: 400,
|
||||||
body: {
|
body: { message: 'Document is already completed' },
|
||||||
message: 'Document is already completed',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const recipient = await getRecipientById({
|
|
||||||
id: Number(recipientId),
|
|
||||||
documentId: Number(documentId),
|
|
||||||
}).catch(() => null);
|
|
||||||
|
|
||||||
if (!recipient) {
|
|
||||||
return {
|
|
||||||
status: 404,
|
|
||||||
body: {
|
|
||||||
message: 'Recipient not found',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipient.signingStatus === SigningStatus.SIGNED) {
|
|
||||||
return {
|
|
||||||
status: 400,
|
|
||||||
body: {
|
|
||||||
message: 'Recipient has already signed the document',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const field = await createField({
|
const createdFields = await prisma.$transaction(async (tx) => {
|
||||||
documentId: Number(documentId),
|
return Promise.all(
|
||||||
recipientId: Number(recipientId),
|
fields.map(async (fieldData) => {
|
||||||
userId: user.id,
|
const {
|
||||||
teamId: team?.id,
|
recipientId,
|
||||||
type,
|
type,
|
||||||
pageNumber,
|
pageNumber,
|
||||||
pageX,
|
pageWidth,
|
||||||
pageY,
|
pageHeight,
|
||||||
pageWidth,
|
pageX,
|
||||||
pageHeight,
|
pageY,
|
||||||
fieldMeta,
|
fieldMeta,
|
||||||
requestMetadata: extractNextApiRequestMetadata(args.req),
|
} = fieldData;
|
||||||
});
|
|
||||||
|
|
||||||
const remappedField = {
|
if (pageNumber <= 0) {
|
||||||
id: field.id,
|
throw new Error('Invalid page number');
|
||||||
documentId: field.documentId,
|
}
|
||||||
recipientId: field.recipientId ?? -1,
|
|
||||||
type: field.type,
|
const recipient = await getRecipientById({
|
||||||
pageNumber: field.page,
|
id: Number(recipientId),
|
||||||
pageX: Number(field.positionX),
|
documentId: Number(documentId),
|
||||||
pageY: Number(field.positionY),
|
}).catch(() => null);
|
||||||
pageWidth: Number(field.width),
|
|
||||||
pageHeight: Number(field.height),
|
if (!recipient) {
|
||||||
customText: field.customText,
|
throw new Error('Recipient not found');
|
||||||
fieldMeta: ZFieldMetaSchema.parse(field.fieldMeta),
|
}
|
||||||
inserted: field.inserted,
|
|
||||||
};
|
if (recipient.signingStatus === SigningStatus.SIGNED) {
|
||||||
|
throw new Error('Recipient has already signed the document');
|
||||||
|
}
|
||||||
|
|
||||||
|
const advancedField = ['NUMBER', 'RADIO', 'CHECKBOX', 'DROPDOWN', 'TEXT'].includes(
|
||||||
|
type,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (advancedField && !fieldMeta) {
|
||||||
|
throw new Error(
|
||||||
|
'Field meta is required for this type of field. Please provide the appropriate field meta object.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldMeta && fieldMeta.type.toLowerCase() !== String(type).toLowerCase()) {
|
||||||
|
throw new Error('Field meta type does not match the field type');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = match(type)
|
||||||
|
.with('RADIO', () => ZRadioFieldMeta.safeParse(fieldMeta))
|
||||||
|
.with('CHECKBOX', () => ZCheckboxFieldMeta.safeParse(fieldMeta))
|
||||||
|
.with('DROPDOWN', () => ZDropdownFieldMeta.safeParse(fieldMeta))
|
||||||
|
.with('NUMBER', () => ZNumberFieldMeta.safeParse(fieldMeta))
|
||||||
|
.with('TEXT', () => ZTextFieldMeta.safeParse(fieldMeta))
|
||||||
|
.with('SIGNATURE', 'INITIALS', 'DATE', 'EMAIL', 'NAME', () => ({
|
||||||
|
success: true,
|
||||||
|
data: {},
|
||||||
|
}))
|
||||||
|
.with('FREE_SIGNATURE', () => ({
|
||||||
|
success: false,
|
||||||
|
error: 'FREE_SIGNATURE is not supported',
|
||||||
|
data: {},
|
||||||
|
}))
|
||||||
|
.exhaustive();
|
||||||
|
|
||||||
|
if (!result.success) {
|
||||||
|
throw new Error('Field meta parsing failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
const field = await tx.field.create({
|
||||||
|
data: {
|
||||||
|
documentId: Number(documentId),
|
||||||
|
recipientId: Number(recipientId),
|
||||||
|
type,
|
||||||
|
page: pageNumber,
|
||||||
|
positionX: pageX,
|
||||||
|
positionY: pageY,
|
||||||
|
width: pageWidth,
|
||||||
|
height: pageHeight,
|
||||||
|
customText: '',
|
||||||
|
inserted: false,
|
||||||
|
fieldMeta: result.data,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
Recipient: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await tx.documentAuditLog.create({
|
||||||
|
data: createDocumentAuditLogData({
|
||||||
|
type: 'FIELD_CREATED',
|
||||||
|
documentId: Number(documentId),
|
||||||
|
user: {
|
||||||
|
id: team?.id ?? user.id,
|
||||||
|
email: team?.name ?? user.email,
|
||||||
|
name: team ? '' : user.name,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
fieldId: field.secondaryId,
|
||||||
|
fieldRecipientEmail: field.Recipient?.email ?? '',
|
||||||
|
fieldRecipientId: recipientId,
|
||||||
|
fieldType: field.type,
|
||||||
|
},
|
||||||
|
requestMetadata: extractNextApiRequestMetadata(args.req),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: field.id,
|
||||||
|
documentId: Number(field.documentId),
|
||||||
|
recipientId: field.recipientId ?? -1,
|
||||||
|
type: field.type,
|
||||||
|
pageNumber: field.page,
|
||||||
|
pageX: Number(field.positionX),
|
||||||
|
pageY: Number(field.positionY),
|
||||||
|
pageWidth: Number(field.width),
|
||||||
|
pageHeight: Number(field.height),
|
||||||
|
customText: field.customText,
|
||||||
|
fieldMeta: ZFieldMetaSchema.parse(field.fieldMeta),
|
||||||
|
inserted: field.inserted,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: 200,
|
status: 200,
|
||||||
body: {
|
body: {
|
||||||
...remappedField,
|
fields: createdFields,
|
||||||
documentId: Number(documentId),
|
documentId: Number(documentId),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ export type TSuccessfulRecipientResponseSchema = z.infer<typeof ZSuccessfulRecip
|
|||||||
/**
|
/**
|
||||||
* Fields
|
* Fields
|
||||||
*/
|
*/
|
||||||
export const ZCreateFieldMutationSchema = z.object({
|
const ZCreateFieldSchema = z.object({
|
||||||
recipientId: z.number(),
|
recipientId: z.number(),
|
||||||
type: z.nativeEnum(FieldType),
|
type: z.nativeEnum(FieldType),
|
||||||
pageNumber: z.number(),
|
pageNumber: z.number(),
|
||||||
@@ -301,12 +301,17 @@ export const ZCreateFieldMutationSchema = z.object({
|
|||||||
pageY: z.number(),
|
pageY: z.number(),
|
||||||
pageWidth: z.number(),
|
pageWidth: z.number(),
|
||||||
pageHeight: z.number(),
|
pageHeight: z.number(),
|
||||||
fieldMeta: ZFieldMetaSchema,
|
fieldMeta: ZFieldMetaSchema.openapi({}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const ZCreateFieldMutationSchema = z.union([
|
||||||
|
ZCreateFieldSchema,
|
||||||
|
z.array(ZCreateFieldSchema).min(1),
|
||||||
|
]);
|
||||||
|
|
||||||
export type TCreateFieldMutationSchema = z.infer<typeof ZCreateFieldMutationSchema>;
|
export type TCreateFieldMutationSchema = z.infer<typeof ZCreateFieldMutationSchema>;
|
||||||
|
|
||||||
export const ZUpdateFieldMutationSchema = ZCreateFieldMutationSchema.partial();
|
export const ZUpdateFieldMutationSchema = ZCreateFieldSchema.partial();
|
||||||
|
|
||||||
export type TUpdateFieldMutationSchema = z.infer<typeof ZUpdateFieldMutationSchema>;
|
export type TUpdateFieldMutationSchema = z.infer<typeof ZUpdateFieldMutationSchema>;
|
||||||
|
|
||||||
@@ -314,6 +319,26 @@ export const ZDeleteFieldMutationSchema = null;
|
|||||||
|
|
||||||
export type TDeleteFieldMutationSchema = typeof ZDeleteFieldMutationSchema;
|
export type TDeleteFieldMutationSchema = typeof ZDeleteFieldMutationSchema;
|
||||||
|
|
||||||
|
const ZSuccessfulFieldSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
documentId: z.number(),
|
||||||
|
recipientId: z.number(),
|
||||||
|
type: z.nativeEnum(FieldType),
|
||||||
|
pageNumber: z.number(),
|
||||||
|
pageX: z.number(),
|
||||||
|
pageY: z.number(),
|
||||||
|
pageWidth: z.number(),
|
||||||
|
pageHeight: z.number(),
|
||||||
|
customText: z.string(),
|
||||||
|
fieldMeta: ZFieldMetaSchema,
|
||||||
|
inserted: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ZSuccessfulFieldCreationResponseSchema = z.object({
|
||||||
|
fields: z.union([ZSuccessfulFieldSchema, z.array(ZSuccessfulFieldSchema)]),
|
||||||
|
documentId: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
export const ZSuccessfulFieldResponseSchema = z.object({
|
export const ZSuccessfulFieldResponseSchema = z.object({
|
||||||
id: z.number(),
|
id: z.number(),
|
||||||
documentId: z.number(),
|
documentId: z.number(),
|
||||||
|
|||||||
@@ -2,25 +2,33 @@ import { prisma } from '@documenso/prisma';
|
|||||||
import type { User } from '@documenso/prisma/client';
|
import type { User } from '@documenso/prisma/client';
|
||||||
import { UserSecurityAuditLogType } from '@documenso/prisma/client';
|
import { UserSecurityAuditLogType } from '@documenso/prisma/client';
|
||||||
|
|
||||||
import { AppError } 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 { validateTwoFactorAuthentication } from './validate-2fa';
|
import { validateTwoFactorAuthentication } from './validate-2fa';
|
||||||
|
|
||||||
type DisableTwoFactorAuthenticationOptions = {
|
type DisableTwoFactorAuthenticationOptions = {
|
||||||
user: User;
|
user: User;
|
||||||
token: string;
|
totpCode?: string;
|
||||||
|
backupCode?: string;
|
||||||
requestMetadata?: RequestMetadata;
|
requestMetadata?: RequestMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const disableTwoFactorAuthentication = async ({
|
export const disableTwoFactorAuthentication = async ({
|
||||||
token,
|
totpCode,
|
||||||
|
backupCode,
|
||||||
user,
|
user,
|
||||||
requestMetadata,
|
requestMetadata,
|
||||||
}: DisableTwoFactorAuthenticationOptions) => {
|
}: DisableTwoFactorAuthenticationOptions) => {
|
||||||
let isValid = await validateTwoFactorAuthentication({ totpCode: token, user });
|
let isValid = false;
|
||||||
|
|
||||||
if (!isValid) {
|
if (!totpCode && !backupCode) {
|
||||||
isValid = await validateTwoFactorAuthentication({ backupCode: token, user });
|
throw new AppError(AppErrorCode.INVALID_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totpCode) {
|
||||||
|
isValid = await validateTwoFactorAuthentication({ totpCode, user });
|
||||||
|
} else if (backupCode) {
|
||||||
|
isValid = await validateTwoFactorAuthentication({ backupCode, user });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
|
|||||||
@@ -110,24 +110,21 @@ export const createField = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = match(type)
|
const result = match(type)
|
||||||
.with('RADIO', () => {
|
.with('RADIO', () => ZRadioFieldMeta.safeParse(fieldMeta))
|
||||||
return ZRadioFieldMeta.safeParse(fieldMeta);
|
.with('CHECKBOX', () => ZCheckboxFieldMeta.safeParse(fieldMeta))
|
||||||
})
|
.with('DROPDOWN', () => ZDropdownFieldMeta.safeParse(fieldMeta))
|
||||||
.with('CHECKBOX', () => {
|
.with('NUMBER', () => ZNumberFieldMeta.safeParse(fieldMeta))
|
||||||
return ZCheckboxFieldMeta.safeParse(fieldMeta);
|
.with('TEXT', () => ZTextFieldMeta.safeParse(fieldMeta))
|
||||||
})
|
.with('SIGNATURE', 'INITIALS', 'DATE', 'EMAIL', 'NAME', () => ({
|
||||||
.with('DROPDOWN', () => {
|
success: true,
|
||||||
return ZDropdownFieldMeta.safeParse(fieldMeta);
|
data: {},
|
||||||
})
|
}))
|
||||||
.with('NUMBER', () => {
|
.with('FREE_SIGNATURE', () => ({
|
||||||
return ZNumberFieldMeta.safeParse(fieldMeta);
|
success: false,
|
||||||
})
|
error: 'FREE_SIGNATURE is not supported',
|
||||||
.with('TEXT', () => {
|
data: {},
|
||||||
return ZTextFieldMeta.safeParse(fieldMeta);
|
}))
|
||||||
})
|
.exhaustive();
|
||||||
.otherwise(() => {
|
|
||||||
return { success: false, data: {} };
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
throw new Error('Field meta parsing failed');
|
throw new Error('Field meta parsing failed');
|
||||||
@@ -145,7 +142,7 @@ export const createField = async ({
|
|||||||
height: pageHeight,
|
height: pageHeight,
|
||||||
customText: '',
|
customText: '',
|
||||||
inserted: false,
|
inserted: false,
|
||||||
fieldMeta: advancedField ? result.data : undefined,
|
fieldMeta: result.data,
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
Recipient: true,
|
Recipient: true,
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ export const updateField = async ({
|
|||||||
requestMetadata,
|
requestMetadata,
|
||||||
fieldMeta,
|
fieldMeta,
|
||||||
}: UpdateFieldOptions) => {
|
}: UpdateFieldOptions) => {
|
||||||
|
if (type === 'FREE_SIGNATURE') {
|
||||||
|
throw new Error('Cannot update a FREE_SIGNATURE field');
|
||||||
|
}
|
||||||
|
|
||||||
const oldField = await prisma.field.findFirstOrThrow({
|
const oldField = await prisma.field.findFirstOrThrow({
|
||||||
where: {
|
where: {
|
||||||
id: fieldId,
|
id: fieldId,
|
||||||
|
|||||||
@@ -607,6 +607,7 @@ msgstr ""
|
|||||||
msgid "Background Color"
|
msgid "Background Color"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:167
|
||||||
#: apps/web/src/components/forms/signin.tsx:451
|
#: apps/web/src/components/forms/signin.tsx:451
|
||||||
msgid "Backup Code"
|
msgid "Backup Code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -684,7 +685,6 @@ msgstr ""
|
|||||||
#: apps/web/src/components/(teams)/dialogs/transfer-team-dialog.tsx:278
|
#: apps/web/src/components/(teams)/dialogs/transfer-team-dialog.tsx:278
|
||||||
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:162
|
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:162
|
||||||
#: apps/web/src/components/(teams)/dialogs/update-team-member-dialog.tsx:187
|
#: apps/web/src/components/(teams)/dialogs/update-team-member-dialog.tsx:187
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:137
|
|
||||||
#: apps/web/src/components/forms/2fa/enable-authenticator-app-dialog.tsx:257
|
#: apps/web/src/components/forms/2fa/enable-authenticator-app-dialog.tsx:257
|
||||||
#: apps/web/src/components/forms/2fa/view-recovery-codes-dialog.tsx:163
|
#: apps/web/src/components/forms/2fa/view-recovery-codes-dialog.tsx:163
|
||||||
#: apps/web/src/components/templates/manage-public-template-dialog.tsx:452
|
#: apps/web/src/components/templates/manage-public-template-dialog.tsx:452
|
||||||
@@ -1143,9 +1143,9 @@ msgstr ""
|
|||||||
msgid "Disable"
|
msgid "Disable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:92
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:116
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:99
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:123
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:142
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:192
|
||||||
msgid "Disable 2FA"
|
msgid "Disable 2FA"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2279,7 +2279,7 @@ msgstr ""
|
|||||||
msgid "Please note that you will lose access to all documents associated with this team & all the members will be removed and notified"
|
msgid "Please note that you will lose access to all documents associated with this team & all the members will be removed and notified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:103
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:127
|
||||||
msgid "Please provide a token from the authenticator, or a backup code. If you do not have a backup code available, please contact support."
|
msgid "Please provide a token from the authenticator, or a backup code. If you do not have a backup code available, please contact support."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3453,7 +3453,7 @@ msgstr ""
|
|||||||
msgid "Two-Factor Authentication"
|
msgid "Two-Factor Authentication"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:66
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:90
|
||||||
msgid "Two-factor authentication disabled"
|
msgid "Two-factor authentication disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3461,7 +3461,7 @@ msgstr ""
|
|||||||
msgid "Two-factor authentication enabled"
|
msgid "Two-factor authentication enabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:68
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:92
|
||||||
msgid "Two-factor authentication has been disabled for your account. You will no longer be required to enter a code from your authenticator app when signing in."
|
msgid "Two-factor authentication has been disabled for your account. You will no longer be required to enter a code from your authenticator app when signing in."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3506,7 +3506,7 @@ msgstr ""
|
|||||||
msgid "Unable to delete team"
|
msgid "Unable to delete team"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:79
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:103
|
||||||
msgid "Unable to disable two-factor authentication"
|
msgid "Unable to disable two-factor authentication"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3654,10 +3654,12 @@ msgstr ""
|
|||||||
msgid "Uploaded file not an allowed file type"
|
msgid "Uploaded file not an allowed file type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:187
|
||||||
#: apps/web/src/components/forms/signin.tsx:471
|
#: apps/web/src/components/forms/signin.tsx:471
|
||||||
msgid "Use Authenticator"
|
msgid "Use Authenticator"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:185
|
||||||
#: apps/web/src/components/forms/signin.tsx:469
|
#: apps/web/src/components/forms/signin.tsx:469
|
||||||
msgid "Use Backup Code"
|
msgid "Use Backup Code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -3944,7 +3946,7 @@ msgstr ""
|
|||||||
msgid "We were unable to create a checkout session. Please try again, or contact support"
|
msgid "We were unable to create a checkout session. Please try again, or contact support"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:81
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:105
|
||||||
msgid "We were unable to disable two-factor authentication for your account. Please ensure that you have entered your password and backup code correctly and try again."
|
msgid "We were unable to disable two-factor authentication for your account. Please ensure that you have entered your password and backup code correctly and try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -602,6 +602,7 @@ msgstr "Back to Documents"
|
|||||||
msgid "Background Color"
|
msgid "Background Color"
|
||||||
msgstr "Background Color"
|
msgstr "Background Color"
|
||||||
|
|
||||||
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:167
|
||||||
#: apps/web/src/components/forms/signin.tsx:451
|
#: apps/web/src/components/forms/signin.tsx:451
|
||||||
msgid "Backup Code"
|
msgid "Backup Code"
|
||||||
msgstr "Backup Code"
|
msgstr "Backup Code"
|
||||||
@@ -679,7 +680,6 @@ msgstr "By enabling 2FA, you will be required to enter a code from your authenti
|
|||||||
#: apps/web/src/components/(teams)/dialogs/transfer-team-dialog.tsx:278
|
#: apps/web/src/components/(teams)/dialogs/transfer-team-dialog.tsx:278
|
||||||
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:162
|
#: apps/web/src/components/(teams)/dialogs/update-team-email-dialog.tsx:162
|
||||||
#: apps/web/src/components/(teams)/dialogs/update-team-member-dialog.tsx:187
|
#: apps/web/src/components/(teams)/dialogs/update-team-member-dialog.tsx:187
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:137
|
|
||||||
#: apps/web/src/components/forms/2fa/enable-authenticator-app-dialog.tsx:257
|
#: apps/web/src/components/forms/2fa/enable-authenticator-app-dialog.tsx:257
|
||||||
#: apps/web/src/components/forms/2fa/view-recovery-codes-dialog.tsx:163
|
#: apps/web/src/components/forms/2fa/view-recovery-codes-dialog.tsx:163
|
||||||
#: apps/web/src/components/templates/manage-public-template-dialog.tsx:452
|
#: apps/web/src/components/templates/manage-public-template-dialog.tsx:452
|
||||||
@@ -1138,9 +1138,9 @@ msgstr "Direct template link usage exceeded ({0}/{1})"
|
|||||||
msgid "Disable"
|
msgid "Disable"
|
||||||
msgstr "Disable"
|
msgstr "Disable"
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:92
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:116
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:99
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:123
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:142
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:192
|
||||||
msgid "Disable 2FA"
|
msgid "Disable 2FA"
|
||||||
msgstr "Disable 2FA"
|
msgstr "Disable 2FA"
|
||||||
|
|
||||||
@@ -2274,7 +2274,7 @@ msgstr "Please note that this action is irreversible. Once confirmed, your webho
|
|||||||
msgid "Please note that you will lose access to all documents associated with this team & all the members will be removed and notified"
|
msgid "Please note that you will lose access to all documents associated with this team & all the members will be removed and notified"
|
||||||
msgstr "Please note that you will lose access to all documents associated with this team & all the members will be removed and notified"
|
msgstr "Please note that you will lose access to all documents associated with this team & all the members will be removed and notified"
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:103
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:127
|
||||||
msgid "Please provide a token from the authenticator, or a backup code. If you do not have a backup code available, please contact support."
|
msgid "Please provide a token from the authenticator, or a backup code. If you do not have a backup code available, please contact support."
|
||||||
msgstr "Please provide a token from the authenticator, or a backup code. If you do not have a backup code available, please contact support."
|
msgstr "Please provide a token from the authenticator, or a backup code. If you do not have a backup code available, please contact support."
|
||||||
|
|
||||||
@@ -3448,7 +3448,7 @@ msgstr "Two factor authentication recovery codes are used to access your account
|
|||||||
msgid "Two-Factor Authentication"
|
msgid "Two-Factor Authentication"
|
||||||
msgstr "Two-Factor Authentication"
|
msgstr "Two-Factor Authentication"
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:66
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:90
|
||||||
msgid "Two-factor authentication disabled"
|
msgid "Two-factor authentication disabled"
|
||||||
msgstr "Two-factor authentication disabled"
|
msgstr "Two-factor authentication disabled"
|
||||||
|
|
||||||
@@ -3456,7 +3456,7 @@ msgstr "Two-factor authentication disabled"
|
|||||||
msgid "Two-factor authentication enabled"
|
msgid "Two-factor authentication enabled"
|
||||||
msgstr "Two-factor authentication enabled"
|
msgstr "Two-factor authentication enabled"
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:68
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:92
|
||||||
msgid "Two-factor authentication has been disabled for your account. You will no longer be required to enter a code from your authenticator app when signing in."
|
msgid "Two-factor authentication has been disabled for your account. You will no longer be required to enter a code from your authenticator app when signing in."
|
||||||
msgstr "Two-factor authentication has been disabled for your account. You will no longer be required to enter a code from your authenticator app when signing in."
|
msgstr "Two-factor authentication has been disabled for your account. You will no longer be required to enter a code from your authenticator app when signing in."
|
||||||
|
|
||||||
@@ -3501,7 +3501,7 @@ msgstr "Unable to delete invitation. Please try again."
|
|||||||
msgid "Unable to delete team"
|
msgid "Unable to delete team"
|
||||||
msgstr "Unable to delete team"
|
msgstr "Unable to delete team"
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:79
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:103
|
||||||
msgid "Unable to disable two-factor authentication"
|
msgid "Unable to disable two-factor authentication"
|
||||||
msgstr "Unable to disable two-factor authentication"
|
msgstr "Unable to disable two-factor authentication"
|
||||||
|
|
||||||
@@ -3649,10 +3649,12 @@ msgstr "Uploaded file is too small"
|
|||||||
msgid "Uploaded file not an allowed file type"
|
msgid "Uploaded file not an allowed file type"
|
||||||
msgstr "Uploaded file not an allowed file type"
|
msgstr "Uploaded file not an allowed file type"
|
||||||
|
|
||||||
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:187
|
||||||
#: apps/web/src/components/forms/signin.tsx:471
|
#: apps/web/src/components/forms/signin.tsx:471
|
||||||
msgid "Use Authenticator"
|
msgid "Use Authenticator"
|
||||||
msgstr "Use Authenticator"
|
msgstr "Use Authenticator"
|
||||||
|
|
||||||
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:185
|
||||||
#: apps/web/src/components/forms/signin.tsx:469
|
#: apps/web/src/components/forms/signin.tsx:469
|
||||||
msgid "Use Backup Code"
|
msgid "Use Backup Code"
|
||||||
msgstr "Use Backup Code"
|
msgstr "Use Backup Code"
|
||||||
@@ -3939,7 +3941,7 @@ msgstr "We were unable to copy your recovery code to your clipboard. Please try
|
|||||||
msgid "We were unable to create a checkout session. Please try again, or contact support"
|
msgid "We were unable to create a checkout session. Please try again, or contact support"
|
||||||
msgstr "We were unable to create a checkout session. Please try again, or contact support"
|
msgstr "We were unable to create a checkout session. Please try again, or contact support"
|
||||||
|
|
||||||
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:81
|
#: apps/web/src/components/forms/2fa/disable-authenticator-app-dialog.tsx:105
|
||||||
msgid "We were unable to disable two-factor authentication for your account. Please ensure that you have entered your password and backup code correctly and try again."
|
msgid "We were unable to disable two-factor authentication for your account. Please ensure that you have entered your password and backup code correctly and try again."
|
||||||
msgstr "We were unable to disable two-factor authentication for your account. Please ensure that you have entered your password and backup code correctly and try again."
|
msgstr "We were unable to disable two-factor authentication for your account. Please ensure that you have entered your password and backup code correctly and try again."
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ export const twoFactorAuthenticationRouter = router({
|
|||||||
|
|
||||||
return await disableTwoFactorAuthentication({
|
return await disableTwoFactorAuthentication({
|
||||||
user,
|
user,
|
||||||
token: input.token,
|
totpCode: input.totpCode,
|
||||||
|
backupCode: input.backupCode,
|
||||||
requestMetadata: extractNextApiRequestMetadata(ctx.req),
|
requestMetadata: extractNextApiRequestMetadata(ctx.req),
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ export type TEnableTwoFactorAuthenticationMutationSchema = z.infer<
|
|||||||
>;
|
>;
|
||||||
|
|
||||||
export const ZDisableTwoFactorAuthenticationMutationSchema = z.object({
|
export const ZDisableTwoFactorAuthenticationMutationSchema = z.object({
|
||||||
token: z.string().trim().min(1),
|
totpCode: z.string().trim().optional(),
|
||||||
|
backupCode: z.string().trim().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TDisableTwoFactorAuthenticationMutationSchema = z.infer<
|
export type TDisableTwoFactorAuthenticationMutationSchema = z.infer<
|
||||||
|
|||||||
Reference in New Issue
Block a user