# 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/`