Files
portal/app/resources/js/api/auth.ts
T
Дмитрий 73e64128dc phase2(2fa-setup): wizard init+confirm+disable+regenerate в SettingsView/SecurityTab
- TwoFactorSetupController (auth:sanctum): /api/2fa/{init,confirm,disable,regenerate-recovery-codes}
- init секрет в session (не в БД), QR-URL otpauth://; confirm активирует 2FA + 8 recovery codes
- disable/regenerate требуют password-confirmation
- User.casts: totp_secret => encrypted

Schema v8.7→v8.8: users.totp_secret VARCHAR(255) → TEXT (encrypted ~256 chars)
Migration fix: explicit ALTER TABLE webhook_dedup_keys ADD FK после DB::unprepared (PDO глотал FK на partitioned)
PartitionsCreateMonthsTest fix: DETACH PARTITION + DROP вместо DROP CASCADE

Frontend: SecurityTab реальная логика (setup wizard 3 шага, disable, regenerate dialogs)

- Pest +10 (101/101 за 13.37с, 364 assertions)
- Vitest 166/166
- CLAUDE.md v1.39→v1.40, реестр v1.48→v1.49, schema v8.7→v8.8

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 04:03:02 +03:00

127 lines
3.8 KiB
TypeScript

import { apiClient, ensureCsrfCookie } from './client';
/**
* API-вызовы для AuthController (см. app/Http/Controllers/Api/AuthController.php).
*
* Все методы делают `ensureCsrfCookie()` перед POST'ами — Sanctum SPA flow.
*/
export interface AuthUser {
id: number;
email: string;
first_name: string | null;
last_name: string | null;
tenant_id: number;
totp_enabled: boolean;
last_login_at: string | null;
}
export interface LoginPayload {
email: string;
password: string;
remember?: boolean;
}
export interface LoginResponse {
user: AuthUser;
requires_2fa: boolean;
}
export interface RegisterPayload {
email: string;
password: string;
accept_offer: boolean;
accept_pdn: boolean;
}
export async function login(payload: LoginPayload): Promise<LoginResponse> {
await ensureCsrfCookie();
const { data } = await apiClient.post<LoginResponse>('/api/auth/login', payload);
return data;
}
export async function register(payload: RegisterPayload): Promise<LoginResponse> {
await ensureCsrfCookie();
const { data } = await apiClient.post<LoginResponse>('/api/auth/register', payload);
return data;
}
export async function me(): Promise<AuthUser> {
const { data } = await apiClient.get<{ user: AuthUser }>('/api/auth/me');
return data.user;
}
export async function logout(): Promise<void> {
await ensureCsrfCookie();
await apiClient.post('/api/auth/logout');
}
export async function verifyTwoFactor(code: string): Promise<LoginResponse> {
await ensureCsrfCookie();
const { data } = await apiClient.post<LoginResponse>('/api/auth/2fa/verify', { code });
return data;
}
export interface RecoveryCodeResponse extends LoginResponse {
recovery_codes_remaining: number;
}
export async function useRecoveryCode(code: string): Promise<RecoveryCodeResponse> {
await ensureCsrfCookie();
const { data } = await apiClient.post<RecoveryCodeResponse>('/api/auth/2fa/recovery-use', { code });
return data;
}
export interface TwoFactorInitResponse {
secret: string;
qr_url: string;
}
export async function twoFactorInit(): Promise<TwoFactorInitResponse> {
await ensureCsrfCookie();
const { data } = await apiClient.post<TwoFactorInitResponse>('/api/2fa/init');
return data;
}
export async function twoFactorConfirm(code: string): Promise<{ recovery_codes: string[]; message: string }> {
await ensureCsrfCookie();
const { data } = await apiClient.post<{ recovery_codes: string[]; message: string }>('/api/2fa/confirm', { code });
return data;
}
export async function twoFactorDisable(password: string): Promise<{ message: string }> {
await ensureCsrfCookie();
const { data } = await apiClient.post<{ message: string }>('/api/2fa/disable', { password });
return data;
}
export async function twoFactorRegenerateRecoveryCodes(
password: string,
): Promise<{ recovery_codes: string[]; message: string }> {
await ensureCsrfCookie();
const { data } = await apiClient.post<{ recovery_codes: string[]; message: string }>(
'/api/2fa/regenerate-recovery-codes',
{ password },
);
return data;
}
export async function forgotPassword(email: string): Promise<{ message: string }> {
await ensureCsrfCookie();
const { data } = await apiClient.post<{ message: string }>('/api/auth/forgot', { email });
return data;
}
export interface ResetPasswordPayload {
token: string;
email: string;
password: string;
password_confirmation: string;
}
export async function resetPassword(payload: ResetPasswordPayload): Promise<{ message: string }> {
await ensureCsrfCookie();
const { data } = await apiClient.post<{ message: string }>('/api/auth/reset-password', payload);
return data;
}