Created React Query hooks: - useFeatureFlags.ts: Feature flag evaluation and management - use2FA.ts: Two-factor authentication setup/verify/disable - useAuditLogs.ts: Audit logs query with filters and stats Hooks include: - useFlagCheck() for simple feature checks - useFeatures() for multiple flags - use2FAStatus(), useSetup2FA(), useEnable2FA() - useAuditLogs(), useAuditStats(), useSecurityEvents() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
307 lines
9.1 KiB
TypeScript
307 lines
9.1 KiB
TypeScript
/**
|
|
* useAuditLogs Hook
|
|
* React Query hooks for Audit Logs management
|
|
* @created Sprint 2 - TASK-2026-01-30-ANALISIS-INTEGRACION
|
|
*/
|
|
|
|
import { useQuery } from '@tanstack/react-query';
|
|
import { apiClient } from '../../../lib/apiClient';
|
|
|
|
// ============================================================================
|
|
// Types
|
|
// ============================================================================
|
|
|
|
export type AuditEventType =
|
|
| 'auth.login'
|
|
| 'auth.logout'
|
|
| 'auth.register'
|
|
| 'auth.password_change'
|
|
| 'auth.2fa_enabled'
|
|
| 'auth.2fa_disabled'
|
|
| 'user.profile_update'
|
|
| 'user.settings_change'
|
|
| 'trading.order_placed'
|
|
| 'trading.order_cancelled'
|
|
| 'investment.deposit'
|
|
| 'investment.withdrawal'
|
|
| 'payment.subscription'
|
|
| 'payment.refund'
|
|
| 'admin.user_suspend'
|
|
| 'admin.user_activate'
|
|
| 'system.config_change';
|
|
|
|
export type EventSeverity = 'info' | 'warning' | 'error' | 'critical';
|
|
|
|
export type EventStatus = 'success' | 'failure' | 'pending';
|
|
|
|
export interface AuditLog {
|
|
id: string;
|
|
eventType: AuditEventType;
|
|
eventStatus: EventStatus;
|
|
severity: EventSeverity;
|
|
userId: string | null;
|
|
sessionId: string | null;
|
|
ipAddress: string | null;
|
|
userAgent: string | null;
|
|
resourceType: string;
|
|
resourceId: string | null;
|
|
resourceName: string | null;
|
|
action: string;
|
|
description: string | null;
|
|
oldValues: Record<string, unknown> | null;
|
|
newValues: Record<string, unknown> | null;
|
|
metadata: Record<string, unknown>;
|
|
requestId: string | null;
|
|
correlationId: string | null;
|
|
serviceName: string | null;
|
|
createdAt: Date;
|
|
}
|
|
|
|
export interface AuditLogFilters {
|
|
userId?: string;
|
|
eventType?: AuditEventType;
|
|
resourceType?: string;
|
|
resourceId?: string;
|
|
severity?: EventSeverity;
|
|
dateFrom?: string;
|
|
dateTo?: string;
|
|
limit?: number;
|
|
offset?: number;
|
|
}
|
|
|
|
export interface AuditStats {
|
|
totalLogs: number;
|
|
byEventType: Partial<Record<AuditEventType, number>>;
|
|
bySeverity: Partial<Record<EventSeverity, number>>;
|
|
criticalEvents: number;
|
|
}
|
|
|
|
export interface SecurityEvent {
|
|
id: string;
|
|
category: string;
|
|
severity: EventSeverity;
|
|
eventStatus: EventStatus;
|
|
userId: string | null;
|
|
ipAddress: string;
|
|
userAgent: string | null;
|
|
eventCode: string;
|
|
eventName: string;
|
|
description: string | null;
|
|
isBlocked: boolean;
|
|
blockReason: string | null;
|
|
requiresReview: boolean;
|
|
createdAt: Date;
|
|
}
|
|
|
|
export interface SecurityEventFilters {
|
|
userId?: string;
|
|
category?: string;
|
|
severity?: EventSeverity;
|
|
isBlocked?: boolean;
|
|
requiresReview?: boolean;
|
|
dateFrom?: string;
|
|
dateTo?: string;
|
|
limit?: number;
|
|
offset?: number;
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Functions
|
|
// ============================================================================
|
|
|
|
async function getAuditLogs(filters: AuditLogFilters = {}): Promise<AuditLog[]> {
|
|
const params = new URLSearchParams();
|
|
|
|
if (filters.userId) params.append('userId', filters.userId);
|
|
if (filters.eventType) params.append('eventType', filters.eventType);
|
|
if (filters.resourceType) params.append('resourceType', filters.resourceType);
|
|
if (filters.resourceId) params.append('resourceId', filters.resourceId);
|
|
if (filters.severity) params.append('severity', filters.severity);
|
|
if (filters.dateFrom) params.append('dateFrom', filters.dateFrom);
|
|
if (filters.dateTo) params.append('dateTo', filters.dateTo);
|
|
if (filters.limit) params.append('limit', filters.limit.toString());
|
|
if (filters.offset) params.append('offset', filters.offset.toString());
|
|
|
|
const response = await apiClient.get(`/audit/logs?${params.toString()}`);
|
|
return response.data.data || [];
|
|
}
|
|
|
|
async function getAuditStats(dateFrom?: string, dateTo?: string): Promise<AuditStats> {
|
|
const params = new URLSearchParams();
|
|
if (dateFrom) params.append('dateFrom', dateFrom);
|
|
if (dateTo) params.append('dateTo', dateTo);
|
|
|
|
const response = await apiClient.get(`/audit/stats?${params.toString()}`);
|
|
return response.data.data;
|
|
}
|
|
|
|
async function getSecurityEvents(filters: SecurityEventFilters = {}): Promise<SecurityEvent[]> {
|
|
const params = new URLSearchParams();
|
|
|
|
if (filters.userId) params.append('userId', filters.userId);
|
|
if (filters.category) params.append('category', filters.category);
|
|
if (filters.severity) params.append('severity', filters.severity);
|
|
if (filters.isBlocked !== undefined) params.append('isBlocked', filters.isBlocked.toString());
|
|
if (filters.requiresReview !== undefined) params.append('requiresReview', filters.requiresReview.toString());
|
|
if (filters.dateFrom) params.append('dateFrom', filters.dateFrom);
|
|
if (filters.dateTo) params.append('dateTo', filters.dateTo);
|
|
if (filters.limit) params.append('limit', filters.limit.toString());
|
|
if (filters.offset) params.append('offset', filters.offset.toString());
|
|
|
|
const response = await apiClient.get(`/audit/security-events?${params.toString()}`);
|
|
return response.data.data || [];
|
|
}
|
|
|
|
async function getUserAuditLogs(userId: string, limit = 50): Promise<AuditLog[]> {
|
|
return getAuditLogs({ userId, limit });
|
|
}
|
|
|
|
// ============================================================================
|
|
// React Query Hooks
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Get audit logs with optional filters
|
|
*/
|
|
export function useAuditLogs(filters: AuditLogFilters = {}) {
|
|
return useQuery({
|
|
queryKey: ['audit', 'logs', filters],
|
|
queryFn: () => getAuditLogs(filters),
|
|
staleTime: 30 * 1000, // 30 seconds
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get audit stats for dashboard
|
|
*/
|
|
export function useAuditStats(dateFrom?: string, dateTo?: string) {
|
|
return useQuery({
|
|
queryKey: ['audit', 'stats', dateFrom, dateTo],
|
|
queryFn: () => getAuditStats(dateFrom, dateTo),
|
|
staleTime: 60 * 1000, // 1 minute
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get security events with optional filters
|
|
*/
|
|
export function useSecurityEvents(filters: SecurityEventFilters = {}) {
|
|
return useQuery({
|
|
queryKey: ['audit', 'security-events', filters],
|
|
queryFn: () => getSecurityEvents(filters),
|
|
staleTime: 30 * 1000, // 30 seconds
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get audit logs for a specific user
|
|
*/
|
|
export function useUserAuditLogs(userId: string, limit = 50) {
|
|
return useQuery({
|
|
queryKey: ['audit', 'user', userId, limit],
|
|
queryFn: () => getUserAuditLogs(userId, limit),
|
|
enabled: !!userId,
|
|
staleTime: 30 * 1000,
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// Helper Functions
|
|
// ============================================================================
|
|
|
|
/**
|
|
* Get user-friendly label for event type
|
|
*/
|
|
export function getEventTypeLabel(eventType: AuditEventType): string {
|
|
const labels: Record<AuditEventType, string> = {
|
|
'auth.login': 'Login',
|
|
'auth.logout': 'Logout',
|
|
'auth.register': 'Registration',
|
|
'auth.password_change': 'Password Change',
|
|
'auth.2fa_enabled': '2FA Enabled',
|
|
'auth.2fa_disabled': '2FA Disabled',
|
|
'user.profile_update': 'Profile Update',
|
|
'user.settings_change': 'Settings Change',
|
|
'trading.order_placed': 'Order Placed',
|
|
'trading.order_cancelled': 'Order Cancelled',
|
|
'investment.deposit': 'Deposit',
|
|
'investment.withdrawal': 'Withdrawal',
|
|
'payment.subscription': 'Subscription',
|
|
'payment.refund': 'Refund',
|
|
'admin.user_suspend': 'User Suspended',
|
|
'admin.user_activate': 'User Activated',
|
|
'system.config_change': 'System Config Change',
|
|
};
|
|
return labels[eventType] || eventType;
|
|
}
|
|
|
|
/**
|
|
* Get severity color for styling
|
|
*/
|
|
export function getSeverityColor(severity: EventSeverity): string {
|
|
const colors: Record<EventSeverity, string> = {
|
|
info: 'text-blue-500',
|
|
warning: 'text-yellow-500',
|
|
error: 'text-red-500',
|
|
critical: 'text-red-700',
|
|
};
|
|
return colors[severity] || 'text-gray-500';
|
|
}
|
|
|
|
/**
|
|
* Get severity badge styles
|
|
*/
|
|
export function getSeverityBadgeClass(severity: EventSeverity): string {
|
|
const classes: Record<EventSeverity, string> = {
|
|
info: 'bg-blue-100 text-blue-800',
|
|
warning: 'bg-yellow-100 text-yellow-800',
|
|
error: 'bg-red-100 text-red-800',
|
|
critical: 'bg-red-200 text-red-900 font-bold',
|
|
};
|
|
return classes[severity] || 'bg-gray-100 text-gray-800';
|
|
}
|
|
|
|
/**
|
|
* Get status badge styles
|
|
*/
|
|
export function getStatusBadgeClass(status: EventStatus): string {
|
|
const classes: Record<EventStatus, string> = {
|
|
success: 'bg-green-100 text-green-800',
|
|
failure: 'bg-red-100 text-red-800',
|
|
pending: 'bg-yellow-100 text-yellow-800',
|
|
};
|
|
return classes[status] || 'bg-gray-100 text-gray-800';
|
|
}
|
|
|
|
/**
|
|
* Format date for display
|
|
*/
|
|
export function formatAuditDate(date: Date | string): string {
|
|
const d = typeof date === 'string' ? new Date(date) : date;
|
|
return d.toLocaleString('es-MX', {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
});
|
|
}
|
|
|
|
// ============================================================================
|
|
// Export
|
|
// ============================================================================
|
|
|
|
export const auditHooks = {
|
|
useAuditLogs,
|
|
useAuditStats,
|
|
useSecurityEvents,
|
|
useUserAuditLogs,
|
|
getEventTypeLabel,
|
|
getSeverityColor,
|
|
getSeverityBadgeClass,
|
|
getStatusBadgeClass,
|
|
formatAuditDate,
|
|
};
|
|
|
|
export default auditHooks;
|