fix: security improvements (#2593)

This commit is contained in:
Catalin Pit
2026-04-30 07:43:20 +03:00
committed by GitHub
parent 2f4c3893a3
commit ae497092d7
17 changed files with 324 additions and 40 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
import { z } from 'zod';
import { ZNameSchema } from '@documenso/lib/constants/auth';
import { zEmail } from '@documenso/lib/utils/zod';
export const ZCurrentPasswordSchema = z
@@ -36,7 +37,7 @@ export const ZPasswordSchema = z
});
export const ZSignUpSchema = z.object({
name: z.string().min(1),
name: ZNameSchema,
email: zEmail(),
password: ZPasswordSchema,
signature: z.string().nullish(),
+15
View File
@@ -1,8 +1,23 @@
import { z } from 'zod';
import { env } from '../utils/env';
import { NEXT_PUBLIC_WEBAPP_URL } from './app';
export const SALT_ROUNDS = 12;
export const URL_PATTERN = /https?:\/\/|www\./i;
/**
* Shared name schema that disallows URLs to prevent phishing via email rendering.
*/
export const ZNameSchema = z
.string()
.trim()
.min(3, { message: 'Please enter a valid name.' })
.refine((value) => !URL_PATTERN.test(value), {
message: 'Name cannot contain URLs.',
});
export const IDENTITY_PROVIDER_NAME: Record<string, string> = {
DOCUMENSO: 'Documenso',
GOOGLE: 'Google',
@@ -2,7 +2,7 @@ import crypto from 'crypto';
import { prisma } from '@documenso/prisma';
import { ONE_DAY } from '../../constants/time';
import { ONE_HOUR } from '../../constants/time';
import { sendForgotPassword } from '../auth/send-forgot-password';
export const forgotPassword = async ({ email }: { email: string }) => {
@@ -41,7 +41,7 @@ export const forgotPassword = async ({ email }: { email: string }) => {
await prisma.passwordResetToken.create({
data: {
token,
expiry: new Date(Date.now() + ONE_DAY),
expiry: new Date(Date.now() + ONE_HOUR),
userId: user.id,
},
});
@@ -54,6 +54,12 @@ export const updatePassword = async ({
},
});
await tx.passwordResetToken.deleteMany({
where: {
userId,
},
});
return await tx.user.update({
where: {
id: userId,
@@ -1,5 +1,7 @@
import { z } from 'zod';
import { ZNameSchema } from '@documenso/lib/constants/auth';
export const ZFindUserSecurityAuditLogsSchema = z.object({
page: z.number().optional(),
perPage: z.number().optional(),
@@ -8,7 +10,7 @@ export const ZFindUserSecurityAuditLogsSchema = z.object({
export type TFindUserSecurityAuditLogsSchema = z.infer<typeof ZFindUserSecurityAuditLogsSchema>;
export const ZUpdateProfileMutationSchema = z.object({
name: z.string().min(1),
name: ZNameSchema,
signature: z.string(),
});
+7 -3
View File
@@ -1,6 +1,7 @@
import { TeamMemberRole } from '@prisma/client';
import { z } from 'zod';
import { URL_PATTERN, ZNameSchema } from '@documenso/lib/constants/auth';
import { PROTECTED_TEAM_URLS } from '@documenso/lib/constants/teams';
import { zEmail } from '@documenso/lib/utils/zod';
@@ -39,11 +40,14 @@ export const ZTeamNameSchema = z
.string()
.trim()
.min(3, { message: 'Team name must be at least 3 characters long.' })
.max(30, { message: 'Team name must not exceed 30 characters.' });
.max(30, { message: 'Team name must not exceed 30 characters.' })
.refine((value) => !URL_PATTERN.test(value), {
message: 'Team name cannot contain URLs.',
});
export const ZCreateTeamEmailVerificationMutationSchema = z.object({
teamId: z.number(),
name: z.string().trim().min(1, { message: 'Please enter a valid name.' }),
name: ZNameSchema,
email: zEmail().trim().toLowerCase().min(1, 'Please enter a valid email.'),
});
@@ -62,7 +66,7 @@ export const ZGetTeamMembersQuerySchema = z.object({
export const ZUpdateTeamEmailMutationSchema = z.object({
teamId: z.number(),
data: z.object({
name: z.string().trim().min(1),
name: ZNameSchema,
}),
});