# HTMLPurifier Cache Directory Fix

## Problem

When deploying to a server, you may encounter this error:
```
Directory /var/www/timebank_cc_dev/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer not writable.
```

This occurs because HTMLPurifier tries to write cache files to its vendor directory, which:
1. Should NOT be writable for security reasons
2. May not have correct permissions on production servers
3. Can be overwritten during `composer install`

## Solution

We've reconfigured HTMLPurifier to use Laravel's cache directory instead.

### Changes Made

1. **Updated `app/Helpers/StringHelper.php`** (Lines 55-63)
   - HTMLPurifier now uses `storage/framework/cache/htmlpurifier`
   - Auto-creates directory if it doesn't exist
   - Works across all environments without manual configuration

2. **Created `deployment-htmlpurifier-fix.sh`**
   - Standalone script to set up HTMLPurifier cache directory
   - Auto-detects web server user or accepts it as argument
   - Gracefully handles permission errors
   - Always exits successfully (doesn't break deployment)

3. **Integrated into `deploy.sh`** (Lines 306-316)
   - Automatically runs during deployment
   - Uses same web user/group as rest of application
   - Runs for both local and server environments

## How It Works

### Automatic (via deploy.sh)

When you run `./deploy.sh`, it will automatically:
1. Create `storage/framework/cache/htmlpurifier` directory
2. Set ownership to web server user (www-data, apache, nginx, etc.)
3. Set permissions to 755
4. Verify the directory is writable

### Manual (if needed)

If you need to run the setup separately:

```bash
# Let script auto-detect web server user
./deployment-htmlpurifier-fix.sh

# Or specify web server user
./deployment-htmlpurifier-fix.sh www-data

# Or specify both user and group
./deployment-htmlpurifier-fix.sh www-data www-data
```

### Code-Level (automatic)

The `StringHelper::sanitizeHtml()` method automatically creates the cache directory if it doesn't exist (lines 58-61):

```php
$cacheDir = storage_path('framework/cache/htmlpurifier');
if (!is_dir($cacheDir)) {
    mkdir($cacheDir, 0755, true);
}
```

## Deployment Instructions

### First Time Setup (New Servers)

Just run your normal deployment:
```bash
./deploy.sh
```

The HTMLPurifier cache directory will be set up automatically.

### Existing Deployments (Already Running)

If you're updating an existing server that already has the old code deployed:

1. **Pull and deploy the latest code:**
   ```bash
   ./deploy.sh
   ```

2. **The script will automatically:**
   - Update code to use new cache location
   - Create and configure the cache directory
   - Set correct permissions

3. **Verify (optional):**
   ```bash
   ls -la storage/framework/cache/htmlpurifier
   ```

   You should see the directory with correct ownership and permissions.

### If You Still Get Errors

If you encounter permission errors after deployment:

1. **Manually run the fix script:**
   ```bash
   cd /var/www/timebank_cc_dev
   ./deployment-htmlpurifier-fix.sh www-data www-data
   ```

2. **Check storage directory permissions:**
   ```bash
   sudo chown -R www-data:www-data storage/
   sudo chmod -R 775 storage/
   ```

3. **Check SELinux (if applicable):**
   ```bash
   sudo chcon -R -t httpd_sys_rw_content_t storage/
   ```

4. **Clear all caches:**
   ```bash
   php artisan cache:clear
   php artisan view:clear
   php artisan config:clear
   ```

## Benefits

1. **Security:** Vendor directory remains read-only
2. **Reliability:** Cache survives `composer install` updates
3. **Laravel Standard:** Uses Laravel's cache directory structure
4. **Cross-Environment:** Works on local, dev, and production without changes
5. **Auto-Recovery:** Code creates directory if missing
6. **Deployment Safe:** Script always continues even if errors occur

## Technical Details

### Cache Location
- **Old (problematic):** `vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer`
- **New (fixed):** `storage/framework/cache/htmlpurifier`

### Permissions
- **Directory:** 0755 (owner: rwx, group: r-x, others: r-x)
- **Owner:** Web server user (www-data, apache, nginx)
- **Group:** Web server group (same as owner)

### Files Created
When HTMLPurifier runs, it creates definition cache files:
- `HTML/4.01_XHTML1.0_Transitional.ser`
- `HTML/4.01_XHTML1.0_Transitional-Attr.AllowedFrameTargets.ser`
- And others based on configuration

These are automatically managed by HTMLPurifier and Laravel's cache clearing commands.

## Troubleshooting

### Error: "Directory not writable"

**Cause:** Web server user can't write to cache directory

**Fix:**
```bash
sudo chown -R www-data:www-data storage/framework/cache/htmlpurifier
sudo chmod -R 755 storage/framework/cache/htmlpurifier
```

### Error: "Failed to create directory"

**Cause:** Parent directory (`storage/framework/cache/`) doesn't have write permissions

**Fix:**
```bash
sudo chown -R www-data:www-data storage/framework/cache/
sudo chmod -R 775 storage/framework/cache/
```

### Error: SELinux blocking writes

**Cause:** SELinux security context preventing writes

**Fix:**
```bash
sudo chcon -R -t httpd_sys_rw_content_t storage/framework/cache/
```

## Testing

After deployment, verify HTMLPurifier works:

1. **View a post with HTML content:**
   - Visit any page that displays post content
   - No errors should appear

2. **Check cache directory:**
   ```bash
   ls -la storage/framework/cache/htmlpurifier/
   ```
   You should see definition cache files created by HTMLPurifier

3. **Run tests:**
   ```bash
   php artisan test --filter PostContentXssProtectionTest
   ```
   All 16 tests should pass

## Related Files

- `app/Helpers/StringHelper.php` - Sanitization method with cache configuration
- `deployment-htmlpurifier-fix.sh` - Standalone setup script
- `deploy.sh` - Main deployment script (includes HTMLPurifier setup)
- `SECURITY_AUDIT_XSS.md` - Complete XSS vulnerability audit report

## Support

If you encounter issues not covered here:

1. Check Laravel logs: `storage/logs/laravel.log`
2. Check web server error logs: `/var/log/apache2/error.log` or `/var/log/nginx/error.log`
3. Verify web server user: `ps aux | grep -E 'apache|nginx|httpd' | grep -v grep`
4. Check storage permissions: `ls -la storage/`
