diff --git a/packages/backend/server/src/core/utils/__tests__/validators.spec.ts b/packages/backend/server/src/core/utils/__tests__/validators.spec.ts new file mode 100644 index 0000000000000..ec375688a90ab --- /dev/null +++ b/packages/backend/server/src/core/utils/__tests__/validators.spec.ts @@ -0,0 +1,44 @@ +import test from 'ava'; + +import { validators } from '../validators'; + +test('can validate', t => { + t.notThrows(() => validators.assertValidEmail('test@example.com')); + t.throws(() => validators.assertValidEmail('test@example')); + t.throws(() => validators.assertValidEmail('test')); + + t.notThrows(() => validators.assertValidPassword('password')); + t.notThrows(() => validators.assertValidPassword('a')); + t.throws(() => validators.assertValidPassword('')); + t.throws(() => validators.assertValidPassword('aaaaaaaaaaaaaaaaaaaaa')); + + t.notThrows(() => + validators.assertValidCredential({ + email: 'test@example.com', + password: 'password', + }) + ); + t.notThrows(() => + validators.assertValidCredential({ + email: 'test@example.com', + password: 'password', + challenge: 'challenge', + }) + ); + t.notThrows(() => + validators.assertValidCredential({ + email: 'test@example.com', + password: 'password', + verifyToken: 'verifyToken', + }) + ); + // challenge and verifyToken should not be both provided + t.throws(() => + validators.assertValidCredential({ + email: 'test@example.com', + password: 'password', + challenge: 'challenge', + verifyToken: 'verifyToken', + }) + ); +}); diff --git a/packages/backend/server/src/core/utils/validators.ts b/packages/backend/server/src/core/utils/validators.ts index 3621bd9b7d1f3..71e07320c4e7d 100644 --- a/packages/backend/server/src/core/utils/validators.ts +++ b/packages/backend/server/src/core/utils/validators.ts @@ -21,6 +21,28 @@ function getAuthCredentialValidator() { .required(); } +function getAuthCredentialWithCaptchaValidator() { + return getAuthCredentialValidator() + .extend({ + verifyToken: z.string().optional(), + challenge: z.string().optional(), + }) + .refine( + data => { + const hasChallenge = !!data.challenge; + const hasVerifyToken = !!data.verifyToken; + return ( + (!hasChallenge && !hasVerifyToken) || + (hasChallenge && !hasVerifyToken) || + (!hasChallenge && hasVerifyToken) + ); + }, + { + message: 'verifyToken and challenge should not be both provided', + } + ); +} + function assertValid(z: z.ZodType, value: unknown) { const result = z.safeParse(value); @@ -45,8 +67,10 @@ export function assertValidPassword(password: string) { export function assertValidCredential(credential: { email: string; password: string; + challenge?: string; + verifyToken?: string; }) { - assertValid(getAuthCredentialValidator(), credential); + assertValid(getAuthCredentialWithCaptchaValidator(), credential); } export const validators = {