diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1c33416..5b7f9dc2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - node: [18] + node: [20] steps: - uses: actions/setup-node@v3 diff --git a/docs/content/1.documentation/1.getting-started/2.configuration.md b/docs/content/1.documentation/1.getting-started/2.configuration.md index e5a94853..0985a9dc 100644 --- a/docs/content/1.documentation/1.getting-started/2.configuration.md +++ b/docs/content/1.documentation/1.getting-started/2.configuration.md @@ -26,7 +26,7 @@ interface ModuleOptions { enabled: boolean; csrf: CsrfOptions | false; nonce: boolean; - removeLoggers: RemoveOptions | false; + removeLoggers: boolean | RemoveOptions; // RemoveOptions is being deprecated, please use `true` instead ssg: Ssg | false; sri: boolean; } @@ -112,12 +112,7 @@ security: { enabled: true, csrf: false, nonce: true, - removeLoggers: { - external: [], - consoleType: ['log', 'debug'], - include: [/\.[jt]sx?$/, /\.vue\??/], - exclude: [/node_modules/, /\.git/] - }, + removeLoggers: true, ssg: { meta: true, hashScripts: true, diff --git a/docs/content/1.documentation/2.headers/1.csp.md b/docs/content/1.documentation/2.headers/1.csp.md index 1b63ef22..191e8e80 100644 --- a/docs/content/1.documentation/2.headers/1.csp.md +++ b/docs/content/1.documentation/2.headers/1.csp.md @@ -77,6 +77,8 @@ contentSecurityPolicy: { 'frame-ancestors'?: ("'self'" | "'none'" | string)[] | false; 'report-uri'?: string[] | false; 'report-to'?: string | false; + 'require-trusted-types-for'?: string | false; + 'trusted-types'?: string[] | string | false; 'upgrade-insecure-requests'?: boolean; } | false ``` diff --git a/docs/content/1.documentation/4.utils/2.remove-console-loggers.md b/docs/content/1.documentation/4.utils/2.remove-console-loggers.md index a130933b..c5528dc8 100644 --- a/docs/content/1.documentation/4.utils/2.remove-console-loggers.md +++ b/docs/content/1.documentation/4.utils/2.remove-console-loggers.md @@ -12,13 +12,58 @@ By default, your application will allow log all activity in the browser when you ℹ Read more about it [here](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html#data-to-exclude). :: -Fortunately, `nuxt-security` module removes both `log` and `debug` console outputs by default so your application is not leaking this information. +Fortunately, the Nuxt Security module removes all `console` outputs by default so your application is not leaking this information. +Nuxt Security also removes all `debugger` statements from your code. -This functionality is delivered by the amazing Vite Plugin by [Talljack](https://github.com/Talljack) that you can check out [here](https://github.com/Talljack/unplugin-remove). +## Options + +This feature is enabled globally default. + +You can disable the feature by setting `removeLoggers: false`: + +```js{}[nuxt.config.ts] +export default defineNuxtConfig({ + modules: ['nuxt-security'], + + security: { + removeLoggers: false + } +}) +``` + +## Alternative method - deprecated + +By default when you set `removeLoggers: true`, Nuxt Security uses the native Vite features to remove statements. + +In addition, Nuxt Security also supports an alternative method for removing console outputs, via the amazing `unplugin-remove` Vite Plugin by [Talljack](https://github.com/Talljack) that you can check out [here](https://github.com/Talljack/unplugin-remove). + +::alert{type="warning"} +ℹ The `unplugin-remove` method is being deprecated and will be removed in a future release. +Please note that `unplugin-remove` will not remove `debugger` statements from your code. +:: + +If you want to use the `unplugin-remove` plugin method, pass an object to the `removeLoggers` configuration instead of passing `true`. + +```js{}[nuxt.config.ts] +export default defineNuxtConfig({ + modules: ['nuxt-security'], + + security: { + removeLoggers: { + external: [], + consoleType: ['log', 'debug'], + include: [/\.[jt]sx?$/, /\.vue\??/], + exclude: [/node_modules/, /\.git/] + } + } +}) +``` + +The `removeLoggers` object can be configured with following values. ```ts -import type { FilterPattern } from '@rollup/pluginutils' -export interface Options { +// https://github.com/Talljack/unplugin-remove/blob/main/src/types.ts +type RemoveOptions { /** * don't remove console.log and debugger these module * @@ -47,32 +92,3 @@ export interface Options { exclude?: FilterPattern } ``` - -If you would like to add some custom functionality to it, you can do so by doing the following: - -```js{}[nuxt.config.ts] -export default defineNuxtConfig({ - modules: ['nuxt-security'], - - security: { - removeLoggers: { - external: [], - consoleType: ['log', 'debug'], - include: [/\.[jt]sx?$/, /\.vue\??/], - exclude: [/node_modules/, /\.git/] - } - } -}) -``` - -However, if you prefer not to have this, you can always disable this functionality from the module configuration (which is not recommended but possible) like the following: - -```js{}[nuxt.config.ts] -export default defineNuxtConfig({ - modules: ['nuxt-security'], - - security: { - removeLoggers: false - } -}) -``` diff --git a/package.json b/package.json index 93c01330..a573918f 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,11 @@ { "name": "nuxt-security", - "version": "2.0.0", + "version": "2.1.0", "license": "MIT", "type": "module", + "engines": { + "node": ">=20.0.0" + }, "homepage": "https://nuxt-security.vercel.app", "description": "🛡️ Security Module for Nuxt based on HTTP Headers and Middleware", "repository": { @@ -54,7 +57,7 @@ "@nuxt/kit": "^3.11.2", "basic-auth": "^2.0.1", "defu": "^6.1.1", - "nuxt-csurf": "^1.5.1", + "nuxt-csurf": "^1.6.5", "pathe": "^1.0.0", "unplugin-remove": "^1.0.3", "xss": "^1.0.14" diff --git a/src/defaultConfig.ts b/src/defaultConfig.ts index b04a5ad0..aa46f987 100644 --- a/src/defaultConfig.ts +++ b/src/defaultConfig.ts @@ -78,13 +78,7 @@ export const defaultSecurityConfig = (serverlUrl: string, strict: boolean) => { enabled: true, csrf: false, nonce: true, - // https://github.com/Talljack/unplugin-remove/blob/main/src/types.ts - removeLoggers: { - external: [], - consoleType: ['log', 'debug'], - include: [/\.[jt]sx?$/, /\.vue\??/], - exclude: [/node_modules/, /\.git/] - }, + removeLoggers: true, ssg: { meta: true, hashScripts: true, @@ -96,7 +90,7 @@ export const defaultSecurityConfig = (serverlUrl: string, strict: boolean) => { } if (strict) { - defaultConfig.headers.crossOriginEmbedderPolicy = 'require-corp' + defaultConfig.headers.crossOriginEmbedderPolicy = process.env.NODE_ENV === 'development' ? 'unsafe-none' : 'require-corp' defaultConfig.headers.contentSecurityPolicy = { 'base-uri': ["'none'"], 'default-src' : ["'none'"], diff --git a/src/module.ts b/src/module.ts index 6c9cbde6..74beddcb 100644 --- a/src/module.ts +++ b/src/module.ts @@ -1,7 +1,7 @@ import { defineNuxtModule, addServerHandler, installModule, addVitePlugin, addServerPlugin, createResolver, addImportsDir, useNitro, addServerImports } from '@nuxt/kit' import { existsSync } from 'node:fs' import { readFile, readdir } from 'node:fs/promises' -import { join } from 'pathe' +import { join, isAbsolute } from 'pathe' import { defu } from 'defu' import viteRemove from 'unplugin-remove/vite' import { getHeadersApplicableToAllResources } from './utils/headers' @@ -58,9 +58,38 @@ export default defineNuxtModule({ // Disable module when `enabled` is set to `false` if (!securityOptions.enabled) { return } - // Register Vite transform plugin to remove loggers + // Register transform plugin to remove loggers if (securityOptions.removeLoggers) { - addVitePlugin(viteRemove(securityOptions.removeLoggers)) + if (securityOptions.removeLoggers !== true) { + // Uses the legacy unplugin-remove plugin method + // This method is deprecated and will be removed in the future + addVitePlugin(viteRemove(securityOptions.removeLoggers)) + + } else { + // Uses the native method by Vite + // Vite can use either esbuild or terser + if (nuxt.options.vite.build?.minify === 'terser') { + // In case of terser, set the drop_console and drop_debugger options + nuxt.options.vite.build = defu( + { + terserOptions: { compress: { drop_console: true, drop_debugger: true } } + }, + nuxt.options.vite.build + ) + } else { + // In the default case, make sure minification by esbuild is turned on and set the drop option + nuxt.options.vite.build = defu( + { minify: true }, + nuxt.options.vite.build + ) + nuxt.options.vite.esbuild = defu( + { + drop: ['console', 'debugger'] as ('console' | 'debugger')[], + }, + nuxt.options.vite.esbuild + ) + } + } } // Copy security headers that apply to all resources into standard route rules @@ -273,13 +302,12 @@ function reorderNitroPlugins(nuxt: Nuxt) { async function hashBundledAssets(nitro: Nitro) { - const hashAlgorithm = 'sha384' + const hashAlgorithm = 'SHA-384' const sriHashes: Record = {} // Will be later necessary to construct url const { cdnURL: appCdnUrl = '', baseURL: appBaseUrl } = nitro.options.runtimeConfig.app - // Go through all public assets folder by folder const publicAssets = nitro.options.publicAssets for (const publicAsset of publicAssets) { @@ -296,18 +324,20 @@ async function hashBundledAssets(nitro: Nitro) { // Node 16 compatibility maintained // Node 18.17+ supports entry.path on DirEnt // const fullPath = join(entry.path, entry.name) - const fullPath = join(dir, entry.name) - const fileContent = await readFile(fullPath) - const hash = generateHash(fileContent, hashAlgorithm) + const path = join(dir, entry.name) + const content = await readFile(path) + const hash = await generateHash(content, hashAlgorithm) // construct the url as it will appear in the head template - const relativeUrl = join(baseURL, entry.name) + const fullPath = join(baseURL, entry.name) let url: string if (appCdnUrl) { // If the cdnURL option was set, the url will be in the form https://... - url = new URL(relativeUrl, appCdnUrl).href + const relativePath = isAbsolute(fullPath) ? fullPath.slice(1) : fullPath + const abdsoluteCdnUrl = appCdnUrl.endsWith('/') ? appCdnUrl : appCdnUrl + '/' + url = new URL(relativePath, abdsoluteCdnUrl).href } else { // If not, the url will be in a relative form: /_nuxt/... - url = join('/', appBaseUrl, relativeUrl) + url = join('/', appBaseUrl, fullPath) } sriHashes[url] = hash } @@ -315,5 +345,6 @@ async function hashBundledAssets(nitro: Nitro) { } } + return sriHashes } diff --git a/src/runtime/nitro/plugins/30-cspSsgHashes.ts b/src/runtime/nitro/plugins/30-cspSsgHashes.ts index 98e785e4..6ad31443 100644 --- a/src/runtime/nitro/plugins/30-cspSsgHashes.ts +++ b/src/runtime/nitro/plugins/30-cspSsgHashes.ts @@ -21,7 +21,7 @@ export default defineNitroPlugin((nitroApp) => { return } - nitroApp.hooks.hook('render:html', (html, { event }) => { + nitroApp.hooks.hook('render:html', async(html, { event }) => { // Exit if no CSP defined const rules = resolveSecurityRules(event) if (!rules.enabled || !rules.headers || !rules.headers.contentSecurityPolicy) { @@ -34,7 +34,7 @@ export default defineNitroPlugin((nitroApp) => { } const scriptHashes = event.context.security!.hashes.script const styleHashes = event.context.security!.hashes.style - const hashAlgorithm = 'sha256' + const hashAlgorithm = 'SHA-256' // Parse HTML if SSG is enabled for this route if (rules.ssg) { @@ -43,12 +43,13 @@ export default defineNitroPlugin((nitroApp) => { // Scan all relevant sections of the NuxtRenderHtmlContext const sections = ['body', 'bodyAppend', 'bodyPrepend', 'head'] as Section[] for (const section of sections) { - html[section].forEach(element => { + for (const element of html[section]) { if (hashScripts) { // Parse all script tags const inlineScriptMatches = element.matchAll(INLINE_SCRIPT_RE) for (const [, scriptText] of inlineScriptMatches) { - scriptHashes.add(`'${generateHash(scriptText, hashAlgorithm)}'`) + const hash = await generateHash(scriptText, hashAlgorithm) + scriptHashes.add(`'${hash}'`) } const externalScriptMatches = element.matchAll(SCRIPT_RE) for (const [, integrity] of externalScriptMatches) { @@ -60,7 +61,8 @@ export default defineNitroPlugin((nitroApp) => { if (hashStyles) { const styleMatches = element.matchAll(STYLE_RE) for (const [, styleText] of styleMatches) { - styleHashes.add(`'${generateHash(styleText, hashAlgorithm)}'`) + const hash = await generateHash(styleText, hashAlgorithm) + styleHashes.add(`'${hash}'`) } } @@ -94,7 +96,7 @@ export default defineNitroPlugin((nitroApp) => { } } } - }) + } } } }) diff --git a/src/runtime/nitro/plugins/40-cspSsrNonce.ts b/src/runtime/nitro/plugins/40-cspSsrNonce.ts index e796de65..822693be 100644 --- a/src/runtime/nitro/plugins/40-cspSsrNonce.ts +++ b/src/runtime/nitro/plugins/40-cspSsrNonce.ts @@ -1,5 +1,4 @@ import { defineNitroPlugin } from '#imports' -import { randomBytes } from 'node:crypto' import { resolveSecurityRules } from '../context' const LINK_RE = /]*?>)/gi @@ -28,7 +27,9 @@ export default defineNitroPlugin((nitroApp) => { const rules = resolveSecurityRules(event) if (rules.enabled && rules.nonce && !import.meta.prerender) { - const nonce = randomBytes(16).toString('base64') + const array = new Uint8Array(18); + crypto.getRandomValues(array) + const nonce = btoa(String.fromCharCode(...array)) event.context.security!.nonce = nonce } }) diff --git a/src/types/headers.ts b/src/types/headers.ts index af94b4ba..8efea7a2 100644 --- a/src/types/headers.ts +++ b/src/types/headers.ts @@ -86,6 +86,8 @@ export type ContentSecurityPolicyValue = { //'navigate-to'?: ("'self'" | "'none'" | "'unsafe-allow-redirects'" | string)[] | string | false; 'report-uri'?: string[] | string | false; 'report-to'?: string | false; + 'require-trusted-types-for'?: string | false; + 'trusted-types'?: string[] | string | false; 'upgrade-insecure-requests'?: boolean; }; diff --git a/src/types/module.ts b/src/types/module.ts index 6547771e..20ddc86f 100644 --- a/src/types/module.ts +++ b/src/types/module.ts @@ -28,11 +28,11 @@ export interface ModuleOptions { sri: boolean basicAuth: BasicAuth | false; csrf: CsrfOptions | boolean; - removeLoggers: RemoveOptions | false; + removeLoggers: RemoveOptions | boolean; } export type NuxtSecurityRouteRules = Partial< - Omit + Omit & { rateLimiter: Omit | false } & { ssg: Omit | false } & { requestSizeLimiter: RequestSizeLimiter | false } diff --git a/src/utils/hash.ts b/src/utils/hash.ts index 7a947b08..2c86db7d 100644 --- a/src/utils/hash.ts +++ b/src/utils/hash.ts @@ -1,7 +1,13 @@ -import { createHash } from 'node:crypto'; -export function generateHash(content: Buffer | string, hashAlgorithm: string) { - const hash = createHash(hashAlgorithm); - hash.update(content); - return `${hashAlgorithm}-${hash.digest('base64')}`; +export async function generateHash(content: Buffer | string, hashAlgorithm: 'SHA-256' | 'SHA-384' | 'SHA-512') { + let buffer: Uint8Array + if (typeof content === 'string') { + buffer = new TextEncoder().encode(content); + } else { + buffer = new Uint8Array(content); + } + const hashBuffer = await crypto.subtle.digest(hashAlgorithm, buffer); + const base64 = btoa(String.fromCharCode(...new Uint8Array(hashBuffer))); + const prefix = hashAlgorithm.replace('-', '').toLowerCase() + return `${prefix}-${base64}`; } diff --git a/src/utils/headers.ts b/src/utils/headers.ts index e1f6d4a3..c04984ea 100644 --- a/src/utils/headers.ts +++ b/src/utils/headers.ts @@ -112,7 +112,7 @@ export function headerObjectFromString(optionKey: OptionKey, headerValue: string const directives = headerValue.split(';').map(directive => directive.trim()).filter(directive => directive) const objectForm = {} as ContentSecurityPolicyValue for (const directive of directives) { - const [type, ...sources] = directive.split(' ').map(token => token.trim()) as [keyof ContentSecurityPolicyValue, ...any] + const [type, ...sources] = directive.split(' ').map(token => token.trim()) as [keyof ContentSecurityPolicyValue, ...string[]] if (type === 'upgrade-insecure-requests') { objectForm[type] = true } else { @@ -173,11 +173,12 @@ function appliesToAllResources(optionKey: OptionKey) { * Extract the subset of security headers that apply to all resources */ export function getHeadersApplicableToAllResources(headers: SecurityHeaders) { - return >Object.fromEntries( + const applicableHeaders = >Object.fromEntries( Object.entries(headers) .filter(([key]) => appliesToAllResources(key as OptionKey)) .map(([key, value]) => ([getNameFromKey(key as OptionKey), headerStringFromObject(key as OptionKey, value)])) ) + return Object.keys(applicableHeaders).length === 0 ? undefined : applicableHeaders } diff --git a/yarn.lock b/yarn.lock index 72143f83..e8652d81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1219,7 +1219,7 @@ "@typescript-eslint/types" "^7.7.1" "@typescript-eslint/utils" "^7.7.1" -"@nuxt/kit@3.11.2", "@nuxt/kit@^3.10.2", "@nuxt/kit@^3.10.3", "@nuxt/kit@^3.11.1", "@nuxt/kit@^3.11.2", "@nuxt/kit@^3.8.2": +"@nuxt/kit@3.11.2", "@nuxt/kit@^3.10.3", "@nuxt/kit@^3.11.1", "@nuxt/kit@^3.11.2", "@nuxt/kit@^3.8.2": version "3.11.2" resolved "https://registry.npmjs.org/@nuxt/kit/-/kit-3.11.2.tgz" integrity sha512-yiYKP0ZWMW7T3TCmsv4H8+jEsB/nFriRAR8bKoSqSV9bkVYWPE36sf7JDux30dQ91jSlQG6LQkB3vCHYTS2cIg== @@ -1243,6 +1243,32 @@ unimport "^3.7.1" untyped "^1.4.2" +"@nuxt/kit@^3.13.2": + version "3.13.2" + resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-3.13.2.tgz#4c019a87e08c33ec14d1059497ba40568b82bfed" + integrity sha512-KvRw21zU//wdz25IeE1E5m/aFSzhJloBRAQtv+evcFeZvuroIxpIQuUqhbzuwznaUwpiWbmwlcsp5uOWmi4vwA== + dependencies: + "@nuxt/schema" "3.13.2" + c12 "^1.11.2" + consola "^3.2.3" + defu "^6.1.4" + destr "^2.0.3" + globby "^14.0.2" + hash-sum "^2.0.0" + ignore "^5.3.2" + jiti "^1.21.6" + klona "^2.0.6" + knitwork "^1.1.0" + mlly "^1.7.1" + pathe "^1.1.2" + pkg-types "^1.2.0" + scule "^1.3.0" + semver "^7.6.3" + ufo "^1.5.4" + unctx "^2.3.1" + unimport "^3.12.0" + untyped "^1.4.2" + "@nuxt/module-builder@^0.8.3": version "0.8.3" resolved "https://registry.yarnpkg.com/@nuxt/module-builder/-/module-builder-0.8.3.tgz#d87312aedd9a025d297f34338d7198652b79fbfa" @@ -1275,6 +1301,24 @@ unimport "^3.7.1" untyped "^1.4.2" +"@nuxt/schema@3.13.2": + version "3.13.2" + resolved "https://registry.yarnpkg.com/@nuxt/schema/-/schema-3.13.2.tgz#4c1011ebf9fd5f821900bbfc50fd5eff2e663e9b" + integrity sha512-CCZgpm+MkqtOMDEgF9SWgGPBXlQ01hV/6+2reDEpJuqFPGzV8HYKPBcIFvn7/z5ahtgutHLzjP71Na+hYcqSpw== + dependencies: + compatx "^0.1.8" + consola "^3.2.3" + defu "^6.1.4" + hookable "^5.5.3" + pathe "^1.1.2" + pkg-types "^1.2.0" + scule "^1.3.0" + std-env "^3.7.0" + ufo "^1.5.4" + uncrypto "^0.1.3" + unimport "^3.12.0" + untyped "^1.4.2" + "@nuxt/telemetry@^2.5.3": version "2.5.3" resolved "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.5.3.tgz" @@ -1555,6 +1599,15 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@rollup/pluginutils@^5.1.2": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.3.tgz#3001bf1a03f3ad24457591f2c259c8e514e0dbdf" + integrity sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + "@rollup/rollup-android-arm-eabi@4.14.0": version "4.14.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz#57936f50d0335e2e7bfac496d209606fa516add4" @@ -2431,6 +2484,11 @@ acorn@^8.12.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -2769,6 +2827,24 @@ c12@^1.10.0: pkg-types "^1.0.3" rc9 "^2.1.1" +c12@^1.11.2: + version "1.11.2" + resolved "https://registry.yarnpkg.com/c12/-/c12-1.11.2.tgz#f8a1e30c10f4b273894a1bcb6944f76c15b56717" + integrity sha512-oBs8a4uvSDO9dm8b7OCFW7+dgtVrwmwnrVXYzLm43ta7ep2jCn/0MhoUFygIWtxhyy6+/MG7/agvpY0U1Iemew== + dependencies: + chokidar "^3.6.0" + confbox "^0.1.7" + defu "^6.1.4" + dotenv "^16.4.5" + giget "^1.2.3" + jiti "^1.21.6" + mlly "^1.7.1" + ohash "^1.1.3" + pathe "^1.1.2" + perfect-debounce "^1.0.0" + pkg-types "^1.2.0" + rc9 "^2.1.2" + cac@^6.7.14: version "6.7.14" resolved "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz" @@ -2812,15 +2888,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599: - version "1.0.30001605" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz" - integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== - -caniuse-lite@^1.0.30001646: - version "1.0.30001651" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" - integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599, caniuse-lite@^1.0.30001646: + version "1.0.30001668" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001668.tgz" + integrity sha512-nWLrdxqCdblixUO+27JtGJJE/txpJlyUy5YN1u53wLZkP0emYCo5zgS6QYft7VUYR42LGgi/S5hdLZTrnyIddw== chai@^4.3.10: version "4.4.1" @@ -2995,6 +3066,11 @@ commondir@^1.0.1: resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== +compatx@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/compatx/-/compatx-0.1.8.tgz#af6f61910ade6ce1073c0fdff23c786bcd75c026" + integrity sha512-jcbsEAR81Bt5s1qOFymBufmCbXCXbk0Ql+K5ouj6gCyx2yHlu6AgmGIi9HxfKixpUDO5bCFJUHQ5uM6ecbTebw== + compress-commons@^6.0.2: version "6.0.2" resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz" @@ -3021,6 +3097,11 @@ confbox@^0.1.7: resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + consola@^3.2.3: version "3.2.3" resolved "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz" @@ -4047,7 +4128,7 @@ get-tsconfig@^4.7.3: dependencies: resolve-pkg-maps "^1.0.0" -giget@^1.2.1: +giget@^1.2.1, giget@^1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz" integrity sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA== @@ -4188,6 +4269,18 @@ globby@^14.0.1: slash "^5.1.0" unicorn-magic "^0.1.0" +globby@^14.0.2: + version "14.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-14.0.2.tgz#06554a54ccfe9264e5a9ff8eded46aa1e306482f" + integrity sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw== + dependencies: + "@sindresorhus/merge-streams" "^2.1.0" + fast-glob "^3.3.2" + ignore "^5.2.4" + path-type "^5.0.0" + slash "^5.1.0" + unicorn-magic "^0.1.0" + graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" @@ -4354,6 +4447,11 @@ ignore@^5.2.0, ignore@^5.2.4, ignore@^5.3.1: resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +ignore@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + image-meta@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/image-meta/-/image-meta-0.2.0.tgz" @@ -4600,6 +4698,11 @@ jiti@^1.19.3, jiti@^1.21.0: resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz" integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== +jiti@^1.21.6: + version "1.21.6" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" + integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -5139,6 +5242,16 @@ mlly@^1.7.1: pkg-types "^1.1.1" ufo "^1.5.3" +mlly@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.2.tgz#21c0d04543207495b8d867eff0ac29fac9a023c0" + integrity sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA== + dependencies: + acorn "^8.12.1" + pathe "^1.1.2" + pkg-types "^1.2.0" + ufo "^1.5.4" + mri@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz" @@ -5457,14 +5570,14 @@ nuxi@^3.11.1: optionalDependencies: fsevents "~2.3.3" -nuxt-csurf@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/nuxt-csurf/-/nuxt-csurf-1.5.1.tgz" - integrity sha512-eR59ogunxo0/GBUczkRbTjnO03Zl6KD1+Wa0DcqqoA3FjWaZ4M3dre3pwRPIL67yh62UtXEWXcNt8cUek3b49w== +nuxt-csurf@^1.6.5: + version "1.6.5" + resolved "https://registry.yarnpkg.com/nuxt-csurf/-/nuxt-csurf-1.6.5.tgz#c900f8817f565d91fe35c712dde7f2b0b46b8c20" + integrity sha512-/DMNTON8LIVhntamKbBmAuM879B0QnuSJa7ZAkmkZe+21m+1QGcjVUxtSkizaM48NUvkuAGYOG0ncn+kqEgrzw== dependencies: - "@nuxt/kit" "^3.10.2" + "@nuxt/kit" "^3.13.2" defu "^6.1.4" - uncsrf "^1.1.1" + uncsrf "^1.2.0" nuxt@^3.11.2: version "3.11.2" @@ -5862,6 +5975,15 @@ pkg-types@^1.1.1, pkg-types@^1.1.3: mlly "^1.7.1" pathe "^1.1.2" +pkg-types@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.2.1.tgz#6ac4e455a5bb4b9a6185c1c79abd544c901db2e5" + integrity sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw== + dependencies: + confbox "^0.1.8" + mlly "^1.7.2" + pathe "^1.1.2" + pluralize@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" @@ -6202,6 +6324,14 @@ rc9@^2.1.1: destr "^2.0.0" flat "^5.0.2" +rc9@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/rc9/-/rc9-2.1.2.tgz#6282ff638a50caa0a91a31d76af4a0b9cbd1080d" + integrity sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg== + dependencies: + defu "^6.1.4" + destr "^2.0.3" + react-is@^18.0.0: version "18.2.0" resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" @@ -6492,6 +6622,11 @@ semver@^7.0.0, semver@^7.1.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.6, semve dependencies: lru-cache "^6.0.0" +semver@^7.6.3: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -6768,16 +6903,7 @@ streamx@^2.15.0: optionalDependencies: bare-events "^2.2.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6809,14 +6935,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -7085,6 +7204,11 @@ ufo@^1.1.2, ufo@^1.2.0, ufo@^1.3.2, ufo@^1.4.0, ufo@^1.5.1, ufo@^1.5.3: resolved "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz" integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw== +ufo@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" + integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== + ultrahtml@^1.5.3: version "1.5.3" resolved "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz" @@ -7125,10 +7249,10 @@ uncrypto@^0.1.3: resolved "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz" integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== -uncsrf@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/uncsrf/-/uncsrf-1.1.1.tgz" - integrity sha512-wH9+N3oNdr2XB3egUKxCR26XTVfYywv2STZYtZLIp8votOf0/9b0axA9gpIHdYfgq/Myfh/HS5e0lQ/+27dj9A== +uncsrf@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/uncsrf/-/uncsrf-1.2.0.tgz#ed6ee2609726848869983cc639b907abed9dff21" + integrity sha512-EyeG1tIx1zisLuqokSXZ5LhndzaUd2WBMS+18IlBUYobJsKSUQMpLIEm6QUfY/Azmhnnz0v2QbkrT6/u2K/Y1g== unctx@^2.3.1: version "2.3.1" @@ -7178,6 +7302,25 @@ unicorn-magic@^0.1.0: resolved "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz" integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== +unimport@^3.12.0: + version "3.13.1" + resolved "https://registry.yarnpkg.com/unimport/-/unimport-3.13.1.tgz#4362340e2df7edad212c693d33808189e058dded" + integrity sha512-nNrVzcs93yrZQOW77qnyOVHtb68LegvhYFwxFMfuuWScmwQmyVCG/NBuN8tYsaGzgQUVYv34E/af+Cc9u4og4A== + dependencies: + "@rollup/pluginutils" "^5.1.2" + acorn "^8.12.1" + escape-string-regexp "^5.0.0" + estree-walker "^3.0.3" + fast-glob "^3.3.2" + local-pkg "^0.5.0" + magic-string "^0.30.11" + mlly "^1.7.1" + pathe "^1.1.2" + pkg-types "^1.2.0" + scule "^1.3.0" + strip-literal "^2.1.0" + unplugin "^1.14.1" + unimport@^3.7.1: version "3.7.1" resolved "https://registry.npmjs.org/unimport/-/unimport-3.7.1.tgz" @@ -7268,6 +7411,14 @@ unplugin@^1.12.0: webpack-sources "^3.2.3" webpack-virtual-modules "^0.6.2" +unplugin@^1.14.1: + version "1.15.0" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.15.0.tgz#cd1e92e537ab14a03354d6f83f29d536fac2e5a9" + integrity sha512-jTPIs63W+DUEDW207ztbaoO7cQ4p5aVaB823LSlxpsFEU3Mykwxf3ZGC/wzxFJeZlASZYgVrWeo7LgOrqJZ8RA== + dependencies: + acorn "^8.14.0" + webpack-virtual-modules "^0.6.2" + unplugin@^1.8.3: version "1.13.1" resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.13.1.tgz#d33e338374bfb80755a3789ed7de25b8f006131c" @@ -7665,16 +7816,7 @@ wide-align@^1.1.2: dependencies: string-width "^1.0.2 || 2 || 3 || 4" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==