=== iDrivee2 Media Upload ===
Contributors: robotstxt, javiercasares
Tags: media, upload, s3, cdn, storage, idrivee2, cloud
Requires at least: 5.3
Tested up to: 7.1
Stable tag: 1.4.2
Requires PHP: 8.1
Version: 1.4.2
License: GPL-3.0-or-later
License URI: https://www.gnu.org/licenses/gpl-3.0.txt

Upload media files to iDrivee2 (S3-compatible storage) with enterprise-grade security and logging.

== Description ==

iDrivee2 Media Upload is a WordPress plugin that automatically uploads media files to iDrivee2 (S3-compatible storage), deletes local copies to save disk space, and rewrites URLs to serve media from a CDN. The plugin features enterprise-grade security with comprehensive logging, rate limiting, and OWASP Top 10 compliance.

**Key Features:**

* **Automatic S3 Upload**: All media files and generated sizes are automatically uploaded to S3-compatible storage
* **Local File Cleanup**: Deletes local files after successful upload to save disk space
* **CDN Integration**: Rewrites WordPress media URLs to serve from custom CDN domain
* **Security Logging**: Comprehensive logging system for all security events and S3 operations
* **Rate Limiting**: Protection against abuse with configurable cooldown periods
* **Admin Interface**: Test S3 connection and upload test files from WordPress admin
* **Multisite Support**: Works seamlessly with WordPress Multisite installations
* **Type-Safe Code**: PHPStan level 9 compliance with strict type declarations
* **OWASP Compliant**: All OWASP Top 10 (2021) vulnerabilities addressed

**Security Features:**

* Security logging with WP_DEBUG_LOG integration
* Rate limiting (60s users, 30s admins)
* S3 operation statistics tracking (30-day retention)
* Comprehensive nonce validation
* Input sanitization and output escaping
* Capability-based access control (manage_options)
* Sensitive data masking in logs
* Security rating: A+ (Excellent)

**Requirements:**

* WordPress 5.3 or higher
* PHP 8.1 to 8.5
* MariaDB 10.6+ or MySQL 5.7+
* S3-compatible storage (iDrivee2, AWS S3, DigitalOcean Spaces, etc.)
* For automatic updates: the [ROBOTSTXT Manager](https://www.robotstxt.software/plugins/robotstxt-manager/) plugin installed and active

== Using the plugin ==

= WP-CLI =

The plugin provides three WP-CLI commands for operations and diagnostics:

* `wp idrivee2 test-connection` — verify that the S3 bucket is accessible with the configured credentials
* `wp idrivee2 cleanup-local-files` — manually run the local file cleanup that normally runs via WP-Cron every 5 minutes
* `wp idrivee2 stats --days=N` — show S3 operation statistics for the last N days (default: 7, max: 30)

= Automatic updates =

Plugin updates are delivered through the [ROBOTSTXT Manager](https://www.robotstxt.software/plugins/robotstxt-manager/) plugin. When it is not installed and active, the plugin shows a dismissible notice on the Plugins page and a persistent notice on Settings → iDrivee2.

== Extra Configurations ==

The plugin requires configuration constants in your `wp-config.php` file. Add these constants before the `/* That's all, stop editing! */` line:

**Required Constants:**

`define('IDRIVEE2_MEDIA_HOST', 'https://your-s3-endpoint.com');`
S3 endpoint URL. Must start with `https://`.

`define('IDRIVEE2_MEDIA_KEY', 'YOUR_ACCESS_KEY_ID');`
S3 Access Key ID for authentication.

`define('IDRIVEE2_MEDIA_SECRET', 'YOUR_SECRET_ACCESS_KEY');`
S3 Secret Access Key for authentication.

`define('IDRIVEE2_MEDIA_BUCKET', 'your-bucket-name');`
S3 bucket name where media files will be stored.

`define('IDRIVEE2_MEDIA_REGION', 'us-east-1');`
AWS region for the S3 service (e.g., 'us-east-1', 'eu-west-1').

**Optional Constants:**

`define('IDRIVEE2_MEDIA_DOMAIN', 'https://cdn.yourdomain.com');`
Custom CDN domain for serving media files. If not defined, files will be served directly from S3 ObjectURL.

`define('IDRIVEE2_UPLOAD_CONCURRENCY', 5);`
Number of simultaneous S3 uploads per attachment. Default: 5. Increase for faster bulk imports on fast connections; decrease if iDrivee2 returns throttling errors. Minimum: 1.

**Security Logging:**

To enable security logging, add these constants:

`define('WP_DEBUG', false);`
Disable debug mode in production.

`define('WP_DEBUG_LOG', true);`
Enable logging to `wp-content/debug.log`.

`define('WP_DEBUG_DISPLAY', false);`
Don't display errors on screen.

**Example Configuration:**

`// iDrivee2 Media Upload Configuration`
`define('IDRIVEE2_MEDIA_HOST',   'https://s3.idrivee2.com');`
`define('IDRIVEE2_MEDIA_KEY',    'YOUR_ACCESS_KEY_ID');`
`define('IDRIVEE2_MEDIA_SECRET', 'YOUR_SECRET_ACCESS_KEY');`
`define('IDRIVEE2_MEDIA_BUCKET', 'my-wordpress-media');`
`define('IDRIVEE2_MEDIA_REGION', 'us-east-1');`
`define('IDRIVEE2_MEDIA_DOMAIN', 'https://cdn.example.com');`

`// Enable Security Logging`
`define('WP_DEBUG', false);`
`define('WP_DEBUG_LOG', true);`
`define('WP_DEBUG_DISPLAY', false);`

== Installation ==

= Automatic download =

1. Visit Plugins → Add New in your WordPress admin
2. Search for "iDrivee2 Media Upload"
3. Click "Install Now" and then "Activate"
4. Configure the required constants in `wp-config.php` (see Extra Configurations)
5. Go to Settings → iDrivee2 to test your configuration

= Manual download =

1. Download the plugin ZIP file
2. Extract the contents and upload to `/wp-content/plugins/idrivee2-media-upload/`
3. Activate the plugin through the Plugins menu in WordPress
4. Configure the required constants in `wp-config.php` (see Extra Configurations)
5. Go to Settings → iDrivee2 to test your configuration

= After Installation =

1. Add the required constants to your `wp-config.php` file
2. Navigate to Settings → iDrivee2 in WordPress admin
3. Click "Test S3 Connection" to verify bucket access
4. Click "Upload Test File" to verify upload capability
5. Upload a test image through Media → Add New
6. Verify the image URL points to your S3/CDN domain
7. Verify local file is deleted after upload

== Frequently Asked Questions ==

= Does this plugin delete local media files? =

Yes. This plugin deletes local media files after successful upload to S3. Ensure your S3 configuration is correct before activation. Files are permanently deleted from your server to save disk space.

= What happens if S3 upload fails? =

If the S3 upload fails, the local file is NOT deleted. The error is logged (if WP_DEBUG_LOG is enabled) and the file remains on your server.

= Are uploaded files publicly accessible? =

Yes. Files are uploaded with `public-read` ACL. All uploaded files are publicly accessible via the S3 URL or your CDN domain.

= Can I use this with any S3-compatible service? =

Yes. The plugin works with any S3-compatible service including iDrivee2, AWS S3, DigitalOcean Spaces, Wasabi, Backblaze B2, and others.

= Does this work with WordPress Multisite? =

Yes. The plugin is fully compatible with WordPress Multisite installations (Network: true).

= What is logged by the security logging system? =

The plugin logs configuration changes (with sensitive data masking), S3 operations (success/failure with error details), rate limit violations, authentication failures, and invalid file upload attempts. All logs include user context (username, user ID) and timestamps.

= How do I view the security logs? =

Enable `WP_DEBUG_LOG` in `wp-config.php`. Logs are written to `wp-content/debug.log`. You can view this file via FTP/SFTP or use a log viewer plugin.

= What is the rate limiting feature? =

Rate limiting prevents abuse of the test functions. Regular users have a 60-second cooldown between actions, administrators have a 30-second cooldown. This prevents brute force testing of S3 credentials.

= Can I disable rate limiting? =

Rate limiting is built-in and cannot be disabled. However, administrators have a shorter cooldown (30s vs 60s).

= Does this plugin modify the WordPress database? =

Yes. The plugin updates attachment GUIDs to S3 URLs. It also stores S3 operation statistics in the database with 30-day retention. The uninstall script removes all plugin data when the plugin is deleted.

= Is this plugin compatible with page caching plugins? =

Yes. The URL rewriting happens at the WordPress level, so it works with all caching plugins.

= What PHP version is required? =

PHP 8.1 or higher is required. The plugin uses strict type declarations and is tested on PHP 8.1 to 8.5.

= How does this plugin receive updates? =

Updates are delivered through the [ROBOTSTXT Manager](https://www.robotstxt.software/plugins/robotstxt-manager/) plugin. Install and activate it to receive automatic updates.

== Compatibility ==

* WordPress: 5.3 - 7.1
* PHP: 8.1 - 8.5
* MariaDB: 10.6+
* MySQL: 5.7+

**Code Quality:**

* PHP Coding Standards: 3.13.6 (0 errors)
* WordPress Coding Standards (WPCS): 3.4.1 (0 violations)
* PHPStan: Level 9 (0 errors, maximum strictness)
* PHPCompatibility: 8.1-8.5 (fully compatible)

== Changelog ==

= 1.4.2 =

_Release date: 2026-08-17_

**Added**

* Dismissible admin notice on the Plugins page when the ROBOTSTXT Manager plugin is not installed or active, linking to https://www.robotstxt.software/plugins/robotstxt-manager/
* Persistent (non-dismissible) notice on Settings → iDrivee2 under the same condition

**Changed**

* Removed the bundled Gitea auto-updater (`robotstxt-updater.php` and `update.json`); automatic updates are now handled by the ROBOTSTXT Manager plugin
* Plugin URI and new `Update URI` header point to https://www.robotstxt.software/plugins/idrivee2-media-upload/
* Author URI updated to https://www.robotstxt.software/
* Composer dependencies updated (aws-sdk-php 3.392.3, guzzle 8.0.2, no known CVEs)

**Localization**

* POT regenerated for 1.4.2; Spanish (es_ES) and Catalan (ca) translations updated — 69/69 strings in both locales

**Compatibility**

* WordPress: 5.3 - 7.1
* PHP: 8.1 - 8.5

**Tests**

* PHP Coding Standards: 3.13.6 (0 errors)
* WordPress Coding Standards: 3.4.1 (0 violations)
* PHPStan: Level 9, 0 errors
* PHPUnit: 78 tests, 125 assertions

= 1.4.1 =

_Release date: 2026-08-10_

**Highlights**

* Security hardening, data preservation option, and WP-CLI commands
* 66 tests (up from 38), 100% coverage of tested classes

**Added**

* **Data preservation option** — new checkbox under Settings → iDrivee2 ("Delete all plugin data when the plugin is uninstalled"). By default all data is preserved on uninstall; users must explicitly opt in to removal.
* **WP-CLI commands** — three new commands for ops automation:
  * `wp idrivee2 test-connection` — verify S3 bucket accessibility
  * `wp idrivee2 cleanup-local-files` — manually trigger the cron file cleanup
  * `wp idrivee2 stats --days=N` — show S3 operation statistics (default 7 days, max 30)

**Security**

* Logger: `get_client_ip()` now validates with `filter_var( FILTER_VALIDATE_IP )` — rejects malformed or spoofed `REMOTE_ADDR` values
* Admin page: `$_POST['test_file']` now calls `wp_unslash()` at read point
* Cron cleanup: replaced `WP_Filesystem()` with `wp_delete_file()` — works in cron without credentials
* Uninstall: data preservation is now opt-in (default: preserve) per AGENTS data preservation policy

**Changed**

* WordPress minimum corrected from 4.1 to 5.3 (verified via wp-compat — `big_image_size_threshold` filter is the binding constraint)
* `uninstall.php`: replaced direct `$wpdb->query()` with `delete_post_meta_by_key()` (WordPress DB API)
* `robotstxt-updater.php`: documented as external dependency with justification

**Compatibility**

* WordPress: 5.3 - 7.1
* PHP: 8.1 - 8.5

**Tests**

* PHP Coding Standards: 3.13.5 (0 errors)
* WordPress Coding Standards: 3.3.0 (0 violations)
* PHPStan: Level 9, 0 errors
* PHPUnit: 66 tests, 109 assertions, 100% coverage

= 1.3.0 =

_Release date: 2026-07-18_

**Highlights**

* New image sub-sizes control — ship less data per upload, ideal for large camera files. Reduces work in both the WP 7.1 client-side path (browser) and the traditional server-side path.

**Added**

* Settings field **Image Sub-sizes** under Settings → iDrivee2 with three modes: `all` (default), `thumbnail` (only the default thumbnail), `none` (no sub-sizes).
* `IDRIVEE2_MEDIA_SUBSIZES_MODE` wp-config.php constant — same priority pattern as the S3 credentials; the field becomes read-only when set.
* In `thumbnail` and `none` modes the `big_image_size_threshold` filter is also disabled, so WordPress no longer creates a `-scaled` derivative for images larger than 2560px. (Requires WordPress 5.3+ for the scaled-disabling; on older WP the mode still applies via `intermediate_image_sizes`.)

**Security**

* `composer audit` CVEs resolved: `guzzlehttp/guzzle` 7.11 → 7.15, `guzzlehttp/psr7` 2.11 → 2.13, `mtdowling/jmespath.php` 2.8 → 2.9 (CVE-2026-55767 / 55568 / 55766 / 54133).

**Tooling**

* `bin/preflight.sh` added — automated pre-deploy verification per AGENTS-testing-build-deployment.md (PHPCS, PHPStan, PHPCompatibility, PHPUnit + coverage, composer audit, candidate ZIP inspection).
* `.claude/settings.json` added — mechanical deny rules for `deploy.sh`, `git push/tag/merge` per AGENTS.md.

**Compatibility**

* WordPress: 4.1 - 7.1
* PHP: 8.1 - 8.5

**Tests**

* PHP Coding Standards: 3.13.5 (0 errors)
* WordPress Coding Standards: 3.3.0 (0 violations)
* PHPStan: Level 9, 0 errors
* PHPUnit: 38 tests, 60 assertions

= Previous versions =

If you want to see the full changelog, visit the [plugin page](https://www.robotstxt.software/plugins/idrivee2-media-upload/).

== Compliance ==

This plugin adheres to the following security measures and review protocols for each version:

* [WordPress Plugin Handbook](https://developer.wordpress.org/plugins/)
* [WordPress Plugin Security](https://developer.wordpress.org/plugins/wordpress-org/plugin-security/)
* [WordPress APIs Security](https://developer.wordpress.org/apis/security/)
* [WordPress Coding Standards](https://github.com/WordPress/WordPress-Coding-Standards)
* [Plugin Check (PCP)](https://wordpress.org/plugins/plugin-check/)
* [OWASP Top 10 (2021)](https://owasp.org/Top10/)
* [PHPStan Level 9](https://phpstan.org/user-guide/rule-levels)

**Security Audit:**

A comprehensive security audit is available at `docs/SECURITY-AUDIT.md` covering all OWASP Top 10 vulnerabilities, WordPress.org Plugin Review requirements, and security best practices.

**Code Quality:**

A detailed code quality report is available at `docs/QUALITY-REPORT.md` with metrics, static analysis results, and maintainability scores.
