diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b7f9dc..c1c3341 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node: [20] + node: [18] steps: - uses: actions/setup-node@v3 diff --git a/package.json b/package.json index a573918..dac8537 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "nuxt-security", - "version": "2.1.0", + "version": "2.1.1", "license": "MIT", "type": "module", "engines": { - "node": ">=20.0.0" + "node": ">=18.0.0" }, "homepage": "https://nuxt-security.vercel.app", "description": "🛡️ Security Module for Nuxt based on HTTP Headers and Middleware", @@ -79,7 +79,7 @@ }, "unbuild": { "entries": [ - "./src/utils/hash.ts", + "./src/utils/crypto.ts", "./src/utils/headers.ts", "./src/utils/merge.ts", "./src/defaultConfig.ts" diff --git a/src/module.ts b/src/module.ts index 74beddc..e50d667 100644 --- a/src/module.ts +++ b/src/module.ts @@ -5,7 +5,7 @@ import { join, isAbsolute } from 'pathe' import { defu } from 'defu' import viteRemove from 'unplugin-remove/vite' import { getHeadersApplicableToAllResources } from './utils/headers' -import { generateHash } from './utils/hash' +import { generateHash } from './utils/crypto' import { defuReplaceArray } from './utils/merge' import { defaultSecurityConfig } from './defaultConfig' import type { Nuxt } from '@nuxt/schema' diff --git a/src/runtime/nitro/plugins/30-cspSsgHashes.ts b/src/runtime/nitro/plugins/30-cspSsgHashes.ts index 6ad3144..e71138e 100644 --- a/src/runtime/nitro/plugins/30-cspSsgHashes.ts +++ b/src/runtime/nitro/plugins/30-cspSsgHashes.ts @@ -1,6 +1,6 @@ import { defineNitroPlugin } from '#imports' import { resolveSecurityRules } from '../context' -import { generateHash } from '../../../utils/hash' +import { generateHash } from '../../../utils/crypto' import type { Section } from '../../../types/module' diff --git a/src/runtime/nitro/plugins/40-cspSsrNonce.ts b/src/runtime/nitro/plugins/40-cspSsrNonce.ts index 822693b..aa7ee8e 100644 --- a/src/runtime/nitro/plugins/40-cspSsrNonce.ts +++ b/src/runtime/nitro/plugins/40-cspSsrNonce.ts @@ -1,5 +1,6 @@ import { defineNitroPlugin } from '#imports' import { resolveSecurityRules } from '../context' +import { generateRandomNonce } from '../../../utils/crypto' const LINK_RE = /]*?>)/gi const SCRIPT_RE = /]*?>)/gi @@ -27,9 +28,7 @@ export default defineNitroPlugin((nitroApp) => { const rules = resolveSecurityRules(event) if (rules.enabled && rules.nonce && !import.meta.prerender) { - const array = new Uint8Array(18); - crypto.getRandomValues(array) - const nonce = btoa(String.fromCharCode(...array)) + const nonce = generateRandomNonce() event.context.security!.nonce = nonce } }) diff --git a/src/utils/hash.ts b/src/utils/crypto.ts similarity index 52% rename from src/utils/hash.ts rename to src/utils/crypto.ts index 2c86db7..f9b12d7 100644 --- a/src/utils/hash.ts +++ b/src/utils/crypto.ts @@ -1,3 +1,8 @@ +// These two lines are required only to maintain compatibility with Node 18 +// - In Node 19 and above, crypto is available in the global scope +// - In Workers environments, crypto is available in the global scope +import { webcrypto } from 'node:crypto' +globalThis.crypto ??= webcrypto as Crypto export async function generateHash(content: Buffer | string, hashAlgorithm: 'SHA-256' | 'SHA-384' | 'SHA-512') { let buffer: Uint8Array @@ -11,3 +16,10 @@ export async function generateHash(content: Buffer | string, hashAlgorithm: 'SHA const prefix = hashAlgorithm.replace('-', '').toLowerCase() return `${prefix}-${base64}`; } + +export function generateRandomNonce() { + const array = new Uint8Array(18); + crypto.getRandomValues(array) + const nonce = btoa(String.fromCharCode(...array)) + return nonce +} diff --git a/src/utils/merge.ts b/src/utils/merge.ts index ca99a9a..10e1558 100644 --- a/src/utils/merge.ts +++ b/src/utils/merge.ts @@ -1,9 +1,9 @@ -import { createDefu } from 'defu'; +import { createDefu } from 'defu' export const defuReplaceArray = createDefu((obj, key, value) => { if (Array.isArray(obj[key]) || Array.isArray(value)) { - obj[key] = value; - return true; + obj[key] = value + return true } -}); +})