# Phase 4: Secure Access + Anti-Cheating - Implementation Guide

## Overview
This guide documents the implementation of a comprehensive secure file access system with dynamic watermarking and an anti-cheating detection system for exam environments.

## What Was Implemented

### 1. Secure File Service

#### `app/Services/SecureFileService.php`
Service for serving files securely with watermarking:

**Image Serving:**
- Downloads original from GCS
- Applies dynamic watermark with user info
- Caches watermarked results (60 minutes)
- Serves as WebP format
- Cache key: `watermark:{path}:{user_id}:{exam_session_id}`

**Audio Serving:**
- Streams directly from GCS
- Supports range requests (for seeking)
- Proper headers: `Content-Type`, `Content-Length`, `Accept-Ranges`
- No processing needed

**Watermark Features:**
- Dynamic text: masked email + session ID + timestamp
- Semi-transparent background overlay
- White text on dark overlay
- Bottom-left positioning
- Responsive font size (12-24px based on image width)

### 2. Secure Token Service

#### `app/Services/SecureTokenService.php`
Token generation and verification:

**Token Format:**
```
Base64(Payload | HMAC-SHA256)
```

**Payload Structure:**
```json
{
  "user_id": "123",
  "exam_session_id": "session-uuid",
  "file_id": "file-uuid",
  "file_type": "image|audio",
  "expiry": 1234567890
}
```

**Security Features:**
- HMAC-SHA256 signature using APP_KEY
- Base64 encoding for transport
- Expiry validation
- Required field validation
- Timing-safe comparison (hash_equals)

### 3. Secure File Controller

#### `app/Http/Controllers/SecureFileController.php`
Handles secure file access and token generation:

**GET /exam/files/{token}** - Serve file securely
- Verifies token signature and expiry
- Validates user authentication matches token
- Checks exam session is active
- Serves watermarked image or streamed audio
- Returns 403 if invalid or expired

**POST /exam/files/token** - Generate access token
- Requires authentication
- Validates exam session is active
- Generates token with 60-minute expiry
- Returns token and expiry time

### 4. Cheating Detection System

#### `app/Http/Controllers/CheatingDetectionController.php`
Handles anti-cheating event logging:

**POST /exam/cheat-event** - Log cheating event
- Validates event type (tab_switch, blur, devtools)
- Records IP address and user agent
- Stores metadata (timestamp, URL)
- Returns warning message to user
- Logs to `cheating_logs` table

**GET /exam/cheat-logs** - Get cheating logs
- Returns logs for current user
- Filters by exam session
- Includes statistics by type
- Only accessible to user's own logs

#### `app/Models/CheatingLog.php`
Eloquent model for cheating logs:

**Model Features:**
- Fillable fields for mass assignment
- JSON casting for metadata
- User relationship
- Query scopes (byType, byExamSession, byUser, recent)

#### `database/migrations/2024_01_15_000001_create_cheating_logs_table.php`
Database schema for cheating logs:

**Table Structure:**
- `id` - Primary key
- `user_id` - User who triggered event
- `exam_session_id` - Associated exam session
- `type` - Event type (enum: tab_switch, blur, devtools)
- `ip_address` - IP address (IPv4/IPv6)
- `user_agent` - Browser user agent
- `metadata` - JSON field for additional data
- `created_at`, `updated_at` - Timestamps

**Indexes:**
- user_id, exam_session_id, type, created_at

### 5. Client-Side Anti-Cheating

#### `public/js/anti-cheating.js`
JavaScript class for client-side detection:

**Detection Methods:**

1. **Tab Switch Detection**
   - Uses `visibilitychange` event
   - Triggers when user switches tabs
   - Detects when document becomes hidden

2. **Window Blur Detection**
   - Uses `blur` event
   - Triggers when window loses focus
   - Detects when user clicks outside

3. **DevTools Detection**
   - **Method 1:** Debugger timing detection
   - **Method 2:** Window dimension changes
   - **Method 3:** Keyboard shortcuts (F12, Ctrl+Shift+I/J/C)

**Features:**
- 5-second cooldown between events
- Automatic logging to server
- Visual warning to user
- CSRF token support
- Configurable endpoint and session ID
- Cleanup method for proper destruction

## API Documentation

### POST /exam/files/token
Generate secure access token for file.

**Request Headers:**
```
Content-Type: application/json
Authorization: Bearer {token}
X-CSRF-TOKEN: {csrf_token}
```

**Request Body:**
```json
{
  "file_id": "file-uuid",
  "file_type": "image|audio",
  "exam_session_id": "session-uuid"
}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Token berhasil dibuat",
  "data": {
    "token": "eyJ1c2VyX2lkIjoiMTIzI...",
    "expires_in": 3600
  }
}
```

**Error Response (403):**
```json
{
  "success": false,
  "message": "Sesi ujian tidak aktif atau telah berakhir"
}
```

### GET /exam/files/{token}
Serve file securely with watermark (if image) or streaming (if audio).

**Response (Image):**
```
Content-Type: image/webp
Cache-Control: private, max-age=3600

[Watermarked WebP Image]
```

**Response (Audio):**
```
Content-Type: audio/mpeg
Content-Length: 1234567
Accept-Ranges: bytes
Cache-Control: private, max-age=3600

[Audio Stream]
```

**Error Response (403):**
```json
{
  "success": false,
  "message": "Token tidak valid atau telah kadaluarsa"
}
```

### POST /exam/cheat-event
Log cheating event to server.

**Request Headers:**
```
Content-Type: application/json
X-CSRF-TOKEN: {csrf_token}
```

**Request Body:**
```json
{
  "type": "tab_switch|blur|devtools",
  "exam_session_id": "session-uuid"
}
```

**Success Response (200):**
```json
{
  "success": true,
  "warning": true,
  "message": "Jangan curang ya 🙂 aktivitas kamu terdeteksi",
  "data": {
    "type": "tab_switch",
    "timestamp": "2024-01-15T12:00:00+07:00"
  }
}
```

### GET /exam/cheat-logs?exam_session_id={id}
Get cheating logs for current user and exam session.

**Success Response (200):**
```json
{
  "success": true,
  "message": "Log curang berhasil diambil",
  "data": {
    "logs": [
      {
        "id": 1,
        "user_id": 123,
        "exam_session_id": "session-uuid",
        "type": "tab_switch",
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0...",
        "metadata": {
          "timestamp": "2024-01-15T12:00:00+07:00",
          "url": "https://..."
        },
        "created_at": "2024-01-15T12:00:00+07:00"
      }
    ],
    "statistics": {
      "total": 10,
      "by_type": {
        "tab_switch": 5,
        "blur": 3,
        "devtools": 2
      }
    }
  }
}
```

## Client-Side Implementation

### 1. Include Anti-Cheat Script
```html
<script src="/js/anti-cheating.js"></script>
```

### 2. Initialize Anti-Cheat Detector
```javascript
const antiCheat = new AntiCheatDetector({
    examSessionId: 'your-exam-session-id',
    cheatEventEndpoint: '/exam/cheat-event',
    enabled: true,
    cooldownMs: 5000
});
```

### 3. Get Access Token for File
```javascript
async function getFileToken(fileId, fileType, examSessionId) {
    const response = await fetch('/exam/files/token', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-TOKEN': getCsrfToken(),
        },
        body: JSON.stringify({
            file_id: fileId,
            file_type: fileType,
            exam_session_id: examSessionId,
        }),
    });
    
    const data = await response.json();
    
    if (!data.success) {
        throw new Error(data.message);
    }
    
    return data.data.token;
}
```

### 4. Load File with Secure URL
```javascript
async function loadSecureFile(fileId, fileType, examSessionId) {
    try {
        // Get token
        const token = await getFileToken(fileId, fileType, examSessionId);
        
        // Load file
        const fileUrl = `/exam/files/${token}`;
        
        if (fileType === 'image') {
            const img = new Image();
            img.src = fileUrl;
            document.body.appendChild(img);
        } else if (fileType === 'audio') {
            const audio = new Audio(fileUrl);
            audio.play();
        }
    } catch (error) {
        console.error('Failed to load file:', error);
    }
}
```

### 5. Complete Exam Page Setup
```html
<!DOCTYPE html>
<html>
<head>
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>CBT Exam</title>
</head>
<body>
    <h1>CBT Exam</h1>
    <div id="exam-content">
        <!-- Exam content here -->
    </div>
    
    <!-- Anti-Cheat Detection -->
    <script src="/js/anti-cheating.js"></script>
    <script>
        const examSessionId = '{{ $examSessionId }}';
        
        // Initialize anti-cheat
        const antiCheat = new AntiCheatDetector({
            examSessionId: examSessionId,
            enabled: true
        });
        
        // Example: Load image
        async function loadQuestionImage(fileId) {
            const token = await getFileToken(fileId, 'image', examSessionId);
            const img = document.createElement('img');
            img.src = `/exam/files/${token}`;
            document.getElementById('exam-content').appendChild(img);
        }
        
        // Example: Load audio
        async function loadQuestionAudio(fileId) {
            const token = await getFileToken(fileId, 'audio', examSessionId);
            const audio = document.createElement('audio');
            audio.src = `/exam/files/${token}`;
            audio.controls = true;
            document.getElementById('exam-content').appendChild(audio);
        }
    </script>
</body>
</html>
```

## Watermark Implementation

### Watermark Text Format
```
ID: abe***@example.com | Session: session-uuid | 15/01/2024 12:00
```

### Watermark Styling
- **Font:** Arial
- **Color:** White (RGB 255, 255, 255)
- **Background:** Semi-transparent black (30% opacity)
- **Position:** Bottom-left, 15px padding
- **Font Size:** 12-24px (responsive)
- **Overlay Size:** 60% width, 10% height

### Cache Strategy
- **Cache Key:** `watermark:{path}:{user_id}:{exam_session_id}`
- **TTL:** 60 minutes
- **Driver:** Redis (configured in Phase 3)
- **Benefit:** Avoids repeated watermarking of same image

## Security Features

### 1. Token Security
- ✅ HMAC-SHA256 signature
- ✅ Expiry time validation
- ✅ Timing-safe comparison
- ✅ Base64 encoding
- ✅ Required field validation

### 2. File Access Security
- ✅ Token required for all file access
- ✅ User authentication verification
- ✅ Exam session validation
- ✅ Tenant isolation
- ✅ No public URLs

### 3. Watermark Security
- ✅ Dynamic user-specific watermarks
- ✅ Timestamp prevents screenshots reuse
- ✅ Email masking for privacy
- ✅ Prevents image sharing

### 4. Anti-Cheating Detection
- ✅ Multiple detection methods
- ✅ Server-side logging
- ✅ IP address tracking
- ✅ User agent logging
- ✅ Cooldown prevents spam

### 5. Audio Security
- ✅ Direct streaming from GCS
- ✅ No caching on client
- ✅ Private cache control
- ✅ Range request support

## Database Schema

### cheating_logs Table
```sql
CREATE TABLE cheating_logs (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    user_id BIGINT UNSIGNED NOT NULL,
    exam_session_id VARCHAR(255) NOT NULL,
    type ENUM('tab_switch', 'blur', 'devtools') NOT NULL,
    ip_address VARCHAR(45) NULL,
    user_agent TEXT NULL,
    metadata JSON NULL,
    created_at TIMESTAMP NULL,
    updated_at TIMESTAMP NULL,
    
    INDEX idx_user_id (user_id),
    INDEX idx_exam_session_id (exam_session_id),
    INDEX idx_type (type),
    INDEX idx_created_at (created_at)
);
```

## Installation & Setup

### 1. Run Migration
```bash
php artisan migrate
```

### 2. Update Exam Session Model (Required)
Update `SecureFileController.php` to implement `validateExamSession()`:

```php
protected function validateExamSession(string $examSessionId): bool
{
    return ExamSession::where('id', $examSessionId)
        ->where('status', 'active')
        ->where('start_time', '<=', now())
        ->where('end_time', '>', now())
        ->exists();
}
```

### 3. Update Audio File Path (Required)
Update `SecureFileController.php` to implement `getAudioFilePath()`:

```php
protected function getAudioFilePath(string $fileId, int $tenantId): string
{
    $audioFile = AudioFile::where('id', $fileId)->first();
    return "tenants/{$tenantId}/audio/{$fileId}.{$audioFile->extension}";
}
```

### 4. Install Font for Watermark
```bash
# Create fonts directory
mkdir -p public/fonts

# Copy Arial or use system font
# Or download free font like Roboto
wget -O public/fonts/arial.ttf https://github.com/liberationfonts/liberation-fonts/raw/master/LiberationSans-Regular.ttf
```

### 5. Update Cache Configuration
Ensure Redis is configured for watermark caching (from Phase 3):
```env
CACHE_DRIVER=redis
```

## Testing

### Test Secure File Access

#### 1. Generate Token
```bash
curl -X POST http://localhost:8000/exam/files/token \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "file_id": "test-file-id",
    "file_type": "image",
    "exam_session_id": "test-session-id"
  }'
```

#### 2. Access File with Token
```bash
# Image
curl http://localhost:8000/exam/files/{token} --output image.webp

# Audio
curl http://localhost:8000/exam/files/{token} --output audio.mp3
```

### Test Anti-Cheating Detection

#### 1. Open Browser Console
```javascript
// Trigger tab switch
document.hidden = true;

// Manually trigger cheat event
await antiCheat.logCheatEvent('tab_switch');
```

#### 2. Check Logs
```bash
# Query database
php artisan tinker
>>> \App\Models\CheatingLog::latest()->get();
```

### Test Watermark
```bash
# Generate token and access file
# Check if watermark is applied
# Verify cache is working
redis-cli
> KEYS watermark:*
```

## Monitoring & Logging

### Log Locations

**Laravel Logs:** `storage/logs/laravel.log`
- Token generation/verification
- File serving events
- Watermark caching
- Cheat event logging
- Errors and warnings

**Database Logs:** `cheating_logs` table
- All cheating events
- IP addresses
- User agents
- Timestamps

### Monitoring Queries

#### View Recent Cheating Events
```sql
SELECT 
    user_id,
    exam_session_id,
    type,
    COUNT(*) as count,
    MAX(created_at) as last_event
FROM cheating_logs
WHERE created_at >= NOW() - INTERVAL 24 HOUR
GROUP BY user_id, exam_session_id, type
ORDER BY count DESC;
```

#### View Users with High Suspicion
```sql
SELECT 
    user_id,
    COUNT(*) as total_events,
    SUM(CASE WHEN type = 'devtools' THEN 1 ELSE 0 END) as devtools_count,
    SUM(CASE WHEN type = 'tab_switch' THEN 1 ELSE 0 END) as tab_switch_count
FROM cheating_logs
WHERE created_at >= NOW() - INTERVAL 24 HOUR
GROUP BY user_id
HAVING total_events > 10
ORDER BY total_events DESC;
```

## Troubleshooting

### Issue: "Token not valid or expired"
**Solutions:**
1. Check APP_KEY in `.env` is consistent
2. Verify token is not older than 60 minutes
3. Ensure user is authenticated
4. Check exam session is active

### Issue: Watermark not appearing
**Solutions:**
1. Verify font file exists at `public/fonts/arial.ttf`
2. Check Intervention Image is installed
3. Clear cache: `php artisan cache:clear`
4. Check GD extension is enabled: `php -m | grep gd`

### Issue: Audio not streaming
**Solutions:**
1. Verify audio file path is correct
2. Check file exists in GCS
3. Ensure AudioFile model has extension field
4. Verify GCS credentials

### Issue: Anti-cheat not detecting events
**Solutions:**
1. Check browser console for JavaScript errors
2. Verify examSessionId is set
3. Ensure endpoint URL is correct
4. Check CSRF token is present
5. Verify detector is initialized

### Issue: Too many cheat events logged
**Solutions:**
1. Adjust cooldown in `AntiCheatDetector`
2. Reduce detection sensitivity
3. Add debounce to blur events
4. Filter legitimate events server-side

## Best Practices

### Development
- ✅ Test with different browsers
- ✅ Verify watermark readability
- ✅ Test with various image sizes
- ✅ Check audio streaming quality
- ✅ Monitor cache hit rates

### Production
- ✅ Monitor cache memory usage
- ✅ Set up alerts for high cheating events
- ✅ Regularly review cheating logs
- ✅ Update detection methods periodically
- ✅ Educate users about anti-cheating

### Security
- ✅ Rotate APP_KEY regularly
- ✅ Keep dependencies updated
- ✅ Monitor for suspicious patterns
- ✅ Implement rate limiting
- ✅ Use HTTPS in production

## Performance Optimization

### Cache Optimization
```php
// Increase watermark cache TTL
Cache::put($cacheKey, $watermarkedContent, now()->addHours(2));
```

### Image Optimization
```php
// Compress watermark further
$image->toWebp(70); // Lower quality
```

### Database Optimization
```sql
-- Add composite index
CREATE INDEX idx_user_session_type ON cheating_logs(user_id, exam_session_id, type);
```

## Integration with Previous Phases

### Phase 1: GCS Migration
- ✅ Uses GCS for all file storage
- ✅ Compatible with migrated path structure
- ✅ Private bucket access enforced

### Phase 2: Signed URL Upload
- ✅ Uploads go to correct directories
- ✅ Images in temp/ for processing
- ✅ Audio in tenants/ directly

### Phase 3: Image Processing
- ✅ Processed images in processed/ directory
- ✅ WebP format for watermarking
- ✅ Optimized size for faster delivery

## Next Steps After Implementation

1. **Test thoroughly**
   - Test file access with different users
   - Verify watermark appears correctly
   - Test audio streaming
   - Verify anti-cheat detection

2. **Monitor in production**
   - Track cache hit rates
   - Monitor cheating logs
   - Check for false positives
   - Review performance metrics

3. **Iterate and improve**
   - Adjust watermark visibility
   - Fine-tune detection sensitivity
   - Optimize cache TTL
   - Update detection methods

## Files Created/Modified
- `app/Services/SecureFileService.php` (new)
- `app/Services/SecureTokenService.php` (new)
- `app/Http/Controllers/SecureFileController.php` (new)
- `app/Http/Controllers/CheatingDetectionController.php` (new)
- `app/Models/CheatingLog.php` (new)
- `database/migrations/2024_01_15_000001_create_cheating_logs_table.php` (new)
- `public/js/anti-cheating.js` (new)
- `routes/web.php` (added exam routes)
- `PHASE4_SECURE_ACCESS_ANTI_CHEATING_GUIDE.md` (new)

## Summary

Phase 4 is complete! The CBT system now has:
1. ✅ Secure file access with token-based authentication
2. ✅ Dynamic image watermarking with user info
3. ✅ Cached watermark results for performance
4. ✅ Comprehensive anti-cheating detection
5. ✅ Server-side logging of suspicious activities
6. ✅ User-friendly warnings for detected events

All 4 phases are now implemented and the system is ready for production deployment!