=== SRI Shield ===
Contributors: spinxdigitaldev
Tags: security, sri, subresource integrity, hardening, script integrity
Requires at least: 7.0
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 1.2.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Add Subresource Integrity hashes to enqueued scripts and styles, approve changed files before they are trusted, and scan pages for missing SRI.

== Description ==

=== 🛡️ Subresource Integrity for Your Enqueued Assets ===

**SRI Shield** records a cryptographic hash (an SRI hash) for each enqueued script and stylesheet the first time it is served, and adds the `integrity` and `crossorigin` attributes to its tag. A visitor's browser compares each file it downloads with that hash and refuses to use a file whose content does not match.

**Changed files wait for your approval.** When a protected file's content changes — after a theme, plugin, or WordPress update, or because the file was modified — SRI Shield keeps serving the previously trusted hash and flags the change for review. Browsers refuse the changed file until an administrator compares the trusted and proposed hashes and either approves the new hash or keeps the trusted one. SRI Shield never re-trusts a changed file on its own.

**What SRI does and does not do.** SRI confirms that a file's content matches a hash; it does not judge whether a file is safe. The first hash for each file is taken from the content the file has at that moment, so a file that was already compromised when it was first hashed is not detected. Generating hashes automatically is not, by itself, protection against malicious changes — that is why changes require review.

=== ✨ Why Choose SRI Shield? ===

* **Automatic Enrollment** — Enqueued scripts and stylesheets receive an integrity hash the first time they are served.
* **Review Before Trust** — A changed file keeps its trusted hash until you approve the new one.
* **Local and External Coverage** — Files from your theme and plugins, and files loaded from CDNs and other remote services that your server can fetch.
* **Page-by-Page Verification** — The scanner checks every script and stylesheet tag on every scanned page.
* **Alerts** — Branded email reports when a scan finds a problem.
* **Invisible to Visitors** — No new buttons, messages, or layout changes.

=== ⚙️ How It Works ===

1. **Enroll** — The first time your site serves an enqueued script or stylesheet, SRI Shield hashes its current content and stores that hash as trusted.
2. **Protect** — The `integrity` and `crossorigin` attributes are added to the file's tag.
3. **Verify** — Each visitor's browser compares the file it received against the hash and blocks it if they do not match.
4. **Detect changes** — With Change Detection on, SRI Shield notices when a local file's modification time or size changes and hashes it again. Scans and re-checks compare every stored hash with freshly fetched content, including remote files.
5. **Review** — Changed files are listed under `Hash Records > Changes Awaiting Review` with the trusted and proposed hashes side by side. Approve the new hash once you have confirmed the change is expected, or keep the trusted hash.
6. **Monitor** — Run the scanner to check your pages. If it finds a problem, it can alert you by email.

=== 🧩 Features at a Glance ===

* **Automatic SRI Enrollment** — Generates SRI hashes for enqueued CSS and JavaScript the first time they are served and injects the `integrity` and `crossorigin` attributes through WordPress loader hooks.

* **Change Review** — When a protected file's content changes, the trusted hash stays in place and the change waits for an administrator. Approving re-fetches the file and succeeds only if it still produces the exact hash you reviewed. Every approval and dismissal is recorded in the Logs.

* **Local, CDN & Remote File Support** — Covers assets hosted on your own site and assets hosted on CDNs and other remote services, when they are accessible from your server.

* **Three Hash Algorithms** — Choose SHA-256, SHA-384, or SHA-512. SHA-384 is the default and is recommended for almost all sites. Changing the algorithm re-encodes a stored hash only after the file's content is confirmed unchanged.

* **Change Detection** — Optionally checks local files for changes (modification time and size) as pages load, so changed files are flagged without waiting for a scan.

* **Stored Hashes** — Hashes are stored in a database table (with a short-lived cache for remote files) and reused, so files are not re-hashed on every visit.

* **Website Scanner** — Fetches your home page and recent posts and pages and analyzes the HTML your server returns. Every script and stylesheet tag on every page is checked on its own, so a file that is protected on one page and unprotected on another is reported on the page where it is unprotected. Results: Valid, Missing, Invalid attribute, Hash mismatch, Crossorigin missing, or Unreachable. Scan depth is adjustable from 1 to 200 pages per run (default 25).

* **Email Alerts** — Sends a responsive HTML email when a scan finds a problem, to the address you choose (your site admin email by default).

* **Hash Records** — Every enrolled file with its URL, type, algorithm, trusted integrity hash, status, and last-updated time, plus a Copy button for the hash and the list of changes awaiting review.

* **Hash an External URL** — Enter the address of an external file to hash it on demand. If the URL is already stored, it is re-checked instead and any change waits for review.

* **Exclusions** — Skip specific assets by handle, or exclude and re-include individual files from Hash Records.

* **Activity Logs** — A record of plugin activity, including every hash approval and dismissal, with export, plus optional structured debug logging.

* **Maintenance Tools** — Reset Cache (clears cached lookups and failed-asset records; trusted hashes and pending reviews are kept) and Re-check Hashes (hashes every registered asset again; changes are flagged for review).

* **Optional Admin Coverage** — Extend integrity attributes to the WordPress admin area as well as the public site.

* **Multisite Ready** — Multisite-compatible activation, and it cleans up after itself on uninstall.

* **Developer Hooks** — Filters and actions to override the algorithm per handle, exclude handles dynamically, change the `crossorigin` attribute, add scan URLs, customize alert emails, and react to scan, change, and approval events.

=== 🔍 Scan Results ===

Run a scan and every script and stylesheet on your checked pages, plus every stored hash record, gets a result:

* **Valid** — The integrity attribute is valid and matches the content currently served.
* **Missing** — The file is served without an integrity attribute on that page.
* **Invalid attribute** — The integrity attribute is empty or contains no valid hash, so browsers load the file without an integrity check.
* **Hash mismatch** — The content no longer matches the declared or trusted hash, so browsers refuse it. This can come from a legitimate update or from a modification. For a stored record, the change is listed under Hash Records for review.
* **Crossorigin missing** — A cross-origin file has a correct hash but no `crossorigin` attribute, so browsers cannot verify it and refuse to load it.
* **Unreachable** — The file could not be fetched to be checked. Its trusted hash, if any, is kept.

**Scanner scope:** the scanner analyzes the HTML your server returns. It does not run JavaScript, so scripts and stylesheets added at runtime — for example by tag managers, consent tools, or lazy loaders — are not detected. It also cannot check whether a remote host sends the CORS headers that cross-origin SRI requires.

The Scanner keeps a short history of recent scans, and stored results can be cleared whenever you like.

=== 📧 Alerts That Match Your Brand ===

Alert emails are fully brandable from the Notifications screen:

* **Logo** — shown at the top of the email (your site name is used if none is set).
* **Accent Color** — the header and button color (default blue, #2563EB).
* **Header Title** — the headline of the email (default "SRI Shield Security Alert").
* **Footer Text** — small print at the bottom (default: your site name).
* **Recipient** — the address that receives alerts (default: your site admin email).
* **Send Test Email** — preview the design and confirm delivery before you rely on alerts.

=== 🔐 Built for Administrators ===

SRI Shield is an administrative tool. Every screen, setting, and review action is restricted to users who can manage site options — the Administrator role on a standard WordPress site. Editors, Authors, Contributors, Subscribers, and visitors never see the plugin's controls and cannot approve hash changes.

=== 🔒 Privacy & External Services ===

SRI Shield runs inside your own WordPress site. To do its job, it makes the following requests from your server:

* **Your own pages** — the Scanner requests pages of your own website to check the files they load.
* **Files your site already uses** — to hash or verify a remote script or stylesheet (for example one hosted on a CDN), the plugin requests that file from its own address using a secure HTTP request. This is the same file your visitors' browsers already download.
* **Alert emails** — notifications are sent using your site's own email setup, to the recipient you choose.

=== 💡 Best For ===

* Sites that load scripts or styles from CDNs and other third-party services.
* Site owners who want to be told when a protected file changes, and to decide whether to trust the change.
* Agencies and teams that need an auditable record of enrolled files and approved changes.
* Developers who want hooks to tune hashing, scanning, and alert emails.

== Installation ==

= WordPress Admin Method =
1. In your WordPress admin, go to `Plugins > Add New`.
2. Search for `SRI Shield`.
3. Click `Install Now`, then `Activate`.
4. Open `SRI Shield` from the WordPress admin sidebar.

= Manual Method =
1. Upload the `sri-shield` folder to the `/wp-content/plugins/` directory.
2. Open the `Plugins` screen in WordPress.
3. Locate `SRI Shield` and click `Activate`.

= After Activation =
1. Open `SRI Shield > Dashboard` and confirm the status badge reads "Protection Active".
2. Configure the hash algorithm, exclusions, and change detection, then save your settings. SHA-384 is the default and is recommended for most sites.
3. Open `Scanner` and run your first scan to check your pages.
4. Open `Notifications`, enable email alerts, and send a test email.

Hashes are recorded as your pages are viewed. After you update a theme, plugin, or WordPress itself, open `Hash Records` and review any changed files: browsers block a changed file until you approve its new hash.

== Frequently Asked Questions ==

= What is Subresource Integrity (SRI)? =

It is a browser security feature. Each script or stylesheet tag carries a hash of the file's expected content. Before using the file, the browser checks that its content still matches the hash, and blocks it if it does not.

= Does SRI Shield guarantee that my files are safe? =

No. SRI confirms that a file matches a hash; it does not decide whether the file is trustworthy. SRI Shield trusts each file's content the first time it is hashed and asks you to approve every later change. Review changes before approving them, and keep using your other security measures.

= Do I need technical knowledge to use SRI Shield? =

No. Every feature is available through settings screens in your WordPress dashboard, and the plugin works with safe defaults.

= Which files does SRI Shield protect? =

CSS and JavaScript assets that are enqueued through WordPress, whether they are local, on a CDN, or on another remote service. Scripts and stylesheets added to pages in other ways (hard-coded tags or JavaScript injection) are not given integrity attributes.

= Does the scanner find scripts loaded by JavaScript? =

No. The scanner analyzes the HTML your server returns and does not run JavaScript, so assets injected at runtime are not detected.

= Does this work with CDN assets? =

Yes. SRI Shield can hash remote assets via secure HTTP requests when the URL is accessible from your server. If a file cannot be reached or verified, it is left without an integrity attribute rather than causing an error. Cross-origin SRI also requires the CDN to send CORS headers.

= Will this process wp-admin assets? =

Only when the Process Admin Assets setting is enabled. It is off by default.

= Will my visitors notice any difference? =

Not while files are unchanged. If a protected file changes and the change has not been approved yet, browsers refuse that file, which can affect the features that depend on it until you review the change.

= Will it slow down my site? =

Hashes are stored and reused, so files are not re-hashed on every visit. A local file is hashed again only when its modification time or size changes.

= Which hash algorithm should I choose? =

SHA-384. It is strong, widely supported, and the default. SHA-256 and SHA-512 are also available if you have a specific reason to change it.

= Can I re-hash all assets? =

Use `Re-check Hashes` on the Dashboard. New assets are enrolled, unchanged assets keep their hash, and changed assets are flagged for review. It never replaces a trusted hash.

= What does a "Hash mismatch" result mean? =

On a page, it means the integrity attribute does not match the content currently served, so browsers refuse the file. For a stored hash record, it means the file changed after its hash was trusted. The change appears under `Hash Records > Changes Awaiting Review`. If you made or expected the change (for example by updating the plugin that ships the file), approve the new hash. If you did not expect it, treat it as a possible security issue and investigate before approving anything.

= A script or style stopped working after an update. What should I do? =

The file probably changed, and browsers are refusing it because its trusted hash no longer matches. Open `Hash Records`, review the change, and approve the new hash if the change is expected. If you need the file to load before you can review it, Exclude it temporarily (it then loads without an integrity attribute) and re-include it after review.

= What does approving a change do? =

SRI Shield fetches the file again and confirms that its content still produces the proposed hash you reviewed; if not, nothing is approved. Approval then makes the new hash trusted. It records that you accept the new content — it does not verify that the content is safe.

= An external or CDN file shows an "Error" status. What does that mean? =

The file could not be reached when it was first hashed. Confirm the file's address is correct and the service is available, then use Re-check. If it still cannot be verified, exclude it.

= I installed a new theme or plugin. Do I need to do anything? =

New files are enrolled automatically the first time they are served. Updated versions of files that were already enrolled need your review on the Hash Records screen. Run a scan to confirm the results.

= Why am I not receiving alert emails? =

Check that Email Notifications is switched on, that the recipient address is valid, and that your site is able to send email. Use `Send Test Email` on the Notifications screen to confirm delivery.

= Who can access SRI Shield? =

Only Administrators. The plugin's menus are hidden from all other roles, and hash changes can only be approved by users who can manage site options.

= Can I undo an exclusion? =

Yes. Any excluded file can be re-included at any time from the Hash Records screen.

= How do I reset everything? =

`Reset Cache` clears cached lookups and failed-asset records so they are retried. Trusted hashes and pending reviews are kept on purpose: deleting them would let the next page load trust the current content of a changed file without review. To stop adding an integrity attribute to a file, exclude it. Deleting the plugin removes all of its data.

= What happens if I deactivate or delete the plugin? =

When you deactivate it, integrity attributes are no longer added and your files are served normally. When you delete it, the plugin runs its uninstall cleanup, which removes its database tables and options.

= Does it work on a Multisite network? =

Yes. SRI Shield supports Multisite activation, works on each site in the network individually, and cleans up after itself if removed.

= Can developers extend SRI Shield? =

Yes. See the "Developer Filters and Actions" section for the available filters and actions.

= How do I get support? =

When opening a support request, please include:

* What you were doing when the issue occurred
* The exact wording of any message or status shown by the plugin
* Any relevant file address shown on the Hash Records or Scanner screens
* Whether you recently changed your theme, plugins, or site files

== Screenshots ==

1. Dashboard with protection status, hash cache statistics, and an overview of key features
2. General Settings for enabling SRI, the default hash algorithm, excluded asset handles, auto regenerate, and scanner depth
3. Maintenance Tools to reset the hash cache or regenerate every integrity hash
4. Scanner screen with the latest scan summary and per-asset results for valid, missing, tampered, and unreachable assets
5. Hash Records screen to hash an external CDN URL and manage every stored integrity hash
6. Notifications screen with tamper alert emails, email branding options, and Send Test Email
7. Logs screen with activity filtered by level, search, and CSV export

== Changelog ==

= 1.2.0 =
* Security: Changed assets are no longer re-hashed and trusted automatically. When a protected file's content changes, its previously trusted hash keeps being served and the change waits for administrator review under Hash Records > Changes Awaiting Review.
* Security: Approving a change requires the manage_options capability, a valid nonce, an explicit confirmation, and a fresh fetch whose content still produces the reviewed hash. Approvals and dismissals are logged.
* Security: Reset Cache, Re-check Hashes, Hash an External URL, the per-record Re-check button, hash-algorithm changes, record pruning, and fetch errors can no longer replace or remove a trusted hash.
* Fix: The scanner evaluates every script and stylesheet occurrence on every page. A protected occurrence on one page no longer hides a missing integrity attribute on another page. Identical findings are merged per page only after evaluation, with an occurrence count, and every stored hash record is verified on each scan.
* New: The scanner reports empty or invalid integrity attributes and missing crossorigin attributes on cross-origin assets, follows browser rules for multiple hashes, and resolves "../" paths, base URLs, and redirects.
* Change: The "Auto Regenerate" setting is now "Change Detection" (same stored option). Hash records are keyed by asset instead of by version, file timestamp, or algorithm; existing trusted hashes are migrated on upgrade.
* Docs: Clarified that the scanner analyzes server-returned HTML and does not run JavaScript, and that SRI verifies content against a hash rather than proving a file is safe.

= 1.1.0 =
* New: Website SRI Scanner that crawls the home page and recent posts/pages, reporting each asset that is missing an integrity hash or fails its integrity check.
* New: Email notifications with a modern, responsive HTML template. Administrators can set a custom logo, accent color, header title, footer text, and recipient, and send a test email.
* New: Dedicated Scanner and Notifications admin screens.
* Improvement: Added a scan-results database table and bumped the schema version; uninstall now removes it.

= 1.0.0 =
* Initial stable release.
* Local/remote SRI hashing with automatic tag injection.
* Admin settings page with maintenance tools.
* Debug logging and extensibility hooks.

== Upgrade Notice ==

= 1.2.0 =
Security update: changed scripts and stylesheets now need your approval before their new hash is trusted. After updating themes, plugins, or WordPress, review changed files under SRI Shield > Hash Records — browsers block a changed file until you approve it. Existing trusted hashes are kept.

= 1.1.0 =
Adds the Website SRI Scanner, email notifications, and dedicated Scanner and Notifications screens. Includes a database update for scan results.

= 1.0.0 =
Initial stable release.

== Developer Filters and Actions ==

Below are commonly used extension points.

= Override whether the plugin is enabled =

    add_filter( 'sri_shield_enabled', function ( $enabled ) {
        return $enabled;
    } );

= Exclude handles dynamically =

    add_filter( 'sri_shield_excluded_handles', function ( $handles ) {
        $handles[] = 'my-dynamic-handle';
        return $handles;
    } );

= Override the algorithm by handle =

    add_filter( 'sri_shield_hash_algorithm', function ( $algorithm, $handle, $url, $type ) {
        if ( 'critical-script' === $handle ) {
            return 'sha512';
        }
        return $algorithm;
    }, 10, 4 );

= Change the crossorigin attribute =

    add_filter( 'sri_shield_crossorigin_attribute', function ( $crossorigin, $handle ) {
        if ( 'local-only-asset' === $handle ) {
            return '';
        }
        return $crossorigin;
    }, 10, 2 );

= Modify a hash when it becomes trusted =

Applied when an asset is first enrolled and when an administrator approves a change.

    add_filter( 'sri_shield_generated_hash', function ( $integrity, $handle ) {
        return $integrity;
    }, 10, 2 );

= Observe cache, hash, and review events =

    add_action( 'sri_shield_hash_generated', function ( $handle, $record ) {
        // An asset was enrolled.
    }, 10, 2 );
    add_action( 'sri_shield_hash_failed', function ( $handle, $record ) {
        // Alerting.
    }, 10, 2 );
    add_action( 'sri_shield_asset_changed', function ( $record, $context ) {
        // Content no longer matches the trusted hash; $record['pending_integrity'] holds the proposed hash.
    }, 10, 2 );
    add_action( 'sri_shield_hash_approved', function ( $record, $previous_integrity, $user_id ) {
        // An administrator approved a change.
    }, 10, 3 );
    add_action( 'sri_shield_hash_change_dismissed', function ( $record, $user_id ) {
        // An administrator kept the trusted hash.
    }, 10, 2 );
    add_action( 'sri_shield_cache_cleared', function () {
        // External cache sync.
    } );

= React to scanner findings =

    add_action( 'sri_shield_tamper_detected', function ( $finding ) {
        // Fired for each hash mismatch. $finding includes page_url, asset_url, declared_integrity, expected_integrity, etc.
    } );
    add_action( 'sri_shield_scan_completed', function ( $summary, $findings ) {
        // Fired once per scan with the run summary and problem findings.
    }, 10, 2 );

= Customize the scanner and notification emails =

    add_filter( 'sri_shield_scan_urls', function ( $urls ) {
        $urls[] = home_url( '/checkout/' );
        return $urls;
    } );
    add_filter( 'sri_shield_email_subject', function ( $subject, $summary, $findings ) {
        return $subject;
    }, 10, 3 );
    add_filter( 'sri_shield_email_recipient', function ( $recipient ) {
        return $recipient;
    } );
