fluentcart-downloads-storage
Implements and audits FluentCart downloadable products, entitlement checks, signed delivery URLs, download limits/expiry logs, Local/S3 storage, custom storage drivers, and Pro R2 behavior. Use when working with ProductDownload, OrderDownloadPermission, generateDownloadFileLink()
Install
npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/fluentcart/fluentcart-downloads-storage
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
git clone https://github.com/Lonsdale201/wp-agent-skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
FluentCart downloads and storage
Separate file metadata, commercial entitlement, signed delivery, and download accounting. Possession of a path, download ID, or signed URL must not create a new entitlement.
Read download-delivery.md before generating links, changing access rules, or implementing a driver.
Preserve the delivery chain
Use ProductDownload records to map product/variation availability to driver metadata. Use OrdergetDownloads() or the customer-profile flow to obtain entitled files. Generate delivery links with HelpergenerateDownloadFileLink($download, $orderId).
For customer delivery always include the qualifying order ID. The helper signs download_identifier, valid_till, and order_id. FileDownloader then validates signature/time, successful payment, a matching product post on one supplied order, subscription access validity, and the final can_be_downloaded filter before dispatching to the storage driver.
Do not:
- expose Local file paths, S3/R2 keys, bucket names, or raw file_url values;
- build signed query strings manually;
- use the admin preview's order-less link as a customer entitlement link;
- cache signed URLs beyond their validity;
- assume a successful order grants every variation's files.
Do not assume the active route enforces limits or login
The customer-profile listing is login/customer scoped before it generates the URL. The resulting 1.6.0 signed URL is bearer authorization: FileDownloader does not re-check the current WP user and does not enforce the configured download_limit/download_expiry or update fct_order_download_permissions.
CustomerHelper contains limit/expiry/accounting code and DownloadService registers a fluent_cart/before_download_check_permission_and_store_log listener, but the active FileDownloader path does not emit that action in the tested source. Treat OrderDownloadPermission accounting as unwired for this route until a runtime test proves otherwise.
If the addon promises download limits, a customer-bound link, or single-use delivery, implement an addon-owned atomic claim before issuing/streaming the file and then delegate to the storage layer. Protect concurrent clicks and do not increment a count merely for rendering a link. Re-audit core after upgrade so enforcement is not accidentally duplicated.
Use fluent_cart/product_download/can_be_downloaded only to further constrain or explicitly extend a verified order context. Inspect orders and download from the payload; never return true for an unbound public identifier.
Extend storage drivers
Extend BaseStorageDriver, provide a settings class/fields, hiddenSettingKeys, driver implementation, connection verification, signed URL/download behavior, and bucket support if required. Attach the registration listener by fluentcart_loaded and call the driver instance's init() during fluent_cart/register_storage_drivers. The action runs on init priority 9, before fluent_cart/init, so registering its listener from fluent_cart/init is too late.
- Keep credentials in hidden settings and exclude them from REST/UI responses.
- Sanitize settings and verify connectivity without leaking provider errors.
- Enforce least-privilege bucket policy and private objects.
- Set a short provider URL expiry and validate filenames/content disposition.
- Prevent path traversal and cross-bucket/object access.
- Make upload/delete idempotent and distinguish missing from unauthorized.
Free 1.6.0 ships Local and S3. Cloudflare R2 is a Pro driver; Free only exposes a promo descriptor.
Subscription and license gates
Subscription downloads depend on Subscription::hasAccessValidity(), not merely the existence of a subscription row. Pro licensing also filters downloads when license validity applies. Compose restrictions; do not replace another module's false decision with true unless the addon deliberately owns that entitlement.
Test matrix
Test paid/unpaid/refunded order, signed-link reuse without login, wrong product/ variation, expired signature, tampered query, the source-confirmed absence or presence of core limit/expiry accounting, addon limit concurrency, active/ expired subscription, valid/expired Pro license, missing object, disabled/ misconfigured driver, filename injection, and cached URL after expiry.
Cross-references
- Use fluentcart-products-inventory for file-to-variation assignment.
- Use fluentcart-subscriptions-renewals for access validity.
- Use fluentcart-licensing-pro for licensed software delivery.
References
- Verified Free source paths:
- fluent-cart/app/Models/ProductDownload.php
- fluent-cart/app/Models/OrderDownloadPermission.php
- fluent-cart/app/Models/Order.php
- fluent-cart/app/Http/Controllers/WebController/FileDownloader.php
- fluent-cart/app/Services/FileSystem/DownloadService.php
- fluent-cart/app/Helpers/Helper.php
- fluent-cart/app/Helpers/CustomerHelper.php
- fluent-cart/app/Hooks/Handlers/GlobalStorageHandler.php
- fluent-cart/app/Modules/StorageDrivers/
- Verified Pro source path:
- fluent-cart-pro/app/Modules/StorageDrivers/R2/
Files (wp-agent-skills)
-
agents
-
openai.yaml 305 B
interface: display_name: "FluentCart downloads and storage" short_description: "Protect file entitlement, signed delivery, and drivers" default_prompt: "Use $fluentcart-downloads-storage to implement or audit this digital delivery flow across entitlement, signed URLs, limits, and private storage."
-
-
references
-
download-delivery.md 2.8 KB
# FluentCart 1.6.0 download delivery ## Data layers | Layer | Purpose | |---|---| | ProductDownload | File metadata, driver, path/key, variation mapping, limits | | Order/Subscription/License | Commercial entitlement | | Signed FluentCart URL | Short-lived delivery authorization for named context | | Storage driver | Streams or redirects to the private object | | OrderDownloadPermission | Intended customer/order/file count and expiry accounting; not wired into the active signed route in 1.6.0 | ## Signed delivery flow ~~~text qualifying order/customer page -> select downloads for product and variation -> generateDownloadFileLink(download, order ID) -> signed site URL with validity -> FileDownloader validates signature and time -> reload download and qualifying paid order -> evaluate subscription/license/addon filter -> driver streams file or issues provider-signed redirect ~~~ Default FluentCart link validity is 60 minutes and is filterable through fluent_cart/download_link_validity_in_minutes. S3/provider URL expiry has the separate fluent_cart/download_expiration_minutes filter. ## Source-verified 1.6.0 enforcement boundary The customer-profile controller requires login, scopes order items to the current Customer, filters downloadable variation mappings, and then generates an order-bound link. After generation, the URL is a bearer credential until its signature expires. FileDownloader checks the signed timestamp, download identifier, successful order payment, matching product post_id, subscription validity, and the can_be_downloaded filter. It does not re-check WP-user ownership, bind the file to a concrete purchased variation, apply ProductDownload limit/expiry settings, or update OrderDownloadPermission. CustomerHelper::checkDownloadPermissionAndStoreLog() contains those additional checks, and DownloadService registers it on fluent_cart/before_download_check_permission_and_store_log. No active emitter for that action was found in the tested tree. An addon requiring those promises must add atomic enforcement and retest the core route after upgrades. ## Driver contract BaseStorageDriver manages: - metadata and settings routes; - settings sanitization and hidden keys; - active status; - optional buckets; - connection verification; - driver discovery via fluent_cart/storage/get_global_storage_drivers. The driver class returned by getDriverClass() performs actual file operations. Never expose the driver instance or hidden credentials to public clients. ## Security checks 1. normalize and confine local paths; 2. reject directory traversal and null bytes; 3. use private object ACLs; 4. bind signed URLs to the minimum object/context; 5. validate response filenames; 6. avoid open redirects; 7. do not reveal whether a foreign object exists; 8. log only identifiers and redacted provider error codes.
-
-
SKILL.md 5.8 KB
--- name: fluentcart-downloads-storage description: >- Implements and audits FluentCart downloadable products, entitlement checks, signed delivery URLs, download limits/expiry logs, Local/S3 storage, custom storage drivers, and Pro R2 behavior. Use when working with ProductDownload, OrderDownloadPermission, generateDownloadFileLink(), FileDownloader, fluent_cart/product_download/can_be_downloaded, fluent_cart/register_storage_drivers, customer download pages, subscription- gated files, private object storage, or preventing raw file-path disclosure. metadata: wp-skills-author: "Soczó Kristóf" wp-skills-contact: "mailto:lonsdale201@hotmail.com" wp-skills-plugin: "fluent-cart" wp-skills-plugin-version-tested: "1.6.0" wp-skills-wp-version-tested: "7.0.2" wp-skills-php-min: "7.4" wp-skills-last-updated: "2026-08-06" --- # FluentCart downloads and storage Separate file metadata, commercial entitlement, signed delivery, and download accounting. Possession of a path, download ID, or signed URL must not create a new entitlement. Read [download-delivery.md](references/download-delivery.md) before generating links, changing access rules, or implementing a driver. ## Preserve the delivery chain Use ProductDownload records to map product/variation availability to driver metadata. Use Order::getDownloads() or the customer-profile flow to obtain entitled files. Generate delivery links with Helper::generateDownloadFileLink($download, $orderId). For customer delivery always include the qualifying order ID. The helper signs download_identifier, valid_till, and order_id. FileDownloader then validates signature/time, successful payment, a matching product post on one supplied order, subscription access validity, and the final can_be_downloaded filter before dispatching to the storage driver. Do not: - expose Local file paths, S3/R2 keys, bucket names, or raw file_url values; - build signed query strings manually; - use the admin preview's order-less link as a customer entitlement link; - cache signed URLs beyond their validity; - assume a successful order grants every variation's files. ## Do not assume the active route enforces limits or login The customer-profile listing is login/customer scoped before it generates the URL. The resulting 1.6.0 signed URL is bearer authorization: FileDownloader does not re-check the current WP user and does not enforce the configured download_limit/download_expiry or update fct_order_download_permissions. CustomerHelper contains limit/expiry/accounting code and DownloadService registers a fluent_cart/before_download_check_permission_and_store_log listener, but the active FileDownloader path does not emit that action in the tested source. Treat OrderDownloadPermission accounting as unwired for this route until a runtime test proves otherwise. If the addon promises download limits, a customer-bound link, or single-use delivery, implement an addon-owned atomic claim before issuing/streaming the file and then delegate to the storage layer. Protect concurrent clicks and do not increment a count merely for rendering a link. Re-audit core after upgrade so enforcement is not accidentally duplicated. Use fluent_cart/product_download/can_be_downloaded only to further constrain or explicitly extend a verified order context. Inspect orders and download from the payload; never return true for an unbound public identifier. ## Extend storage drivers Extend BaseStorageDriver, provide a settings class/fields, hiddenSettingKeys, driver implementation, connection verification, signed URL/download behavior, and bucket support if required. Attach the registration listener by fluentcart_loaded and call the driver instance's init() during fluent_cart/register_storage_drivers. The action runs on init priority 9, before fluent_cart/init, so registering its listener from fluent_cart/init is too late. - Keep credentials in hidden settings and exclude them from REST/UI responses. - Sanitize settings and verify connectivity without leaking provider errors. - Enforce least-privilege bucket policy and private objects. - Set a short provider URL expiry and validate filenames/content disposition. - Prevent path traversal and cross-bucket/object access. - Make upload/delete idempotent and distinguish missing from unauthorized. Free 1.6.0 ships Local and S3. Cloudflare R2 is a Pro driver; Free only exposes a promo descriptor. ## Subscription and license gates Subscription downloads depend on Subscription::hasAccessValidity(), not merely the existence of a subscription row. Pro licensing also filters downloads when license validity applies. Compose restrictions; do not replace another module's false decision with true unless the addon deliberately owns that entitlement. ## Test matrix Test paid/unpaid/refunded order, signed-link reuse without login, wrong product/ variation, expired signature, tampered query, the source-confirmed absence or presence of core limit/expiry accounting, addon limit concurrency, active/ expired subscription, valid/expired Pro license, missing object, disabled/ misconfigured driver, filename injection, and cached URL after expiry. ## Cross-references - Use fluentcart-products-inventory for file-to-variation assignment. - Use fluentcart-subscriptions-renewals for access validity. - Use fluentcart-licensing-pro for licensed software delivery. ## References - Verified Free source paths: - fluent-cart/app/Models/ProductDownload.php - fluent-cart/app/Models/OrderDownloadPermission.php - fluent-cart/app/Models/Order.php - fluent-cart/app/Http/Controllers/WebController/FileDownloader.php - fluent-cart/app/Services/FileSystem/DownloadService.php - fluent-cart/app/Helpers/Helper.php - fluent-cart/app/Helpers/CustomerHelper.php - fluent-cart/app/Hooks/Handlers/GlobalStorageHandler.php - fluent-cart/app/Modules/StorageDrivers/ - Verified Pro source path: - fluent-cart-pro/app/Modules/StorageDrivers/R2/
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.