-
Notifications
You must be signed in to change notification settings - Fork 78
Expand file tree
/
Copy path20-subresourceIntegrity.ts
More file actions
59 lines (52 loc) · 2.26 KB
/
20-subresourceIntegrity.ts
File metadata and controls
59 lines (52 loc) · 2.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import { defineNitroPlugin, useRuntimeConfig } from '#imports'
//@ts-expect-error : we are importing from the virtual file system
import sriHashes from '#sri-hashes'
import { resolveSecurityRules } from '../context'
import type { Section } from '../../../types/module'
const SCRIPT_RE = /<script((?=[^>]+\bsrc="([^"]+)")(?![^>]+\bintegrity="[^"]+")[^>]+)(?:\/>|><\/script>)/g
const LINK_RE = /<link((?=[^>]+\brel="(?:stylesheet|preload|modulepreload)")(?=[^>]+\bhref="([^"]+)")(?![^>]+\bintegrity="[\w\-+/=]+")[^>]+)>/g
/**
* This plugin adds Subresource Integrity (SRI) hashes to script and link tags in the HTML.
*/
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('render:html', (html, { event }) => {
// Exit if SRI not enabled for this route
const rules = resolveSecurityRules(event)
if (!rules.enabled || !rules.sri) {
return
}
const runtimeConfig = useRuntimeConfig()
const cdnURL = runtimeConfig.app.cdnURL.replace(/\/$/, '') // Remove trailing slash
// Scan all relevant sections of the NuxtRenderHtmlContext
// Note: integrity can only be set on scripts and on links with rel preload, modulepreload and stylesheet
// However the SRI standard provides that other elements may be added to that list in the future
const sections = ['body', 'bodyAppend', 'bodyPrepend', 'head'] as Section[]
for (const section of sections) {
html[section] = html[section].map(element => {
// Skip non-string elements
if (typeof element !== 'string') {
return element;
}
element = element.replace(SCRIPT_RE, (match, rest: string, src: string) => {
const hash = sriHashes[src.replace(cdnURL, '')]
if (hash) {
const integrityScript = `<script integrity="${hash}"${rest}></script>`
return integrityScript
} else {
return match
}
})
element = element.replace(LINK_RE, (match, rest: string, href: string) => {
const hash = sriHashes[href.replace(cdnURL, '')]
if (hash) {
const integrityLink = `<link integrity="${hash}"${rest}>`
return integrityLink
} else {
return match
}
})
return element
})
}
})
})