Skip to content

Commit 0200861

Browse files
committed
fix failing tests, cleanup
1 parent 9afca3e commit 0200861

File tree

6 files changed

+21
-22
lines changed

6 files changed

+21
-22
lines changed

apps/sim/app/(auth)/signup/signup-form.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,8 @@ describe('SignupPage', () => {
211211
fireEvent.click(submitButton)
212212

213213
await waitFor(() => {
214-
expect(mockSendOtp).toHaveBeenCalledWith({
215-
email: 'user@company.com',
216-
type: 'email-verification',
217-
})
214+
// With sendVerificationOnSignUp: true, OTP is sent automatically by Better Auth
215+
// No manual OTP sending in the component anymore
218216
expect(mockRouter.push).toHaveBeenCalledWith('/verify?fromSignup=true')
219217
})
220218
})
@@ -390,7 +388,9 @@ describe('SignupPage', () => {
390388
fireEvent.click(submitButton)
391389

392390
await waitFor(() => {
393-
expect(mockRouter.push).toHaveBeenCalledWith('/invite/123')
391+
// Security fix: ALL signups now go to /verify first to prevent bypass
392+
// The invite redirect happens AFTER email verification is completed
393+
expect(mockRouter.push).toHaveBeenCalledWith('/verify?fromSignup=true')
394394
})
395395
})
396396

apps/sim/app/(auth)/signup/signup-form.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,13 +327,12 @@ function SignupFormContent({
327327
return
328328
}
329329

330-
// For new signups, always require verification to prevent bypass
331-
// sendVerificationOnSignUp: true will automatically send the OTP
330+
// For new signups, always require verification
332331
if (typeof window !== 'undefined') {
333332
sessionStorage.setItem('verificationEmail', emailValue)
334333
localStorage.setItem('has_logged_in_before', 'true')
335334

336-
// Set cookie flag for middleware check (prevents bypass)
335+
// Set cookie flag for middleware check
337336
document.cookie = 'requiresEmailVerification=true; path=/; max-age=900; SameSite=Lax' // 15 min expiry
338337
document.cookie = 'has_logged_in_before=true; path=/; max-age=31536000; SameSite=Lax'
339338

apps/sim/app/(auth)/verify/use-verification.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export function useVerification({
125125
if (typeof window !== 'undefined') {
126126
sessionStorage.removeItem('verificationEmail')
127127

128-
// Clear the verification requirement flag - this prevents the bypass
128+
// Clear the verification requirement flag
129129
document.cookie =
130130
'requiresEmailVerification=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT'
131131

apps/sim/lib/auth.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ export const auth = betterAuth({
156156
},
157157
emailAndPassword: {
158158
enabled: true,
159-
requireEmailVerification: false, // Keep false - don't break existing users
160-
sendVerificationOnSignUp: true, // Auto-send verification emails
159+
requireEmailVerification: false,
160+
sendVerificationOnSignUp: true,
161161
throwOnMissingCredentials: true,
162162
throwOnInvalidCredentials: true,
163163
sendResetPassword: async ({ user, url, token }, request) => {
@@ -238,7 +238,7 @@ export const auth = betterAuth({
238238
throw new Error('Email is required')
239239
}
240240

241-
// Validate email before sending OTP (using quick validation for performance)
241+
// Validate email before sending OTP
242242
const validation = quickValidateEmail(data.email)
243243
if (!validation.isValid) {
244244
logger.warn('Email validation failed', {

apps/sim/lib/email/validation.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,28 @@ import { quickValidateEmail, validateEmail } from './validation'
22

33
describe('Email Validation', () => {
44
describe('validateEmail', () => {
5-
it('should validate a correct email', async () => {
5+
it.concurrent('should validate a correct email', async () => {
66
const result = await validateEmail('user@example.com')
77
expect(result.isValid).toBe(true)
88
expect(result.checks.syntax).toBe(true)
99
expect(result.checks.disposable).toBe(true)
1010
})
1111

12-
it('should reject invalid syntax', async () => {
12+
it.concurrent('should reject invalid syntax', async () => {
1313
const result = await validateEmail('invalid-email')
1414
expect(result.isValid).toBe(false)
1515
expect(result.reason).toBe('Invalid email format')
1616
expect(result.checks.syntax).toBe(false)
1717
})
1818

19-
it('should reject disposable email addresses', async () => {
19+
it.concurrent('should reject disposable email addresses', async () => {
2020
const result = await validateEmail('test@10minutemail.com')
2121
expect(result.isValid).toBe(false)
2222
expect(result.reason).toBe('Disposable email addresses are not allowed')
2323
expect(result.checks.disposable).toBe(false)
2424
})
2525

26-
it('should accept legitimate business emails', async () => {
26+
it.concurrent('should accept legitimate business emails', async () => {
2727
const legitimateEmails = [
2828
'test@gmail.com',
2929
'noreply@gmail.com',
@@ -38,13 +38,13 @@ describe('Email Validation', () => {
3838
}
3939
})
4040

41-
it('should reject consecutive dots (RFC violation)', async () => {
41+
it.concurrent('should reject consecutive dots (RFC violation)', async () => {
4242
const result = await validateEmail('user..name@example.com')
4343
expect(result.isValid).toBe(false)
4444
expect(result.reason).toBe('Email contains suspicious patterns')
4545
})
4646

47-
it('should reject very long local parts (RFC violation)', async () => {
47+
it.concurrent('should reject very long local parts (RFC violation)', async () => {
4848
const longLocalPart = 'a'.repeat(65)
4949
const result = await validateEmail(`${longLocalPart}@example.com`)
5050
expect(result.isValid).toBe(false)
@@ -53,20 +53,20 @@ describe('Email Validation', () => {
5353
})
5454

5555
describe('quickValidateEmail', () => {
56-
it('should validate quickly without MX check', () => {
56+
it.concurrent('should validate quickly without MX check', () => {
5757
const result = quickValidateEmail('user@example.com')
5858
expect(result.isValid).toBe(true)
5959
expect(result.checks.mxRecord).toBe(true) // Skipped, so assumed true
6060
expect(result.confidence).toBe('medium')
6161
})
6262

63-
it('should reject invalid emails quickly', () => {
63+
it.concurrent('should reject invalid emails quickly', () => {
6464
const result = quickValidateEmail('invalid-email')
6565
expect(result.isValid).toBe(false)
6666
expect(result.reason).toBe('Invalid email format')
6767
})
6868

69-
it('should reject disposable emails quickly', () => {
69+
it.concurrent('should reject disposable emails quickly', () => {
7070
const result = quickValidateEmail('test@tempmail.org')
7171
expect(result.isValid).toBe(false)
7272
expect(result.reason).toBe('Disposable email addresses are not allowed')

apps/sim/middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export async function middleware(request: NextRequest) {
9494
return NextResponse.redirect(new URL('/login', request.url))
9595
}
9696

97-
// Check if user needs email verification (prevents the bypass vulnerability)
97+
// Check if user needs email verification
9898
const requiresVerification = request.cookies.get('requiresEmailVerification')
9999
if (requiresVerification?.value === 'true') {
100100
return NextResponse.redirect(new URL('/verify', request.url))

0 commit comments

Comments
 (0)