=== BuildsByLuke Upload Vault – Secure File Uploads for Gravity Forms ===
Contributors: lukeaxiomflow
Tags: gravity forms, file upload, security, privacy, access control
Requires at least: 6.2
Tested up to: 7.1
Stable tag: 1.1.1
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Secure Gravity Forms file uploads: see what a leaked URL exposes, then lock it down with deny rules and a capability-checked download proxy.

== Description ==

Files people upload through your Gravity Forms — CVs, contracts, ID documents, medical intake forms — are stored in a folder whose only protection is that its name is hard to guess. Gravity Forms' own documentation says uploads are safe *"as long as the folder name for that form is not shared publicly."*

But upload URLs get shared constantly: they sit in notification emails, entry exports, browser histories, server logs and referrer headers. Anyone who ever obtains such a URL can download the file — no login, no permission check, forever.

**Upload Vault shows you what your server actually serves, then helps you restrict it.**

= Free — audit and protect =

* **Exposure audit** — Upload Vault asks your own server for your own upload URLs (a loopback request) and reports, as a served fact, whether a stranger with the URL would receive the file. It also checks whether upload folders expose a browsable directory listing.
* **Protection** — one click writes deny rules (a marker block in the upload folder's `.htaccess`, safely alongside anything already there) plus anti-listing placeholder files. On servers that ignore `.htaccess` (nginx, IIS) Upload Vault shows you the exact server snippet and keeps reporting honestly until direct requests are actually refused.
* **Downloads keep working** — files are served through a capability-checked proxy. Links in entry views and notification emails are rewritten to proxy links automatically, so protecting uploads breaks nothing you rely on.
* **Honest verdicts** — the audit never claims "protected" unless the server was observed refusing direct requests. If your site cannot loopback-request itself, Upload Vault says so instead of guessing.
* **Watchdog** — a scheduled re-audit on the cadence you choose (hourly, twice daily, daily or weekly) with an email when a folder becomes newly exposed, plus a Site Health test.
* **WP-CLI and REST, ungated** — `wp upload-vault audit --format=json` and a read-only `upload-vault/v1/status` endpoint (administrators only) for your own dashboards, monitoring and fleet tooling.
* Forms whose uploads are meant to be public (e.g. images you embed) can be left open per folder.

= Pro =

* Expiring signed share links (1 hour to 30 days, optional download cap, revocable) — hand a client one file without creating a WordPress user.
* Per-form access rules: choose which roles may download each form's files.
* Download audit trail — who downloaded what, when, from which IP, allowed or denied — with CSV export.
* Retention auto-purge: per-form maximum file age with preview (helpful for data-minimisation policies).
* Slack & webhook alerts the moment an audit finds new exposure.

= Honest limitations =

* On nginx/IIS the written rules cannot take effect by themselves — Upload Vault gives you the exact snippet and verifies once it's in place. Until then it reports "installed, NOT verified", never "protected".
* If your uploads are offloaded to a CDN or external storage, those copies are outside this plugin's reach. When an upload URL on your own host redirects to one of them, Upload Vault stops at the redirect instead of following it, and reports that folder as unknown rather than claiming it is either exposed or protected.
* A URL that already leaked before protection cannot be un-leaked; protection stops the server serving it from now on.
* Some hosts block loopback requests; the audit then reports itself impaired rather than guessing.
* No plugin can guarantee security or make a site compliant with any regulation. Upload Vault helps you see and restrict access to Gravity Forms uploads; responsibility for the site remains with its administrators.

Upload Vault is an independent product of Builds By Luke and is **not affiliated with, endorsed by, or sponsored by Rocketgenius, Inc. ("Gravity Forms")**. It also runs without Gravity Forms active — uploaded files outlive the form plugin, so you can audit and protect a directory left behind by a deactivated install.

== External services ==

**The audit itself contacts nothing external.** It sends HTTP requests from your server to your server's own public URLs (loopback) to observe what it actually serves. Redirects are not followed by the HTTP layer: Upload Vault resolves each hop itself and re-checks the destination against your site address before requesting it, so a URL of yours that redirects off-site is stopped and reported rather than followed. File contents never leave your site.

**Freemius (freemius.com), who sell and license the Pro version**

Freemius is contacted in four situations. Every one of them is something you click. It is never contacted in the background.

1. **If you opt in on the welcome screen** (or start a trial / activate a licence). Sent to api.freemius.com: your site URL, your WordPress and PHP versions, and the email address of the account you activate with. Skipping the opt-in is a first-class choice and the plugin is fully functional without it.
2. **If you open the "Upgrade" page** under the plugin's menu. Your own server (not your browser) asks api.freemius.com for current plan prices, sending your site URL. This happens whoever you are, including if you skipped the opt-in — but only when you open that page. The page itself loads no third-party scripts; everything it renders is served from this plugin's own folder. The payment SDK's bundled pricing script used to inject Google Analytics and a remote checkout script into wp-admin on that page; this build removes both, along with the SDK's remaining remote references (all modifications are listed under "Source code" below).
3. **If you open the "Contact Us" page**, which is Freemius's hosted support form (wp.freemius.com). The link carries your site URL and your WordPress login URL so the form knows which site you are writing about.
4. **If you click a plan to buy**, you go to Freemius's hosted checkout (checkout.freemius.com). It receives your site URL, site name, WordPress and PHP versions, and your WordPress administrator email address (pre-filled, sent whether or not you complete the purchase). Freemius is the merchant of record. Their checkout page loads its own third-party scripts (at the time of writing: Stripe, PayPal, Google Tag Manager, and Freemius's own assets); we do not control that list. If you never click a plan, none of it loads.

Terms: https://freemius.com/terms/ — Privacy: https://freemius.com/privacy/

Installing, activating, skipping the opt-in, every scheduled audit, using every screen, deactivating (the SDK's deactivation-feedback dialog is switched off in this build, so deactivation is one click and sends nothing), and WordPress's update cycle all complete without contacting Freemius at all. Free updates come from WordPress.org like any other plugin.

**Slack or your own webhook (Pro, optional)**
If you configure a Slack or generic webhook URL, Upload Vault posts a short alert (site URL, verdict, affected folder names, timestamp — never file contents) to that URL when an audit finds new exposure. Nothing is sent until you enter a URL yourself. See the [Slack terms](https://slack.com/terms-of-service) and [privacy policy](https://slack.com/trust/privacy/privacy-policy) if you use a Slack webhook.

== Source code ==

This plugin's own PHP and JavaScript are unminified and readable in the plugin folder. The one exception is the third-party payment SDK in `vendor/freemius/`, which ships pre-minified; its source and build tooling are public:

* Freemius WordPress SDK: https://github.com/Freemius/wordpress-sdk
* The pricing screen at `vendor/freemius/assets/js/pricing/freemius-pricing.js`: https://github.com/Freemius/pricing-page

This plugin ships four deliberate modifications to that SDK (all in `assets/js/pricing/freemius-pricing.js`, all removing remote references from wp-admin): the `appendScripts()` method is emptied (it injected Google Analytics + checkout.js), the GA pageview tracker is stubbed out, the remote loader GIF is replaced with an inline data-URI, and testimonial photos are forced to the bundled placeholder. Three carry an "Upload Vault:" comment at the patch site.

== Installation ==

1. Install and activate the plugin.
2. Open **Upload Vault → Exposure Audit** and run the first audit.
3. If folders are exposed, click **Protect uploads**, then re-check the verdict — it flips to Protected only when your server was observed refusing direct requests (on nginx/IIS, add the shown snippet first).

== Frequently Asked Questions ==

= Does it need Gravity Forms to be active? =

No. The audit, protection and proxy work on the `gravity_forms` upload directory itself, which outlives the form plugin. With Gravity Forms active you additionally get form titles and automatic link rewriting in entry views and notification emails.

= It says "Rules installed, NOT verified" — is that a bug? =

No — that's the plugin being honest. Your server (typically nginx or IIS) ignores `.htaccess`, so the deny rules can't take effect on their own. The audit page shows the exact server snippet; once it's in place and the server refuses direct requests, the verdict flips to Protected.

= Will protecting uploads break the links my team already uses? =

Entry views and new notification emails switch to proxy links automatically (when Gravity Forms is active). Direct URLs in old emails will stop working for strangers — that is the point — but any logged-in user with entry access gets the same file through the Files screen or entry view.

= Does it modify or move my uploaded files? =

No. It writes only: a marker block in the upload folder's `.htaccess` (removed on unprotect/uninstall), empty `index.html` placeholders to stop directory listings, and its own database table. Files are never moved, renamed or altered. The Pro retention feature deletes files only if you explicitly enable it and set per-form limits.

= What happens on uninstall? =

Upload Vault removes its deny rules (restoring Gravity Forms' stock behaviour), drops its database tables (`uvgf_files`, and `uvgf_shares`/`uvgf_log` if Pro was used) and deletes its options. The empty `index.html` placeholders are left in place (they are inert).

= Is this plugin an official Gravity Forms add-on? =

No. Upload Vault is an independent product and is not affiliated with, endorsed by, or sponsored by Rocketgenius, Inc.

== Screenshots ==

1. The Exposure Audit — a served-fact verdict per form folder, with direct-access and listing checks.
2. The Files screen — every upload in the registry with capability-checked proxy downloads.
3. Settings — the audit cadence (every choice is free), alert email, link rewriting, and per-folder exceptions.

== Changelog ==

= 1.1.1 =
* Initial public release.

== Upgrade Notice ==

= 1.1.1 =
First public release.
