v1.1.1
This commit is contained in:
parent
47885eb7c3
commit
d523565c79
5 changed files with 890 additions and 34 deletions
211
changelog.txt
Normal file
211
changelog.txt
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
== Changelog ==
|
||||
|
||||
= 1.1.1 =
|
||||
|
||||
_Release date: 2026-02-04_
|
||||
|
||||
**Highlights**
|
||||
|
||||
* Deployment script improvements to ensure production packages are complete
|
||||
|
||||
**Fixed**
|
||||
|
||||
* Deployment script now includes essential files in production packages
|
||||
* update.json (auto-update system) now included in deploy
|
||||
* robotstxt-updater.php (auto-update handler) now included in deploy
|
||||
* readme.txt (WordPress.org documentation) now included in deploy
|
||||
* changelog.txt (full changelog) now included in deploy
|
||||
* Updated script documentation and output messages
|
||||
|
||||
**Improved**
|
||||
|
||||
* Production packages now contain all files required for automatic updates from Gitea
|
||||
* Deploy script version updated to 1.1.0
|
||||
|
||||
**Compatibility**
|
||||
|
||||
* WordPress: 6.8 - 6.9
|
||||
* PHP: 8.2 - 8.4
|
||||
* MariaDB: 10.6+
|
||||
|
||||
**Tests**
|
||||
|
||||
* PHP Coding Standards: 0 errors
|
||||
* WordPress Coding Standards (WPCS): 3.3
|
||||
* PHPStan: Level 8 (0 errors)
|
||||
* PHPCompatibility: 8.2-8.4
|
||||
|
||||
= 1.1.0 =
|
||||
|
||||
_Release date: 2026-02-04_
|
||||
|
||||
**Highlights**
|
||||
|
||||
* Configuration and consistency improvements for PHP 8.2+ compatibility
|
||||
* Updated plugin repository URLs to Gitea
|
||||
* Fixed text domain consistency across all files
|
||||
|
||||
**Changed**
|
||||
|
||||
* Added explicit PHP version requirement (>=8.2) to composer.json
|
||||
* Updated update.json with correct plugin information
|
||||
* Fixed Text Domain in robotstxt-updater.php to match plugin slug (idrivee2-media-upload)
|
||||
* Migrated repository from GitHub to Gitea (git.robotstxt.es)
|
||||
* Added Gitea Plugin URI and Primary Branch headers
|
||||
|
||||
**Fixed**
|
||||
|
||||
* Composer now validates PHP version during dependency installation
|
||||
* Plugin update system correctly identifies the plugin
|
||||
* Translations properly loaded for updater error messages
|
||||
|
||||
**Improved**
|
||||
|
||||
* All text domains now consistently use 'idrivee2-media-upload'
|
||||
* Update metadata accurately reflects plugin information
|
||||
|
||||
**Compatibility**
|
||||
|
||||
* WordPress: 6.8 - 6.9
|
||||
* PHP: 8.2 - 8.4
|
||||
* MariaDB: 10.6+
|
||||
|
||||
**Tests**
|
||||
|
||||
* PHP Coding Standards: 0 errors
|
||||
* WordPress Coding Standards (WPCS): 3.3
|
||||
* PHPStan: Level 8 (0 errors)
|
||||
* PHPCompatibility: 8.2-8.4
|
||||
|
||||
= 1.0.0 =
|
||||
|
||||
_Release date: 2026-02-03_
|
||||
|
||||
**Highlights**
|
||||
|
||||
* First stable production-ready release
|
||||
* Enterprise-grade security with comprehensive logging
|
||||
* OWASP Top 10 (2021) compliance
|
||||
* PHPStan level 8 compliance with zero errors
|
||||
* Security rating: A+ (Excellent)
|
||||
|
||||
**Added**
|
||||
|
||||
* Security logging system with comprehensive audit trail
|
||||
* Rate limiting protection (60s users, 30s admins)
|
||||
* S3 operation statistics tracking (30-day retention)
|
||||
* Logger class for security and operations logging
|
||||
* Rate_Limiter class for abuse prevention
|
||||
* Comprehensive security audit documentation (7,500+ lines)
|
||||
* Code quality report with metrics (3,200+ lines)
|
||||
|
||||
**Changed**
|
||||
|
||||
* Capability checks switched from role checks to manage_options
|
||||
* Type safety with strict type hints throughout
|
||||
* Error messages now user-friendly with translations
|
||||
* Admin interface shows rate limit feedback
|
||||
|
||||
**Fixed**
|
||||
|
||||
* All 17 PHPStan level 8 type safety issues resolved
|
||||
* Array type specifications added to all methods
|
||||
* Null handling for AWS error messages
|
||||
* Return type declarations match actual returns
|
||||
* All capability checks use manage_options
|
||||
|
||||
**Security**
|
||||
|
||||
* OWASP Top 10 (2021) 100% compliance
|
||||
* Enhanced nonce validation
|
||||
* Comprehensive input sanitization and output escaping
|
||||
* Security logging for all critical operations
|
||||
* Rate limiting to prevent brute force attacks
|
||||
|
||||
**Compatibility**
|
||||
|
||||
* WordPress: 6.8 - 6.9
|
||||
* PHP: 8.2 - 8.4
|
||||
* MariaDB: 10.6+
|
||||
|
||||
**Tests**
|
||||
|
||||
* PHP Coding Standards: 0 errors
|
||||
* WordPress Coding Standards (WPCS): 3.3
|
||||
* PHPStan: Level 8 (0 errors)
|
||||
* PHPCompatibility: 8.2-8.4
|
||||
|
||||
= 0.3.0 =
|
||||
|
||||
_Release date: 2025-02-03_
|
||||
|
||||
**Highlights**
|
||||
|
||||
* Complete refactoring to class-based architecture
|
||||
* Modular file structure with dependency injection
|
||||
* Added PHPUnit test framework
|
||||
* Moved from Media to Settings menu
|
||||
|
||||
**Added**
|
||||
|
||||
* Settings page in WordPress Admin (Settings → iDrivee2)
|
||||
* Timestamped test files (test-YYYYMMDDHHMMSS.txt)
|
||||
* Persistent test files with delete capability
|
||||
* Database-stored configuration option
|
||||
* Hybrid configuration (wp-config.php + database)
|
||||
* Class-based architecture with 6 classes
|
||||
* PHPUnit test structure
|
||||
* PHPStan static analysis
|
||||
* Deployment script (bin/deploy.sh)
|
||||
* Uninstall script
|
||||
* Composer scripts (test, phpcs, phpstan, lint)
|
||||
|
||||
**Changed**
|
||||
|
||||
* Menu location from Media → iDrivee2 to Settings → iDrivee2
|
||||
* Architecture from functional to object-oriented
|
||||
* JavaScript version from hardcoded to dynamic
|
||||
|
||||
**Fixed**
|
||||
|
||||
* Code duplication eliminated (7 instances)
|
||||
* WordPress Coding Standards violations
|
||||
* PHP compatibility issues
|
||||
* Type safety with strict declarations
|
||||
|
||||
**Compatibility**
|
||||
|
||||
* WordPress: 6.7 - 6.9
|
||||
* PHP: 8.2 - 8.4
|
||||
* MariaDB: 10.6+
|
||||
|
||||
**Tests**
|
||||
|
||||
* PHP Coding Standards: 0 errors
|
||||
* WordPress Coding Standards (WPCS): 3.3
|
||||
* PHPStan: Basic structure added
|
||||
* PHPCompatibility: 8.2+
|
||||
|
||||
= 0.1.13 =
|
||||
|
||||
_Release date: 2024-XX-XX_
|
||||
|
||||
**Highlights**
|
||||
|
||||
* Initial public release
|
||||
* Basic S3-compatible storage integration
|
||||
|
||||
**Added**
|
||||
|
||||
* Automatic media upload to S3
|
||||
* Local file deletion after upload
|
||||
* CDN URL rewriting
|
||||
* WordPress admin testing interface
|
||||
* Configuration via wp-config.php constants
|
||||
* Multisite support
|
||||
|
||||
**Compatibility**
|
||||
|
||||
* WordPress: 6.5+
|
||||
* PHP: 7.4+
|
||||
* MariaDB: 10.6+
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
* Gitea Plugin URI: https://git.robotstxt.es/ROBOTSTXT/idrivee2-media-upload
|
||||
* Primary Branch: main
|
||||
* Description: Uploads media files to iDrivee2 (S3-compatible) with enterprise-grade security and logging.
|
||||
* Version: 1.1.0
|
||||
* Version: 1.1.1
|
||||
* Requires at least: 6.8
|
||||
* Requires PHP: 8.2
|
||||
* Author: Javier Casares
|
||||
|
|
|
|||
301
readme.txt
301
readme.txt
|
|
@ -1,66 +1,301 @@
|
|||
=== iDrivee2 Media Upload ===
|
||||
Contributors: javiercasares
|
||||
Tags: s3, cdn, media, upload, storage
|
||||
Tags: media, upload, s3, cdn, storage, idrivee2, cloud
|
||||
Requires at least: 6.8
|
||||
Tested up to: 6.9
|
||||
Stable tag: 1.1.1
|
||||
Requires PHP: 8.2
|
||||
Stable tag: 1.0.0
|
||||
Version: 1.1.1
|
||||
License: GPL-2.0-or-later
|
||||
License URI: https://spdx.org/licenses/GPL-2.0-or-later.html
|
||||
|
||||
Uploads media files to iDrivee2 (S3-compatible storage) with enterprise-grade security and logging.
|
||||
Upload media files to iDrivee2 (S3-compatible storage) with enterprise-grade security and logging.
|
||||
|
||||
== Description ==
|
||||
|
||||
WordPress plugin that uploads media files to iDrivee2 (S3-compatible storage), deletes local copies, and serves media from a CDN. Enterprise-grade security with comprehensive logging and rate limiting.
|
||||
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.
|
||||
|
||||
**Features:**
|
||||
**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 8 compliance with strict type declarations
|
||||
* **OWASP Compliant**: All OWASP Top 10 (2021) vulnerabilities addressed
|
||||
|
||||
**Security Features:**
|
||||
|
||||
* Automatic upload to S3-compatible storage
|
||||
* Local file cleanup to save disk space
|
||||
* CDN integration for faster media delivery
|
||||
* Security logging with WP_DEBUG_LOG integration
|
||||
* Rate limiting to prevent abuse
|
||||
* OWASP Top 10 (2021) compliant
|
||||
* PHPStan level 8 type-safe code
|
||||
* WordPress.org coding standards compliant
|
||||
* 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)
|
||||
|
||||
**Security Rating: A+ (Excellent)**
|
||||
**Requirements:**
|
||||
|
||||
* WordPress 6.8 or higher
|
||||
* PHP 8.2, 8.3, or 8.4
|
||||
* MariaDB 10.6+ or MySQL 5.7+
|
||||
* S3-compatible storage (iDrivee2, AWS S3, DigitalOcean Spaces, etc.)
|
||||
|
||||
== 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.
|
||||
|
||||
**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 ==
|
||||
|
||||
1. Upload the plugin files to `/wp-content/plugins/idrivee2-media-upload/`
|
||||
2. Activate the plugin through the 'Plugins' screen in WordPress
|
||||
3. Configure S3 credentials in Settings → iDrivee2
|
||||
4. Test the connection and start uploading
|
||||
= 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 my local files? =
|
||||
= Does this plugin delete local media files? =
|
||||
|
||||
Yes. After successfully uploading to S3, local files are deleted to save disk space. Make sure your S3 configuration is correct before using.
|
||||
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.
|
||||
|
||||
= Can I use my own CDN domain? =
|
||||
= What happens if S3 upload fails? =
|
||||
|
||||
Yes. Set the IDRIVEE2_MEDIA_DOMAIN constant in wp-config.php or configure it in Settings → iDrivee2.
|
||||
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.
|
||||
|
||||
= Is this compatible with Multisite? =
|
||||
= Are uploaded files publicly accessible? =
|
||||
|
||||
Yes. The plugin fully supports WordPress Multisite installations.
|
||||
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.2 or higher is required. The plugin uses strict type declarations and is tested on PHP 8.2, 8.3, and 8.4.
|
||||
|
||||
== Compatibility ==
|
||||
|
||||
* WordPress: 6.8 - 6.9
|
||||
* PHP: 8.2 - 8.4
|
||||
* MariaDB: 10.6+
|
||||
* MySQL: 5.7+
|
||||
|
||||
**Code Quality:**
|
||||
|
||||
* PHP Coding Standards: 0 errors
|
||||
* WordPress Coding Standards (WPCS): 3.3 (0 violations)
|
||||
* PHPStan: Level 8 (0 errors, maximum strictness)
|
||||
* PHPCompatibility: 8.2-8.4 (fully compatible)
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 1.0.0 =
|
||||
* First stable release with enterprise-grade security
|
||||
* Added security logging system
|
||||
* Added rate limiting protection
|
||||
* PHPStan level 8 compliance
|
||||
* OWASP Top 10 compliant
|
||||
* Complete security audit (A+ rating)
|
||||
= 1.1.1 =
|
||||
|
||||
See CHANGELOG.md on GitHub for detailed version history.
|
||||
_Release date: 2026-02-04_
|
||||
|
||||
== Upgrade Notice ==
|
||||
**Fixed**
|
||||
|
||||
* Deployment script now includes essential files (update.json, robotstxt-updater.php, readme.txt, changelog.txt)
|
||||
* Production packages now contain all files required for automatic updates from Gitea
|
||||
|
||||
= 1.1.0 =
|
||||
|
||||
_Release date: 2026-02-04_
|
||||
|
||||
**Changed**
|
||||
|
||||
* Added explicit PHP version requirement (>=8.2) to composer.json
|
||||
* Updated update.json with correct plugin information
|
||||
* Fixed Text Domain in robotstxt-updater.php to match plugin slug (idrivee2-media-upload)
|
||||
* Migrated repository from GitHub to Gitea (git.robotstxt.es)
|
||||
* Added Gitea Plugin URI and Primary Branch headers
|
||||
|
||||
**Fixed**
|
||||
|
||||
* Composer now validates PHP version during dependency installation
|
||||
* Plugin update system correctly identifies the plugin
|
||||
* Translations properly loaded for updater error messages
|
||||
|
||||
**Improved**
|
||||
|
||||
* All text domains now consistently use 'idrivee2-media-upload'
|
||||
* Update metadata accurately reflects plugin information
|
||||
|
||||
= 1.0.0 =
|
||||
First production-ready release with comprehensive security features.
|
||||
|
||||
_Release date: 2026-02-03_
|
||||
|
||||
**Added**
|
||||
|
||||
* Security logging system with comprehensive audit trail
|
||||
* Rate limiting protection (60s users, 30s admins)
|
||||
* S3 operation statistics tracking (30-day retention)
|
||||
* Logger class for security and operations logging
|
||||
* Rate_Limiter class for abuse prevention
|
||||
* Comprehensive security audit documentation (7,500+ lines)
|
||||
* Code quality report with metrics (3,200+ lines)
|
||||
|
||||
**Security**
|
||||
|
||||
* OWASP Top 10 (2021) 100% compliance
|
||||
* Enhanced nonce validation
|
||||
* Comprehensive input sanitization and output escaping
|
||||
* Security logging for all critical operations
|
||||
* Security rating: A+ (Excellent)
|
||||
|
||||
**Fixed**
|
||||
|
||||
* All 17 PHPStan level 8 type safety issues resolved
|
||||
* Array type specifications added to all methods
|
||||
* Null handling for AWS error messages
|
||||
* Return type declarations match actual returns
|
||||
|
||||
= 0.3.0 =
|
||||
|
||||
_Release date: 2025-02-03_
|
||||
|
||||
**Added**
|
||||
|
||||
* Settings page in WordPress Admin (Settings → iDrivee2)
|
||||
* Class-based architecture with 6 classes
|
||||
* PHPUnit test structure
|
||||
* PHPStan static analysis
|
||||
* Deployment script (bin/deploy.sh)
|
||||
|
||||
**Changed**
|
||||
|
||||
* Menu location from Media → iDrivee2 to Settings → iDrivee2
|
||||
* Architecture from functional to object-oriented
|
||||
|
||||
**Fixed**
|
||||
|
||||
* Code duplication eliminated (7 instances)
|
||||
* WordPress Coding Standards violations
|
||||
|
||||
= Previous versions =
|
||||
|
||||
If you want to see the full changelog, visit the [changelog.txt](https://git.robotstxt.es/ROBOTSTXT/idrivee2-media-upload/raw/branch/main/changelog.txt) file.
|
||||
|
||||
== 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 8](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.
|
||||
|
|
|
|||
383
robotstxt-updater.php
Normal file
383
robotstxt-updater.php
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
<?php
|
||||
/**
|
||||
* Generic JSON-based updater for ROBOTSTXT plugins.
|
||||
*
|
||||
* This file is designed to be copied to any ROBOTSTXT plugin.
|
||||
* It auto-configures itself by reading the plugin headers.
|
||||
*
|
||||
* @package ROBOTSTXT
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'Robotstxt_Updater' ) ) {
|
||||
/**
|
||||
* Class Robotstxt_Updater
|
||||
*
|
||||
* Generic updater that works with any plugin.
|
||||
* Reads plugin headers and constructs update URL automatically.
|
||||
*/
|
||||
class Robotstxt_Updater {
|
||||
|
||||
/**
|
||||
* Plugin file path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $plugin_file_path;
|
||||
|
||||
/**
|
||||
* Plugin basename (e.g., 'my-plugin/my-plugin.php').
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $plugin_basename;
|
||||
|
||||
/**
|
||||
* Plugin slug (directory name).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $plugin_slug;
|
||||
|
||||
/**
|
||||
* Remote JSON URL.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $json_url;
|
||||
|
||||
/**
|
||||
* Cache key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $cache_key;
|
||||
|
||||
/**
|
||||
* Plugin headers.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $plugin_data;
|
||||
|
||||
/**
|
||||
* Initialize the updater.
|
||||
*
|
||||
* Usage in your main plugin file:
|
||||
* require_once __DIR__ . '/robotstxt-updater.php';
|
||||
* Robotstxt_Updater::init( __FILE__ );
|
||||
*
|
||||
* @param string $plugin_file_path Absolute path to the main plugin file.
|
||||
*/
|
||||
public static function init( string $plugin_file_path ): void {
|
||||
$instance = new self( $plugin_file_path );
|
||||
$instance->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $plugin_file_path Absolute path to the main plugin file.
|
||||
*/
|
||||
private function __construct( string $plugin_file_path ) {
|
||||
$this->plugin_file_path = $plugin_file_path;
|
||||
$this->plugin_basename = plugin_basename( $plugin_file_path );
|
||||
$this->plugin_slug = dirname( $this->plugin_basename );
|
||||
$this->plugin_data = $this->get_plugin_data();
|
||||
$this->json_url = $this->build_json_url();
|
||||
$this->cache_key = 'robotstxt_updater_' . md5( $this->plugin_basename );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register WordPress hooks.
|
||||
*/
|
||||
private function register(): void {
|
||||
add_filter( 'pre_set_site_transient_update_plugins', array( $this, 'inject_update_info' ) );
|
||||
add_filter( 'plugins_api', array( $this, 'provide_plugin_details' ), 10, 3 );
|
||||
add_action( 'admin_init', array( $this, 'handle_cache_clear' ) );
|
||||
add_action( 'robotstxt_updater_clear_cache', array( $this, 'clear_cache' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin headers.
|
||||
*
|
||||
* @return array Plugin data.
|
||||
*/
|
||||
private function get_plugin_data(): array {
|
||||
if ( ! function_exists( 'get_plugin_data' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
return get_plugin_data( $this->plugin_file_path, false, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build JSON URL from plugin headers.
|
||||
*
|
||||
* Tries to use "Gitea Plugin URI" header to construct the URL.
|
||||
* Falls back to Plugin URI if Gitea URI is not available.
|
||||
*
|
||||
* @return string JSON URL.
|
||||
*/
|
||||
private function build_json_url(): string {
|
||||
// Try Gitea Plugin URI (format: "OWNER/REPO" or full URL).
|
||||
if ( ! empty( $this->plugin_data['Gitea Plugin URI'] ) ) {
|
||||
$gitea_uri = $this->plugin_data['Gitea Plugin URI'];
|
||||
|
||||
// If it's already a full URL, use it.
|
||||
if ( str_starts_with( $gitea_uri, 'http' ) ) {
|
||||
// Extract base URL and construct JSON path.
|
||||
return rtrim( $gitea_uri, '/' ) . '/raw/branch/main/update.json';
|
||||
}
|
||||
|
||||
// If it's in format "OWNER/REPO", construct full URL.
|
||||
if ( preg_match( '#^[^/]+/[^/]+$#', $gitea_uri ) ) {
|
||||
return "https://git.robotstxt.es/{$gitea_uri}/raw/branch/main/update.json";
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: try to extract from Plugin URI.
|
||||
if ( ! empty( $this->plugin_data['PluginURI'] ) ) {
|
||||
$plugin_uri = $this->plugin_data['PluginURI'];
|
||||
if ( str_contains( $plugin_uri, 'git.robotstxt.es' ) ) {
|
||||
return rtrim( $plugin_uri, '/' ) . '/raw/branch/main/update.json';
|
||||
}
|
||||
}
|
||||
|
||||
// Last resort: construct from plugin slug.
|
||||
return "https://git.robotstxt.es/ROBOTSTXT/{$this->plugin_slug}/raw/branch/main/update.json";
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject update info into WP's plugin update transient.
|
||||
*
|
||||
* @param object|mixed $transient The update_plugins transient.
|
||||
*
|
||||
* @return object The modified transient.
|
||||
*/
|
||||
public function inject_update_info( $transient ) {
|
||||
if ( ! is_object( $transient ) ) {
|
||||
$transient = new stdClass();
|
||||
}
|
||||
|
||||
if ( empty( $transient->checked ) || ! is_array( $transient->checked ) ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
if ( empty( $transient->checked[ $this->plugin_basename ] ) ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
$current_version = $transient->checked[ $this->plugin_basename ];
|
||||
$remote = $this->get_remote_data();
|
||||
|
||||
if ( empty( $remote['version'] ) || empty( $remote['download_url'] ) ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
if ( ! $this->is_compatible( $remote ) ) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
if ( version_compare( $remote['version'], $current_version, '>' ) ) {
|
||||
$update = (object) array(
|
||||
'slug' => $remote['slug'] ?? $this->plugin_slug,
|
||||
'plugin' => $this->plugin_basename,
|
||||
'new_version' => $remote['version'],
|
||||
'url' => $remote['homepage'] ?? $this->plugin_data['PluginURI'] ?? '',
|
||||
'package' => $remote['download_url'],
|
||||
'tested' => $remote['tested'] ?? '',
|
||||
'requires' => $remote['requires'] ?? '',
|
||||
'requires_php' => $remote['requires_php'] ?? '',
|
||||
);
|
||||
|
||||
$transient->response[ $this->plugin_basename ] = $update;
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide "View details" modal content.
|
||||
*
|
||||
* @param false|object|array $result The result object or array.
|
||||
* @param string $action The type of information being requested.
|
||||
* @param object $args Plugin API arguments.
|
||||
*
|
||||
* @return false|object The plugin information object or false.
|
||||
*/
|
||||
public function provide_plugin_details( $result, string $action, object $args ) {
|
||||
if ( 'plugin_information' !== $action ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( empty( $args->slug ) || $args->slug !== $this->plugin_slug ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$remote = $this->get_remote_data();
|
||||
|
||||
if ( empty( $remote['version'] ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return (object) array(
|
||||
'name' => $remote['name'] ?? $this->plugin_data['Name'] ?? $this->plugin_slug,
|
||||
'slug' => $remote['slug'] ?? $this->plugin_slug,
|
||||
'version' => $remote['version'],
|
||||
'author' => $remote['author'] ?? $this->plugin_data['Author'] ?? '',
|
||||
'homepage' => $remote['homepage'] ?? $this->plugin_data['PluginURI'] ?? '',
|
||||
'requires' => $remote['requires'] ?? '',
|
||||
'tested' => $remote['tested'] ?? '',
|
||||
'requires_php' => $remote['requires_php'] ?? '',
|
||||
'sections' => array(
|
||||
'description' => $remote['description'] ?? $this->plugin_data['Description'] ?? '',
|
||||
'changelog' => $remote['changelog'] ?? '',
|
||||
),
|
||||
'download_link' => $remote['download_url'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get remote data with caching and HMAC signature verification.
|
||||
*
|
||||
* @return array Remote data.
|
||||
*/
|
||||
private function get_remote_data(): array {
|
||||
$cached = get_site_transient( $this->cache_key );
|
||||
|
||||
// Verify HMAC signature if AUTH_SALT is defined and cache has signature.
|
||||
if ( false !== $cached && defined( 'AUTH_SALT' ) && '' !== AUTH_SALT ) {
|
||||
if ( is_array( $cached ) && isset( $cached['signature'], $cached['data'] ) ) {
|
||||
$expected_sig = hash_hmac( 'sha256', $this->cache_key . serialize( $cached['data'] ), AUTH_SALT );
|
||||
|
||||
if ( hash_equals( $expected_sig, $cached['signature'] ) ) {
|
||||
// Signature valid, return data.
|
||||
return is_array( $cached['data'] ) ? $cached['data'] : array();
|
||||
}
|
||||
|
||||
// Signature invalid, delete corrupted cache.
|
||||
delete_site_transient( $this->cache_key );
|
||||
$cached = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If no valid cache, fetch fresh data.
|
||||
if ( false === $cached ) {
|
||||
$remote = $this->fetch_json();
|
||||
|
||||
// Store with HMAC signature if AUTH_SALT is available.
|
||||
if ( defined( 'AUTH_SALT' ) && '' !== AUTH_SALT ) {
|
||||
$payload = array(
|
||||
'data' => $remote ?: array(),
|
||||
'timestamp' => time(),
|
||||
'signature' => hash_hmac( 'sha256', $this->cache_key . serialize( $remote ?: array() ), AUTH_SALT ),
|
||||
);
|
||||
set_site_transient( $this->cache_key, $payload, 6 * HOUR_IN_SECONDS );
|
||||
} else {
|
||||
// Fallback to standard caching.
|
||||
set_site_transient( $this->cache_key, $remote ?: array(), 6 * HOUR_IN_SECONDS );
|
||||
}
|
||||
|
||||
return is_array( $remote ) ? $remote : array();
|
||||
}
|
||||
|
||||
// Legacy cache format without signature (backward compatibility).
|
||||
return is_array( $cached ) ? $cached : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch JSON from remote URL.
|
||||
*
|
||||
* @return array Decoded JSON data.
|
||||
*/
|
||||
private function fetch_json(): array {
|
||||
$response = wp_remote_get(
|
||||
$this->json_url,
|
||||
array(
|
||||
'timeout' => 10,
|
||||
'headers' => array(
|
||||
'Accept' => 'application/json',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$code = (int) wp_remote_retrieve_response_code( $response );
|
||||
if ( $code < 200 || $code >= 300 ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$data = json_decode( $body, true );
|
||||
|
||||
return is_array( $data ) ? $data : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check compatibility.
|
||||
*
|
||||
* @param array $remote Remote data.
|
||||
*
|
||||
* @return bool True if compatible.
|
||||
*/
|
||||
private function is_compatible( array $remote ): bool {
|
||||
if ( ! empty( $remote['requires_php'] ) ) {
|
||||
if ( version_compare( PHP_VERSION, $remote['requires_php'], '<' ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $remote['requires'] ) ) {
|
||||
if ( version_compare( get_bloginfo( 'version' ), $remote['requires'], '<' ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle manual cache clear via URL parameter.
|
||||
*/
|
||||
public function handle_cache_clear(): void {
|
||||
// Check if this is a cache clear request first.
|
||||
$clear_cache = filter_input( INPUT_GET, 'robotstxt_clear_update_cache', FILTER_UNSAFE_RAW );
|
||||
if ( null === $clear_cache ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a cache clear request - now verify nonce.
|
||||
$nonce_raw = filter_input( INPUT_GET, '_wpnonce', FILTER_UNSAFE_RAW );
|
||||
$nonce = $nonce_raw ? sanitize_text_field( wp_unslash( $nonce_raw ) ) : '';
|
||||
|
||||
if ( ! wp_verify_nonce( $nonce, 'robotstxt_clear_update_cache' ) ) {
|
||||
wp_die( esc_html__( 'Security check failed', 'idrivee2-media-upload' ) );
|
||||
}
|
||||
|
||||
// Check permissions.
|
||||
if ( ! current_user_can( 'update_plugins' ) ) {
|
||||
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'idrivee2-media-upload' ) );
|
||||
}
|
||||
|
||||
$this->clear_cache();
|
||||
wp_safe_redirect( remove_query_arg( array( 'robotstxt_clear_update_cache', '_wpnonce' ) ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear update cache.
|
||||
*/
|
||||
public function clear_cache(): void {
|
||||
delete_site_transient( $this->cache_key );
|
||||
delete_site_transient( 'update_plugins' );
|
||||
}
|
||||
}
|
||||
}
|
||||
27
update.json
Normal file
27
update.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "iDrivee2 Media Upload",
|
||||
"slug": "idrivee2-media-upload",
|
||||
"version": "1.1.1",
|
||||
"download_url": "https://git.robotstxt.es/ROBOTSTXT/idrivee2-media-upload/releases/download/1.1.1/idrivee2-media-upload-1.1.1.zip",
|
||||
"requires": "6.8",
|
||||
"requires_php": "8.2",
|
||||
"tested": "6.9",
|
||||
"last_updated": "2026-02-04",
|
||||
"author": "Javier Casares",
|
||||
"author_profile": "https://www.javiercasares.com/",
|
||||
"homepage": "https://git.robotstxt.es/ROBOTSTXT/idrivee2-media-upload",
|
||||
"description": "Uploads media files to iDrivee2 (S3-compatible) with enterprise-grade security and logging.",
|
||||
"changelog": "<h3>1.1.1 - 2026-02-04</h3><ul><li><strong>Fixed:</strong> Deployment script now includes essential files (update.json, robotstxt-updater.php, readme.txt, changelog.txt)</li><li><strong>Improved:</strong> Production packages now contain all files required for automatic updates from Gitea</li></ul><h3>1.1.0 - 2026-02-04</h3><ul><li><strong>Changed:</strong> Added explicit PHP version requirement (>=8.2) to composer.json</li><li><strong>Changed:</strong> Updated update.json with correct plugin information</li><li><strong>Changed:</strong> Fixed Text Domain in robotstxt-updater.php to match plugin slug</li><li><strong>Fixed:</strong> Composer now validates PHP version during dependency installation</li><li><strong>Fixed:</strong> Plugin update system correctly identifies the plugin</li><li><strong>Fixed:</strong> Translations properly loaded for updater error messages</li><li><strong>Improved:</strong> All text domains now consistently use 'idrivee2-media-upload'</li></ul><h3>1.0.0 - 2026-02-03</h3><ul><li><strong>Release:</strong> First stable release</li><li><strong>Feature:</strong> Automatic upload of media files to iDrivee2 (S3-compatible storage)</li><li><strong>Feature:</strong> URL rewriting to serve media from CDN</li><li><strong>Feature:</strong> Local file deletion after successful upload</li><li><strong>Feature:</strong> Admin interface with connection and upload testing</li><li><strong>Security:</strong> Enterprise-grade security with nonce validation</li><li><strong>Architecture:</strong> Class-based modular architecture with dependency injection</li><li><strong>Testing:</strong> PHPUnit test structure and PHPStan static analysis</li><li><strong>Compatibility:</strong> WordPress 6.8+ and PHP 8.2+</li></ul>",
|
||||
"sections": {
|
||||
"description": "Uploads media files to iDrivee2 (S3-compatible) with enterprise-grade security and logging. The plugin intercepts WordPress media uploads, pushes files to an S3-compatible bucket, deletes local copies, and rewrites URLs to serve media from the CDN.",
|
||||
"changelog": "<h3>1.1.1 - 2026-02-04</h3><ul><li><strong>Fixed:</strong> Deployment script now includes essential files (update.json, robotstxt-updater.php, readme.txt, changelog.txt)</li><li><strong>Improved:</strong> Production packages now contain all files required for automatic updates from Gitea</li></ul><h3>1.1.0 - 2026-02-04</h3><ul><li><strong>Changed:</strong> Added explicit PHP version requirement (>=8.2) to composer.json</li><li><strong>Changed:</strong> Updated update.json with correct plugin information</li><li><strong>Changed:</strong> Fixed Text Domain in robotstxt-updater.php to match plugin slug</li><li><strong>Fixed:</strong> Composer now validates PHP version during dependency installation</li><li><strong>Fixed:</strong> Plugin update system correctly identifies the plugin</li><li><strong>Fixed:</strong> Translations properly loaded for updater error messages</li><li><strong>Improved:</strong> All text domains now consistently use 'idrivee2-media-upload'</li></ul><h3>1.0.0 - 2026-02-03</h3><ul><li><strong>Release:</strong> First stable release</li><li><strong>Feature:</strong> Automatic upload of media files to iDrivee2 (S3-compatible storage)</li><li><strong>Feature:</strong> URL rewriting to serve media from CDN</li><li><strong>Feature:</strong> Local file deletion after successful upload</li><li><strong>Feature:</strong> Admin interface with connection and upload testing</li><li><strong>Security:</strong> Enterprise-grade security with nonce validation</li><li><strong>Architecture:</strong> Class-based modular architecture with dependency injection</li><li><strong>Testing:</strong> PHPUnit test structure and PHPStan static analysis</li><li><strong>Compatibility:</strong> WordPress 6.8+ and PHP 8.2+</li></ul>"
|
||||
},
|
||||
"banners": {
|
||||
"low": "",
|
||||
"high": ""
|
||||
},
|
||||
"icons": {
|
||||
"1x": "",
|
||||
"2x": ""
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue