feat(auth): add password reset functionality and user model update

- Introduced a `mustResetPassword` field in the User model to manage password reset requirements.
- Enhanced authentication flow to support password changes, including validation and error handling.
- Updated frontend components to handle password reset scenarios and integrate with the new API endpoints.
- Modified authentication context and hooks to accommodate the new password reset logic.
- Adjusted E2E tests to ensure proper coverage for the password reset functionality.
This commit is contained in:
Adrian Acala
2026-01-18 12:33:25 -08:00
parent 1a52fe80f3
commit 15ac634d15
12 changed files with 370 additions and 32 deletions
+37 -1
View File
@@ -7,6 +7,7 @@ type AuthStatus = {
enabled: boolean;
authenticated: boolean;
bootstrapRequired?: boolean;
user?: { mustResetPassword?: boolean } | null;
};
const AUTH_USERNAME = process.env.AUTH_USERNAME || "admin";
@@ -43,10 +44,44 @@ const fetchAuthStatus = async (request: APIRequestContext): Promise<AuthStatus>
export const ensureApiAuthenticated = async (request: APIRequestContext) => {
const status = await fetchAuthStatus(request);
if (!status.enabled || status.authenticated) {
if (!status.enabled || (status.authenticated && !status.user?.mustResetPassword)) {
return;
}
const resetIfRequired = async () => {
if (!status.user?.mustResetPassword) return;
let resetResponse = await request.post(`${BASE_URL}/auth/password`, {
headers: {
"Content-Type": "application/json",
...(await getCsrfHeaders(request)),
},
data: {
currentPassword: AUTH_PASSWORD,
newPassword: AUTH_PASSWORD,
},
});
if (!resetResponse.ok() && resetResponse.status() === 403) {
await refreshCsrfToken(request);
resetResponse = await request.post(`${BASE_URL}/auth/password`, {
headers: {
"Content-Type": "application/json",
...(await getCsrfHeaders(request)),
},
data: {
currentPassword: AUTH_PASSWORD,
newPassword: AUTH_PASSWORD,
},
});
}
if (!resetResponse.ok()) {
const text = await resetResponse.text();
throw new Error(`Failed to reset admin password: ${resetResponse.status()} ${text}`);
}
};
if (status.bootstrapRequired) {
let response = await request.post(`${BASE_URL}/auth/bootstrap`, {
headers: {
@@ -78,6 +113,7 @@ export const ensureApiAuthenticated = async (request: APIRequestContext) => {
throw new Error(`Failed to bootstrap test session: ${response.status()} ${text}`);
}
await resetIfRequired();
return;
}