# CSRF Token Audit Tools

This directory contains tools to help you audit and fix CSRF token issues in your application.

## The Problem

CSRF (Cross-Site Request Forgery) protection requires that:
1. Every POST form must include a CSRF token field: `<?= csrf_field() ?>`
2. Every JavaScript function that makes POST requests must include the CSRF token

Missing CSRF tokens will cause "Invalid CSRF token" errors when users submit forms or make AJAX requests.

## Tools Available

### 1. System Scripts Manager (Recommended)

The CSRF Token Audit is integrated into the System Scripts Manager for easy web-based execution.

**Access:** Settings > Administration > System Scripts > CSRF Token Audit

**Benefits:**
- No command-line access needed
- Visual interface with categories
- Execution history tracking
- Automatic logging of who ran the audit and when

**Parameters:**
- **Output Format**: Choose between Summary (top 20 issues) or Detailed (all issues)

### 2. Full Audit Script (`check_csrf_tokens.php`)

Scans all view files and generates a comprehensive report.

**Usage:**
```bash
php check_csrf_tokens.php
```

**Output:**
- Console output showing critical issues
- Detailed report saved to `csrf_audit_report.txt`

**What it checks:**
- ✅ Files with proper CSRF tokens
- ❌ POST forms without `csrf_field()`
- ⚠️  JavaScript that references `csrf_token` but no field present

### 3. Quick Check Script (`csrf_check.sh`)

Fast command-line utility for checking specific files or directories.

**Usage:**
```bash
# Check entire views directory (default)
./csrf_check.sh

# Check specific directory
./csrf_check.sh views/quotes

# Check specific file
./csrf_check.sh views/quotes/general/show.php
```

**Example Output:**
```
Checking CSRF tokens in: views/quotes
======================================

❌ views/quotes/index.php - POST form without csrf_field()
✅ views/quotes/general/show.php - OK
⚠️  views/quotes/battery/show.php - JS csrf_token without csrf_field()

======================================
Summary:
  Critical Issues: 1
  Warnings: 1
  Files with CSRF: 12
```

## Current Status

As of the last audit (November 27, 2025):
- **Total files scanned:** 605
- **Files with CSRF tokens:** 212
- **Files with issues:** 115

See `csrf_audit_report.txt` for the complete list of files needing attention.

## How to Fix Issues

### Issue 1: POST Form Without csrf_field()

**Problem:** Form submits but has no CSRF token
```php
<form method="POST" action="...">
    <!-- Missing csrf_field() -->
    <button type="submit">Submit</button>
</form>
```

**Solution:** Add `csrf_field()` inside the form
```php
<form method="POST" action="...">
    <?= csrf_field() ?>
    <button type="submit">Submit</button>
</form>
```

### Issue 2: JavaScript References csrf_token Without Field

**Problem:** JavaScript tries to access CSRF token that doesn't exist on page
```javascript
fetch('/api/endpoint', {
    method: 'POST',
    body: 'csrf_token=' + document.querySelector('input[name="csrf_token"]').value
})
```

**Solution:** Add hidden CSRF field somewhere on the page (before the script)
```php
<!-- Add this before your script tag or modal -->
<?= csrf_field() ?>

<script>
// Now the token is available
fetch('/api/endpoint', {
    method: 'POST',
    body: 'csrf_token=' + document.querySelector('input[name="csrf_token"]').value
})
</script>
```

### Issue 3: Modal Forms Without CSRF Token

**Problem:** Modal contains a form but no CSRF field
```php
<div class="modal">
    <form id="emailForm">
        <input type="email" name="email">
        <button onclick="submitForm()">Send</button>
    </form>
</div>

<script>
function submitForm() {
    // Tries to get csrf_token but it doesn't exist
    const token = document.querySelector('[name="csrf_token"]').value;
}
</script>
```

**Solution:** Add CSRF field before the modal or inside it
```php
<!-- Option 1: Before modal (recommended if multiple modals need it) -->
<?= csrf_field() ?>

<!-- Option 2: Inside the modal form -->
<div class="modal">
    <form id="emailForm">
        <?= csrf_field() ?>
        <input type="email" name="email">
        <button onclick="submitForm()">Send</button>
    </form>
</div>
```

## Priority Files to Fix

Based on user-facing impact, prioritize these:

### High Priority (User-facing forms)
- `quotes/general/show.php` ✅ (Already fixed)
- `crm/opportunities_show.php`
- `invoices/index.php`
- `products/edit.php`
- `customers/show.php`

### Medium Priority (Admin/Settings)
- `settings/*.php` files
- `dashboard/customize.php`
- `warehouses/*.php`

### Low Priority (Trash/Utility pages)
- `*/trash.php` files
- Import/export pages

## Testing After Fixes

After adding CSRF tokens to a file:

1. Clear browser cache
2. Test the form submission or AJAX call
3. Verify no "Invalid CSRF token" error appears
4. Run the audit script to confirm the fix:
   ```bash
   ./csrf_check.sh views/your/fixed/file.php
   ```

## Maintenance

**When to run audits:**
- Before major releases
- After adding new forms or AJAX functionality
- When users report "Invalid CSRF token" errors
- Weekly during active development

**Quick check workflow:**
```bash
# After modifying a view file
./csrf_check.sh views/path/to/your/file.php

# Before committing changes to a module
./csrf_check.sh views/module_name

# Full audit before release
php check_csrf_tokens.php
```

## Common Patterns

### Pattern 1: Standard Form
```php
<form method="POST" action="<?= base_url('endpoint') ?>">
    <?= csrf_field() ?>
    <!-- form fields -->
    <button type="submit">Submit</button>
</form>
```

### Pattern 2: AJAX with FormData
```javascript
const formData = new FormData();
formData.append('field', value);
formData.append('csrf_token', document.querySelector('[name="csrf_token"]').value);

fetch('/endpoint', {
    method: 'POST',
    body: formData
});
```

### Pattern 3: AJAX with JSON
```javascript
fetch('/endpoint', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        field: value,
        csrf_token: document.querySelector('[name="csrf_token"]').value
    })
});
```

### Pattern 4: Multiple Modals on One Page
```php
<!-- One csrf_field() at top of page serves all modals -->
<?= csrf_field() ?>

<div class="modal" id="modal1">
    <form><!-- no csrf_field needed here --></form>
</div>

<div class="modal" id="modal2">
    <form><!-- no csrf_field needed here --></form>
</div>
```

## Notes

- The CSRF token field is a hidden input: `<input type="hidden" name="csrf_token" value="...">`
- One `csrf_field()` per page is usually enough (unless forms are in different contexts)
- The `csrf_validate()` function in controllers automatically checks the token
- CSRF tokens expire with the session

## Questions?

If you encounter issues or need help fixing CSRF problems, check:
1. The generated `csrf_audit_report.txt` for your specific file
2. The controller handling the request to ensure it calls `csrf_validate()`
3. The browser console for JavaScript errors related to CSRF token access
