Update dependencies and calculate correct integrity hashes for local files#347
Update dependencies and calculate correct integrity hashes for local files#347pivaldi wants to merge 13 commits intonext-theme:mainfrom
Conversation
This patch fixes the integrity hash mismatch bug when using `plugins: local`
with hexo-theme-next.
## Problem
When using `plugins: local`, the NexT theme was using hardcoded CDN integrity
hashes for local files, causing browser SRI (Subresource Integrity) validation
failures. All vendor assets were blocked, resulting in blank pages.
## Root Cause
The theme's `_vendors.yml` contains integrity hashes for CDN versions of
libraries. When `plugins: local` was enabled, the plugin copied files from
node_modules which had different content than the CDN versions, but the theme
still used the CDN hashes.
## Solution
The plugin now:
- Calculates SHA-256 integrity hashes for all files it copies
- Stores hashes in `localIntegrityMap` object
- Exports `getLocalIntegrity(path)` function for theme integration
- Registers `next_vendor_integrity` Hexo helper for template access
- Adds debug logging for calculated hashes
## Changes
- Add `crypto` module import for hash calculation
- Add `calculateIntegrity()` function to compute SHA-256 hashes in SRI format
- Modify `readFile()` to calculate and store hashes for all copied files
- Convert module.exports to named function `pluginMain` for better extensibility
- Export `getLocalIntegrity()` function to expose hash map to consumers
- Register Hexo helper for template/theme access to hashes
- Add informational logging
## Theme Integration
For complete fix, the theme's `scripts/events/lib/vendors.js` should be
updated to use these local hashes when `plugins === 'local'`:
```javascript
const shouldUseIntegrity = plugins !== 'local';
vendors[key] = {
url: links[plugins] || links.cdnjs,
integrity: shouldUseIntegrity ? value.integrity : undefined
};
```
Or to use calculated hashes:
```javascript
let integrityHash = value.integrity;
if (plugins === 'local' && typeof internal === 'function') {
const localHash = internal.getLocalIntegrity(`lib/${name}/${file}`);
if (localHash) integrityHash = localHash;
}
```
## Testing
Tested with:
- hexo-theme-next latest version
- Verified integrity hashes match actual file content
- Confirmed no SRI errors in browser when using `plugins: local`
- All vendor assets load correctly
## Breaking Changes
None - maintains full backward compatibility.
## Related Issues
Fixes the "integrity hash bug" that prevented using `plugins: local`.
When `vendors.plugins` is set to `local`, integrity hashes are now computed from the actual local files via `@next-theme/plugins` `getLocalIntegrity()` rather than using the hardcoded CDN hashes from `_vendors.yml`. This fixes SRI (Subresource Integrity) validation failures that caused browsers to block all vendor assets when self-hosting, resulting in blank pages. CDN mode is unaffected: hardcoded hashes from `_vendors.yml` are still used when `plugins` is not `local`. Depends on: next-theme/plugins#347
|
@pivaldi Thanks for your contribution! Under what circumstances did you encounter the integrity hash mismatch? Do you have a specific example and reproduction steps for testing? |
|
Hello @stevenjoezhang Sorry for breaking compatibility with CDNJS. Circumstances of the IssueThe integrity hash mismatch occurs when using Root Cause AnalysisIn // For local plugins, use calculated integrity hash from the plugin
// For CDN, use the hardcoded hash from _vendors.yml
let integrityHash = value.integrity;
if (plugins === "local" && typeof internal === "function") {
const localHash = internal.getLocalIntegrity(`lib/${name}/${file}`);
if (localHash) {
integrityHash = localHash;
}
}The Problem
Why Files Differ
Reproduction StepsStep 1: Configure Local VendorsEdit vendors:
internal: local
plugins: localStep 2: Install Dependenciesnpm install @next-theme/pluginsStep 3: Generate the Sitehexo clean
hexo generateStep 4: Inspect Generated HTMLLook at the generated HTML files (e.g., <script src="/lib/mermaid/dist/mermaid.min.js"
integrity="sha256-XXXXX..."
crossorigin="anonymous"></script>Step 5: Compare Integrity HashesHash in mermaid:
name: mermaid
version: 11.10.1
file: dist/mermaid.min.js
integrity: sha256-BmQmdWDS8X2OTbrwELWK366LV6escyWhHHe0XCTU/Hk=Hash in generated HTML (calculated by
Step 6: Browser Console ErrorIf hashes don't match, the browser will show: This causes the script to fail loading, breaking functionality. Practical ExampleTesting Hash MismatchYou can verify this manually by comparing file hashes: # Download CDN version
curl -sL https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.10.1/dist/mermaid.min.js | \
openssl dgst -sha256 -binary | openssl base64
# Hash local version
openssl dgst -sha256 -binary node_modules/mermaid/dist/mermaid.min.js | openssl base64If these produce different hashes, you've confirmed the mismatch. Why Removing Remote CDN Resolves ThisBy removing remote CDN fallback logic and relying solely on local files with dynamically-calculated integrity hashes:
Impact on UsersThis issue affects users who:
Proposed SolutionThe fix removes the dependency on hardcoded CDN integrity hashes by:
This makes the integrity checking reliable and automatic, without manual hash maintenance. Additional ContextCurrent setup in my environment: {
"@next-theme/plugins": "8.27.0 (custom fork)"
}The custom fork addresses this issue by ensuring integrity hashes are always calculated from the actual files being served, not from hardcoded CDN references. |
See the commit message of the last commit.
The rest are just version updates of the dependencies.