mirror of
https://github.com/kjanat/livedash-node.git
synced 2026-01-16 19:32:08 +01:00
fix: resolve all Biome linting errors and Prettier formatting issues
- Reduce cognitive complexity in lib/api/handler.ts (23 → 15) - Reduce cognitive complexity in lib/config/provider.ts (38 → 15) - Fix TypeScript any type violations in multiple files - Remove unused variable in lib/batchSchedulerOptimized.ts - Add prettier-ignore comments to documentation with intentional syntax errors - Resolve Prettier/Biome formatting conflicts with targeted ignores - Create .prettierignore for build artifacts and dependencies All linting checks now pass and build completes successfully (47/47 pages).
This commit is contained in:
@ -8,10 +8,10 @@ The Admin Audit Logs API provides secure access to security audit trails for adm
|
||||
|
||||
## Authentication & Authorization
|
||||
|
||||
- **Authentication**: NextAuth.js session required
|
||||
- **Authorization**: ADMIN role required for all endpoints
|
||||
- **Rate-Limiting**: Integrated with existing authentication rate-limiting system
|
||||
- **Audit Trail**: All API access is logged for security monitoring
|
||||
- **Authentication**: NextAuth.js session required
|
||||
- **Authorization**: ADMIN role required for all endpoints
|
||||
- **Rate-Limiting**: Integrated with existing authentication rate-limiting system
|
||||
- **Audit Trail**: All API access is logged for security monitoring
|
||||
|
||||
## API Endpoints
|
||||
|
||||
@ -25,28 +25,31 @@ GET /api/admin/audit-logs
|
||||
|
||||
#### Query Parameters
|
||||
|
||||
| Parameter | Type | Description | Default | Example |
|
||||
|-----------|------|-------------|---------|---------|
|
||||
| `page` | number | Page number (1-based) | 1 | `?page=2` |
|
||||
| `limit` | number | Records per page (max 100) | 50 | `?limit=25` |
|
||||
| `eventType` | string | Filter by event type | - | `?eventType=login_attempt` |
|
||||
| `outcome` | string | Filter by outcome | - | `?outcome=FAILURE` |
|
||||
| `severity` | string | Filter by severity level | - | `?severity=HIGH` |
|
||||
| `userId` | string | Filter by specific user ID | - | `?userId=user-123` |
|
||||
| `startDate` | string | Filter from date (ISO 8601) | - | `?startDate=2024-01-01T00:00:00Z` |
|
||||
| `endDate` | string | Filter to date (ISO 8601) | - | `?endDate=2024-01-02T00:00:00Z` |
|
||||
| Parameter | Type | Description | Default | Example |
|
||||
| ----------- | ------ | --------------------------- | ------- | --------------------------------- |
|
||||
| `page` | number | Page number (1-based) | 1 | `?page=2` |
|
||||
| `limit` | number | Records per page (max 100) | 50 | `?limit=25` |
|
||||
| `eventType` | string | Filter by event type | - | `?eventType=login_attempt` |
|
||||
| `outcome` | string | Filter by outcome | - | `?outcome=FAILURE` |
|
||||
| `severity` | string | Filter by severity level | - | `?severity=HIGH` |
|
||||
| `userId` | string | Filter by specific user ID | - | `?userId=user-123` |
|
||||
| `startDate` | string | Filter from date (ISO 8601) | - | `?startDate=2024-01-01T00:00:00Z` |
|
||||
| `endDate` | string | Filter to date (ISO 8601) | - | `?endDate=2024-01-02T00:00:00Z` |
|
||||
|
||||
#### Example Request
|
||||
|
||||
```javascript
|
||||
const response = await fetch('/api/admin/audit-logs?' + new URLSearchParams({
|
||||
page: '1',
|
||||
limit: '25',
|
||||
eventType: 'login_attempt',
|
||||
outcome: 'FAILURE',
|
||||
startDate: '2024-01-01T00:00:00Z',
|
||||
endDate: '2024-01-02T00:00:00Z'
|
||||
}));
|
||||
const response = await fetch(
|
||||
"/api/admin/audit-logs?" +
|
||||
new URLSearchParams({
|
||||
page: "1",
|
||||
limit: "25",
|
||||
eventType: "login_attempt",
|
||||
outcome: "FAILURE",
|
||||
startDate: "2024-01-01T00:00:00Z",
|
||||
endDate: "2024-01-02T00:00:00Z",
|
||||
})
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
```
|
||||
@ -96,20 +99,27 @@ const data = await response.json();
|
||||
|
||||
#### Error Responses
|
||||
|
||||
**Unauthorized (401)**
|
||||
|
||||
```json
|
||||
// Unauthorized (401)
|
||||
{
|
||||
"success": false,
|
||||
"error": "Unauthorized"
|
||||
}
|
||||
```
|
||||
|
||||
// Insufficient permissions (403)
|
||||
**Insufficient permissions (403)**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Insufficient permissions"
|
||||
}
|
||||
```
|
||||
|
||||
// Server error (500)
|
||||
**Server error (500)**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Internal server error"
|
||||
@ -134,51 +144,52 @@ POST /api/admin/audit-logs/retention
|
||||
}
|
||||
```
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
**Note**: `action` field accepts one of: `"cleanup"`, `"configure"`, or `"status"`
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `action` | string | Yes | Action to perform: `cleanup`, `configure`, or `status` |
|
||||
| `retentionDays` | number | No | Retention period in days (for configure action) |
|
||||
| `dryRun` | boolean | No | Preview changes without executing (for cleanup) |
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------------- | ------- | -------- | ------------------------------------------------------ |
|
||||
| `action` | string | Yes | Action to perform: `cleanup`, `configure`, or `status` |
|
||||
| `retentionDays` | number | No | Retention period in days (for configure action) |
|
||||
| `dryRun` | boolean | No | Preview changes without executing (for cleanup) |
|
||||
|
||||
#### Example Requests
|
||||
|
||||
**Check retention status:**
|
||||
|
||||
```javascript
|
||||
const response = await fetch('/api/admin/audit-logs/retention', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action: 'status' })
|
||||
const response = await fetch("/api/admin/audit-logs/retention", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ action: "status" }),
|
||||
});
|
||||
```
|
||||
|
||||
**Configure retention policy:**
|
||||
|
||||
```javascript
|
||||
const response = await fetch('/api/admin/audit-logs/retention', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
const response = await fetch("/api/admin/audit-logs/retention", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: 'configure',
|
||||
retentionDays: 365
|
||||
})
|
||||
action: "configure",
|
||||
retentionDays: 365,
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
**Cleanup old logs (dry run):**
|
||||
|
||||
```javascript
|
||||
const response = await fetch('/api/admin/audit-logs/retention', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
const response = await fetch("/api/admin/audit-logs/retention", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: 'cleanup',
|
||||
dryRun: true
|
||||
})
|
||||
action: "cleanup",
|
||||
dryRun: true,
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
@ -186,57 +197,57 @@ const response = await fetch('/api/admin/audit-logs/retention', {
|
||||
|
||||
### Access Control
|
||||
|
||||
- **Role-based Access**: Only ADMIN users can access audit logs
|
||||
- **Company Isolation**: Users only see logs for their company
|
||||
- **Session Validation**: Active NextAuth session required
|
||||
- **Role-based Access**: Only ADMIN users can access audit logs
|
||||
- **Company Isolation**: Users only see logs for their company
|
||||
- **Session Validation**: Active NextAuth session required
|
||||
|
||||
### Audit Trail
|
||||
|
||||
- **Access Logging**: All audit log access is recorded
|
||||
- **Metadata Tracking**: Request parameters and results are logged
|
||||
- **IP Tracking**: Client IP addresses are recorded for all requests
|
||||
- **Access Logging**: All audit log access is recorded
|
||||
- **Metadata Tracking**: Request parameters and results are logged
|
||||
- **IP Tracking**: Client IP addresses are recorded for all requests
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
- **Integrated Protection**: Uses existing authentication rate-limiting
|
||||
- **Abuse Prevention**: Protects against excessive API usage
|
||||
- **Error Tracking**: Failed attempts are monitored
|
||||
- **Integrated Protection**: Uses existing authentication rate-limiting
|
||||
- **Abuse Prevention**: Protects against excessive API usage
|
||||
- **Error Tracking**: Failed attempts are monitored
|
||||
|
||||
## Event Types
|
||||
|
||||
Common event types available for filtering:
|
||||
|
||||
| Event Type | Description |
|
||||
|------------|-------------|
|
||||
| `login_attempt` | User login attempts |
|
||||
| `login_success` | Successful logins |
|
||||
| `logout` | User logouts |
|
||||
| `password_reset_request` | Password reset requests |
|
||||
| Event Type | Description |
|
||||
| ------------------------- | -------------------------- |
|
||||
| `login_attempt` | User login attempts |
|
||||
| `login_success` | Successful logins |
|
||||
| `logout` | User logouts |
|
||||
| `password_reset_request` | Password reset requests |
|
||||
| `password_reset_complete` | Password reset completions |
|
||||
| `user_creation` | New user registrations |
|
||||
| `user_modification` | User profile changes |
|
||||
| `admin_action` | Administrative actions |
|
||||
| `data_export` | Data export activities |
|
||||
| `security_violation` | Security policy violations |
|
||||
| `user_creation` | New user registrations |
|
||||
| `user_modification` | User profile changes |
|
||||
| `admin_action` | Administrative actions |
|
||||
| `data_export` | Data export activities |
|
||||
| `security_violation` | Security policy violations |
|
||||
|
||||
## Outcome Types
|
||||
|
||||
| Outcome | Description |
|
||||
|---------|-------------|
|
||||
| `SUCCESS` | Operation completed successfully |
|
||||
| `FAILURE` | Operation failed |
|
||||
| `BLOCKED` | Operation was blocked by security policy |
|
||||
| `WARNING` | Operation completed with warnings |
|
||||
| `RATE_LIMITED` | Operation was rate limited |
|
||||
| Outcome | Description |
|
||||
| -------------- | ---------------------------------------- |
|
||||
| `SUCCESS` | Operation completed successfully |
|
||||
| `FAILURE` | Operation failed |
|
||||
| `BLOCKED` | Operation was blocked by security policy |
|
||||
| `WARNING` | Operation completed with warnings |
|
||||
| `RATE_LIMITED` | Operation was rate limited |
|
||||
|
||||
## Severity Levels
|
||||
|
||||
| Severity | Description | Use Case |
|
||||
|----------|-------------|----------|
|
||||
| `LOW` | Informational events | Normal operations |
|
||||
| `MEDIUM` | Notable events | Configuration changes |
|
||||
| `HIGH` | Security events | Failed logins, violations |
|
||||
| `CRITICAL` | Critical security events | Breaches, attacks |
|
||||
| Severity | Description | Use Case |
|
||||
| ---------- | ------------------------ | ------------------------- |
|
||||
| `LOW` | Informational events | Normal operations |
|
||||
| `MEDIUM` | Notable events | Configuration changes |
|
||||
| `HIGH` | Security events | Failed logins, violations |
|
||||
| `CRITICAL` | Critical security events | Breaches, attacks |
|
||||
|
||||
## Usage Examples
|
||||
|
||||
@ -247,16 +258,19 @@ async function getDailySecurityReport() {
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
yesterday.setHours(0, 0, 0, 0);
|
||||
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
const response = await fetch('/api/admin/audit-logs?' + new URLSearchParams({
|
||||
startDate: yesterday.toISOString(),
|
||||
endDate: today.toISOString(),
|
||||
limit: '100'
|
||||
}));
|
||||
|
||||
|
||||
const response = await fetch(
|
||||
"/api/admin/audit-logs?" +
|
||||
new URLSearchParams({
|
||||
startDate: yesterday.toISOString(),
|
||||
endDate: today.toISOString(),
|
||||
limit: "100",
|
||||
})
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
return data.data.auditLogs;
|
||||
}
|
||||
@ -268,14 +282,17 @@ async function getDailySecurityReport() {
|
||||
async function getFailedLogins(hours = 24) {
|
||||
const since = new Date();
|
||||
since.setHours(since.getHours() - hours);
|
||||
|
||||
const response = await fetch('/api/admin/audit-logs?' + new URLSearchParams({
|
||||
eventType: 'login_attempt',
|
||||
outcome: 'FAILURE',
|
||||
startDate: since.toISOString(),
|
||||
limit: '100'
|
||||
}));
|
||||
|
||||
|
||||
const response = await fetch(
|
||||
"/api/admin/audit-logs?" +
|
||||
new URLSearchParams({
|
||||
eventType: "login_attempt",
|
||||
outcome: "FAILURE",
|
||||
startDate: since.toISOString(),
|
||||
limit: "100",
|
||||
})
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
return data.data.auditLogs;
|
||||
}
|
||||
@ -287,13 +304,16 @@ async function getFailedLogins(hours = 24) {
|
||||
async function getUserActivity(userId, days = 7) {
|
||||
const since = new Date();
|
||||
since.setDate(since.getDate() - days);
|
||||
|
||||
const response = await fetch('/api/admin/audit-logs?' + new URLSearchParams({
|
||||
userId: userId,
|
||||
startDate: since.toISOString(),
|
||||
limit: '50'
|
||||
}));
|
||||
|
||||
|
||||
const response = await fetch(
|
||||
"/api/admin/audit-logs?" +
|
||||
new URLSearchParams({
|
||||
userId: userId,
|
||||
startDate: since.toISOString(),
|
||||
limit: "50",
|
||||
})
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
return data.data.auditLogs;
|
||||
}
|
||||
@ -303,21 +323,21 @@ async function getUserActivity(userId, days = 7) {
|
||||
|
||||
### Database Optimization
|
||||
|
||||
- **Indexed Queries**: All filter columns are properly indexed
|
||||
- **Pagination**: Efficient offset-based pagination with limits
|
||||
- **Time Range Filtering**: Optimized for date range queries
|
||||
- **Indexed Queries**: All filter columns are properly indexed
|
||||
- **Pagination**: Efficient offset-based pagination with limits
|
||||
- **Time Range Filtering**: Optimized for date range queries
|
||||
|
||||
### Memory Usage
|
||||
|
||||
- **Limited Results**: Maximum 100 records per request
|
||||
- **Streaming**: Large exports use streaming for memory efficiency
|
||||
- **Connection Pooling**: Database connections are pooled
|
||||
- **Limited Results**: Maximum 100 records per request
|
||||
- **Streaming**: Large exports use streaming for memory efficiency
|
||||
- **Connection Pooling**: Database connections are pooled
|
||||
|
||||
### Caching Considerations
|
||||
|
||||
- **No Caching**: Audit logs are never cached for security reasons
|
||||
- **Fresh Data**: All queries hit the database for real-time results
|
||||
- **Read Replicas**: Consider using read replicas for heavy reporting
|
||||
- **No Caching**: Audit logs are never cached for security reasons
|
||||
- **Fresh Data**: All queries hit the database for real-time results
|
||||
- **Read Replicas**: Consider using read replicas for heavy reporting
|
||||
|
||||
## Error Handling
|
||||
|
||||
@ -325,24 +345,24 @@ async function getUserActivity(userId, days = 7) {
|
||||
|
||||
```javascript
|
||||
try {
|
||||
const response = await fetch('/api/admin/audit-logs');
|
||||
const response = await fetch("/api/admin/audit-logs");
|
||||
const data = await response.json();
|
||||
|
||||
|
||||
if (!data.success) {
|
||||
switch (response.status) {
|
||||
case 401:
|
||||
console.error('User not authenticated');
|
||||
console.error("User not authenticated");
|
||||
break;
|
||||
case 403:
|
||||
console.error('User lacks admin permissions');
|
||||
console.error("User lacks admin permissions");
|
||||
break;
|
||||
case 500:
|
||||
console.error('Server error:', data.error);
|
||||
console.error("Server error:", data.error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Network error:', error);
|
||||
console.error("Network error:", error);
|
||||
}
|
||||
```
|
||||
|
||||
@ -351,18 +371,18 @@ try {
|
||||
```javascript
|
||||
async function fetchWithRetry(url, options = {}, maxRetries = 3, retryCount = 0) {
|
||||
const response = await fetch(url, options);
|
||||
|
||||
|
||||
if (response.status === 429 && retryCount < maxRetries) {
|
||||
// Rate limited, wait with exponential backoff and retry
|
||||
const delay = Math.pow(2, retryCount) * 1000; // 1s, 2s, 4s
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
return fetchWithRetry(url, options, maxRetries, retryCount + 1);
|
||||
}
|
||||
|
||||
|
||||
if (response.status === 429) {
|
||||
throw new Error(`Rate limited after ${maxRetries} retries`);
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
}
|
||||
```
|
||||
@ -371,44 +391,44 @@ async function fetchWithRetry(url, options = {}, maxRetries = 3, retryCount = 0)
|
||||
|
||||
### Key Metrics to Monitor
|
||||
|
||||
- **Request Volume**: Track API usage patterns
|
||||
- **Error Rates**: Monitor authentication and authorization failures
|
||||
- **Query Performance**: Track slow queries and optimize
|
||||
- **Data Growth**: Monitor audit log size and plan retention
|
||||
- **Request Volume**: Track API usage patterns
|
||||
- **Error Rates**: Monitor authentication and authorization failures
|
||||
- **Query Performance**: Track slow queries and optimize
|
||||
- **Data Growth**: Monitor audit log size and plan retention
|
||||
|
||||
### Alert Conditions
|
||||
|
||||
- **High Error Rates**: >5% of requests failing
|
||||
- **Unusual Access Patterns**: Off-hours access, high-volume usage
|
||||
- **Performance Degradation**: Query times >2 seconds
|
||||
- **Security Events**: Multiple failed admin access attempts
|
||||
- **High Error Rates**: >5% of requests failing
|
||||
- **Unusual Access Patterns**: Off-hours access, high-volume usage
|
||||
- **Performance Degradation**: Query times >2 seconds
|
||||
- **Security Events**: Multiple failed admin access attempts
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Security
|
||||
|
||||
- Always validate user permissions before displaying UI
|
||||
- Log all administrative access to audit logs
|
||||
- Use HTTPS in production environments
|
||||
- Implement proper error handling to avoid information leakage
|
||||
- Always validate user permissions before displaying UI
|
||||
- Log all administrative access to audit logs
|
||||
- Use HTTPS in production environments
|
||||
- Implement proper error handling to avoid information leakage
|
||||
|
||||
### Performance
|
||||
|
||||
- Use appropriate page sizes (25-50 records typical)
|
||||
- Implement client-side pagination for better UX
|
||||
- Cache results only in memory, never persist
|
||||
- Use date range filters to limit query scope
|
||||
- Use appropriate page sizes (25-50 records typical)
|
||||
- Implement client-side pagination for better UX
|
||||
- Cache results only in memory, never persist
|
||||
- Use date range filters to limit query scope
|
||||
|
||||
### User Experience
|
||||
|
||||
- Provide clear filtering options in the UI
|
||||
- Show loading states for long-running queries
|
||||
- Implement export functionality for reports
|
||||
- Provide search and sort capabilities
|
||||
- Provide clear filtering options in the UI
|
||||
- Show loading states for long-running queries
|
||||
- Implement export functionality for reports
|
||||
- Provide search and sort capabilities
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Security Audit Logging](./security-audit-logging.md)
|
||||
- [Security Monitoring](./security-monitoring.md)
|
||||
- [CSRF Protection](./CSRF_PROTECTION.md)
|
||||
- [Authentication System](../lib/auth.ts)
|
||||
- [Security Audit Logging](./security-audit-logging.md)
|
||||
- [Security Monitoring](./security-monitoring.md)
|
||||
- [CSRF Protection](./CSRF_PROTECTION.md)
|
||||
- [Authentication System](../lib/auth.ts)
|
||||
|
||||
Reference in New Issue
Block a user