-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy path+server.ts
More file actions
104 lines (89 loc) · 2.56 KB
/
Copy path+server.ts
File metadata and controls
104 lines (89 loc) · 2.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { json, error } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { db } from '$lib/server/db';
import { hashPassword } from '$lib/server/crypto';
import {
validatePasswordResetToken,
markPasswordResetTokenAsUsed
} from '$lib/server/password-reset';
import { deleteAllUserSessions, verifyCsrfToken } from '$lib/server/sessions';
import { createAuditLog } from '$lib/server/audit';
export const POST: RequestHandler = async (event) => {
try {
const { token, password, csrfToken: submittedCsrfToken } = await event.request.json();
// Validate CSRF token
if (!submittedCsrfToken || !verifyCsrfToken(event, submittedCsrfToken)) {
throw error(403, {
message: 'Invalid CSRF token'
});
}
if (!token || !password) {
throw error(400, {
message: 'Token and password are required'
});
}
// Parse token (format: "tokenId:token")
const [tokenId, tokenValue] = token.split(':');
if (!tokenId || !tokenValue) {
throw error(400, {
message: 'Invalid token format'
});
}
// Validate password strength
if (password.length < 8) {
throw error(400, {
message: 'Password must be at least 8 characters long'
});
}
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/;
if (!passwordRegex.test(password)) {
throw error(400, {
message:
'Password must contain at least one uppercase letter, one lowercase letter, and one number'
});
}
// Validate token
const userId = await validatePasswordResetToken(tokenId, tokenValue);
if (!userId) {
throw error(400, {
message: 'Invalid or expired reset token'
});
}
// Hash new password
const passwordHash = await hashPassword(password);
// Update user password
const user = await db.user.update({
where: { id: userId },
data: { passwordHash },
select: { id: true, email: true, teamId: true }
});
// Mark token as used
await markPasswordResetTokenAsUsed(tokenId);
// Invalidate all existing sessions (force re-login)
await deleteAllUserSessions(userId);
// Audit password reset completion
await createAuditLog({
userId: user.id,
teamId: user.teamId ?? undefined,
action: 'USER_PASSWORD_CHANGED',
resourceType: 'User',
resourceId: user.id,
metadata: {
email: user.email,
method: 'reset_token'
},
event
});
return json({
message: 'Password has been reset successfully'
});
} catch (err) {
if (err && typeof err === 'object' && 'status' in err) {
throw err;
}
console.error('Reset password error:', err);
throw error(500, {
message: 'An error occurred'
});
}
};