diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4d30b83..9b5c4d4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,9 +2,9 @@ name: "CodeQL" on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] schedule: - cron: "39 8 * * 3" @@ -20,11 +20,11 @@ jobs: strategy: fail-fast: false matrix: - language: [ javascript ] + language: [javascript] steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Initialize CodeQL uses: github/codeql-action/init@v4 diff --git a/.github/workflows/commenter.yml b/.github/workflows/commenter.yml index ce339f4..a42f2db 100644 --- a/.github/workflows/commenter.yml +++ b/.github/workflows/commenter.yml @@ -4,25 +4,24 @@ on: [push, pull_request] jobs: run: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 - - name: Use Node.js - uses: actions/setup-node@v6 - - run: npm install - - run: | - node lib/comment.js --diff | tee -a results.txt - - name: Comment PR - uses: marocchino/sticky-pull-request-comment@v2 - with: - path: results.txt - - uses: actions/github-script@v8 - with: - script: | - const fs = require('fs'); - const fileContent = fs.readFileSync('results.txt', 'utf8'); - if (fileContent.includes('❌')) { - core.setFailed('CDN check failed!') - } + - uses: actions/checkout@v6 + - name: Use Node.js + uses: actions/setup-node@v6 + - run: npm install + - run: | + node lib/comment.js --diff | tee -a results.txt + - name: Comment PR + uses: marocchino/sticky-pull-request-comment@v2 + with: + path: results.txt + - uses: actions/github-script@v8 + with: + script: | + const fs = require('fs'); + const fileContent = fs.readFileSync('results.txt', 'utf8'); + if (fileContent.includes('❌')) { + core.setFailed('CDN check failed!') + } diff --git a/index.js b/index.js index 2529162..b02e714 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ const { readFileSync, statSync, readdirSync } = require('fs'); +const crypto = require('crypto'); const { join, relative } = require('path'); function walk(dir, callback) { @@ -13,6 +14,17 @@ function walk(dir, callback) { }); } +function calculateIntegrity(data) { + // Calculate SHA-256 hash and return in base64 format (SRI format) + const hash = crypto.createHash('sha256'); + hash.update(data); + return 'sha256-' + hash.digest('base64'); +} + +// Store integrity hashes for files we process +// This will be exported so the theme can access it +const localIntegrityMap = {}; + function readFile(plugin_dir, value) { let { name, file, dir } = value; if (!file) file = dir; @@ -37,23 +49,28 @@ function readFile(plugin_dir, value) { } if (stats.isDirectory()) { walk(origin, path => { + const fileData = readFileSync(path); + const dist_path = join(dist, relative(origin, path)); data.push({ - path: join(dist, relative(origin, path)), - data: readFileSync(path) + path: dist_path, + data: fileData }); + localIntegrityMap[dist_path] = calculateIntegrity(fileData); }); } else if (stats.isFile()) { + const fileData = readFileSync(origin); data.push({ path: dist, - data: readFileSync(origin) + data: fileData }); + localIntegrityMap[dist] = calculateIntegrity(fileData); } return { data }; } -module.exports = function(hexo, vendors) { +function pluginMain(hexo, vendors) { let generator = []; let errors = []; vendors.fontawesome_font = { @@ -82,4 +99,24 @@ module.exports = function(hexo, vendors) { hexo.log.warn('Maybe you can find the solution here: https://github.com/next-theme/plugins#debug'); } hexo.extend.generator.register('next_vendors', () => generator); + + // Register a helper to access local integrity hashes + hexo.extend.helper.register('next_vendor_integrity', function(path) { + // Normalize path to match our map keys + const normalizedPath = path.replace(/^\//, ''); + return localIntegrityMap[normalizedPath]; + }); + + // Log integrity hashes for debugging + hexo.log.info('[next-theme/plugins] Calculated integrity hashes for local files'); + if (Object.keys(localIntegrityMap).length > 0) { + hexo.log.debug(` Total files with integrity hashes: ${Object.keys(localIntegrityMap).length}`); + } +} + +// Export both the main function and a method to get integrity hashes +module.exports = pluginMain; +module.exports.getLocalIntegrity = function(path) { + const normalizedPath = path.replace(/^\//, ''); + return localIntegrityMap[normalizedPath]; }; diff --git a/package.json b/package.json index 38b47ff..692fd8b 100644 --- a/package.json +++ b/package.json @@ -7,30 +7,26 @@ "prepublishOnly": "npm i && node lib/generator.js" }, "repository": "next-theme/plugins", - "keywords": [ - "hexo", - "hexo generator", - "hexo plugin" - ], + "keywords": ["hexo", "hexo generator", "hexo plugin"], "author": "Mimi (https://zhangshuqiao.org)", "license": "MIT", "dependencies": { "@creativecommons/vocabulary": "2020.11.3", - "@fancyapps/ui": "5.0.31", - "@fortawesome/fontawesome-free": "7.0.0", + "@fancyapps/ui": "6.1.10", + "@fortawesome/fontawesome-free": "7.1.0", "@next-theme/pjax": "0.6.0", - "algoliasearch": "5.36.0", + "algoliasearch": "5.47.0", "animate.css": "3.1.1", - "animejs": "3.2.1", - "disqusjs": "3.1.0", - "firebase": "12.2.1", + "animejs": "4.3.5", + "disqusjs": "3.1.1", + "firebase": "12.8.0", "gitalk": "1.8.0", "hexo-generator-searchdb": "1.5.0", - "katex": "0.16.9", + "katex": "0.16.28", "lozad": "1.16.0", - "mathjax": "3.2.2", + "mathjax": "4.1.0", "medium-zoom": "1.1.0", - "mermaid": "11.10.1", + "mermaid": "11.12.2", "pace-js": "1.2.4", "pangu": "7.2.0", "pdfobject": "2.3.1",