mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 23:11:13 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
210
lib/services/auth/mfaService.ts
Normal file
210
lib/services/auth/mfaService.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* MFA (Multi-Factor Authentication) Service
|
||||
*
|
||||
* Handles TOTP (Time-based One-Time Password) setup, verification,
|
||||
* and management for two-factor authentication.
|
||||
*/
|
||||
|
||||
import { apiClient } from '@/lib/api/client';
|
||||
import {
|
||||
TOTPSetupResponse,
|
||||
TOTPConfirmData,
|
||||
TOTPVerifyData,
|
||||
MFAChallengeData,
|
||||
AuthResponse,
|
||||
} from '@/lib/types/auth';
|
||||
import { tokenStorage } from './tokenStorage';
|
||||
|
||||
/**
|
||||
* Enable MFA/2FA for current user
|
||||
* Returns TOTP secret and QR code URL
|
||||
*/
|
||||
export async function setupTOTP(): Promise<TOTPSetupResponse> {
|
||||
const response = await apiClient.post<TOTPSetupResponse>('/api/v1/auth/mfa/enable');
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm MFA setup with verification token
|
||||
* Completes MFA setup after verifying the token is valid
|
||||
*/
|
||||
export async function confirmTOTP(data: TOTPConfirmData): Promise<void> {
|
||||
await apiClient.post('/api/v1/auth/mfa/confirm', data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable MFA/2FA for current user
|
||||
* Removes all TOTP devices and disables MFA requirement
|
||||
*/
|
||||
export async function disableTOTP(): Promise<void> {
|
||||
await apiClient.post('/api/v1/auth/mfa/disable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify MFA token (for testing)
|
||||
* Returns whether the token is valid
|
||||
*/
|
||||
export async function verifyTOTP(data: TOTPVerifyData): Promise<boolean> {
|
||||
try {
|
||||
await apiClient.post('/api/v1/auth/mfa/verify', data);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete MFA challenge during login
|
||||
* Called when user has MFA enabled and needs to provide token
|
||||
*/
|
||||
export async function challengeMFA(data: MFAChallengeData): Promise<AuthResponse> {
|
||||
const response = await apiClient.post<AuthResponse>('/api/v1/auth/mfa/challenge', {
|
||||
token: data.code,
|
||||
});
|
||||
|
||||
// Store tokens after successful MFA challenge
|
||||
tokenStorage.setAccessToken(response.data.access);
|
||||
tokenStorage.setRefreshToken(response.data.refresh);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate new backup codes
|
||||
* Returns a list of one-time use backup codes
|
||||
*/
|
||||
export async function generateBackupCodes(): Promise<string[]> {
|
||||
const response = await apiClient.post<{ backup_codes: string[] }>('/api/v1/auth/mfa/backup-codes');
|
||||
return response.data.backup_codes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a backup code to login when TOTP is unavailable
|
||||
*/
|
||||
export async function useBackupCode(code: string): Promise<AuthResponse> {
|
||||
const response = await apiClient.post<AuthResponse>('/api/v1/auth/mfa/backup-code', {
|
||||
code,
|
||||
});
|
||||
|
||||
// Store tokens after successful backup code use
|
||||
tokenStorage.setAccessToken(response.data.access);
|
||||
tokenStorage.setRefreshToken(response.data.refresh);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove MFA with password confirmation
|
||||
*/
|
||||
export async function removeMFA(password: string): Promise<void> {
|
||||
await apiClient.post('/api/v1/auth/mfa/remove', {
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* WebAuthn/Passkey Support
|
||||
* Django-allauth provides WebAuthn through its MFA module
|
||||
*/
|
||||
|
||||
export interface WebAuthnCredential {
|
||||
id: string;
|
||||
name: string;
|
||||
created_at: string;
|
||||
last_used?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of registered WebAuthn credentials (passkeys)
|
||||
*/
|
||||
export async function getWebAuthnCredentials(): Promise<WebAuthnCredential[]> {
|
||||
const response = await apiClient.get<{ credentials: WebAuthnCredential[] }>(
|
||||
'/accounts/mfa/webauthn/list/'
|
||||
);
|
||||
return response.data.credentials;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start WebAuthn registration process
|
||||
* Returns challenge data for credential creation
|
||||
*/
|
||||
export async function startWebAuthnRegistration(): Promise<PublicKeyCredentialCreationOptions> {
|
||||
const response = await apiClient.get<PublicKeyCredentialCreationOptions>(
|
||||
'/accounts/mfa/webauthn/add/'
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete WebAuthn registration
|
||||
* @param credential The created PublicKeyCredential from browser
|
||||
* @param name Optional friendly name for the credential
|
||||
*/
|
||||
export async function completeWebAuthnRegistration(
|
||||
credential: PublicKeyCredential,
|
||||
name?: string
|
||||
): Promise<void> {
|
||||
await apiClient.post('/accounts/mfa/webauthn/add/', {
|
||||
credential: JSON.stringify(credential),
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a WebAuthn credential
|
||||
* @param credentialId The ID of the credential to remove
|
||||
*/
|
||||
export async function removeWebAuthnCredential(credentialId: string): Promise<void> {
|
||||
await apiClient.post(`/accounts/mfa/webauthn/remove/${credentialId}/`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start WebAuthn authentication challenge
|
||||
* Used during login when user has passkey enabled
|
||||
*/
|
||||
export async function startWebAuthnAuthentication(): Promise<PublicKeyCredentialRequestOptions> {
|
||||
const response = await apiClient.get<PublicKeyCredentialRequestOptions>(
|
||||
'/accounts/mfa/webauthn/authenticate/'
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete WebAuthn authentication
|
||||
* @param credential The assertion credential from browser
|
||||
*/
|
||||
export async function completeWebAuthnAuthentication(
|
||||
credential: PublicKeyCredential
|
||||
): Promise<AuthResponse> {
|
||||
const response = await apiClient.post<AuthResponse>(
|
||||
'/accounts/mfa/webauthn/authenticate/',
|
||||
{
|
||||
credential: JSON.stringify(credential),
|
||||
}
|
||||
);
|
||||
|
||||
// Store tokens after successful WebAuthn authentication
|
||||
tokenStorage.setAccessToken(response.data.access);
|
||||
tokenStorage.setRefreshToken(response.data.refresh);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// Export all functions as a service object for convenience
|
||||
export const mfaService = {
|
||||
setupTOTP,
|
||||
confirmTOTP,
|
||||
disableTOTP,
|
||||
verifyTOTP,
|
||||
challengeMFA,
|
||||
generateBackupCodes,
|
||||
useBackupCode,
|
||||
removeMFA,
|
||||
// WebAuthn/Passkey methods
|
||||
getWebAuthnCredentials,
|
||||
startWebAuthnRegistration,
|
||||
completeWebAuthnRegistration,
|
||||
removeWebAuthnCredential,
|
||||
startWebAuthnAuthentication,
|
||||
completeWebAuthnAuthentication,
|
||||
};
|
||||
Reference in New Issue
Block a user