Skip to content

Commit

Permalink
feat: set crossorigin="anonymous" when possible
Browse files Browse the repository at this point in the history
With this commit we set the crossorigin attribute's value to "anonymous"
for <script>, <style> and <link rel="stylesheet"> elements when they
refer to external cross-origin resources.

Signed-off-by: Andres Correa Casablanca <[email protected]>
  • Loading branch information
castarco committed Feb 16, 2024
1 parent c599367 commit e5ebb22
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 17 deletions.
30 changes: 23 additions & 7 deletions core.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,32 @@ export const generateSRIHash = data => {
return `sha256-${hash.digest('base64')}`
}

/** @typedef {(hash: string, attrs: string, content?: string | undefined) => string} ElemReplacer */
/**
* @typedef {(
* hash: string,
* attrs: string,
* setCrossorigin: boolean,
* content?: string | undefined,
* ) => string} ElemReplacer
*/

/** @type {ElemReplacer} */
const scriptReplacer = (hash, attrs, content) =>
`<script${attrs} integrity="${hash}">${content ?? ''}</script>`
const scriptReplacer = (hash, attrs, setCrossorigin, content) =>
`<script${attrs} integrity="${hash}"${
setCrossorigin ? ' crossorigin="anonymous"' : ''
}>${content ?? ''}</script>`

/** @type {ElemReplacer} */
const styleReplacer = (hash, attrs, content) =>
`<style${attrs} integrity="${hash}">${content ?? ''}</style>`
const styleReplacer = (hash, attrs, setCrossorigin, content) =>
`<style${attrs} integrity="${hash}"${
setCrossorigin ? ' crossorigin="anonymous"' : ''
}>${content ?? ''}</style>`

/** @type {ElemReplacer} */
const linkStyleReplacer = (hash, attrs) => `<link${attrs} integrity="${hash}"/>`
const linkStyleReplacer = (hash, attrs, setCrossorigin) =>
`<link${attrs} integrity="${hash}"${
setCrossorigin ? ' crossorigin="anonymous"' : ''
}/>`

const srcRegex = /\s+(src|href)\s*=\s*("(?<src1>.*?)"|'(?<src2>.*?)')/i
const integrityRegex =
Expand Down Expand Up @@ -103,6 +117,7 @@ export const updateSriHashes = async (logger, distDir, content, h) => {

/** @type {string | undefined} */
let sriHash = undefined
let setCrossorigin = false

if (attrs) {
if (attrsRegex && !attrsRegex.test(attrs)) {
Expand Down Expand Up @@ -133,6 +148,7 @@ export const updateSriHashes = async (logger, distDir, content, h) => {
const resourcePath = resolve(distDir, `.${src}`)
resourceContent = await readFile(resourcePath)
} else if (src.startsWith('http')) {
setCrossorigin = true
const resourceResponse = await fetch(src, { method: 'GET' })
resourceContent = await resourceResponse.arrayBuffer()
} else {
Expand All @@ -153,7 +169,7 @@ export const updateSriHashes = async (logger, distDir, content, h) => {
if (sriHash) {
updatedContent = updatedContent.replace(
match[0],
replacer(sriHash, attrs, content),
replacer(sriHash, attrs, setCrossorigin, content),
)
}
}
Expand Down
9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@kindspells/astro-sri-csp",
"version": "0.4.0",
"version": "0.4.1",
"description": "An Astro plugin to compute and inject SRI hashes for script and style tags",
"private": false,
"type": "module",
Expand Down Expand Up @@ -57,7 +57,12 @@
"typescript": "^5.3.3",
"vitest": "^1.2.2"
},
"repository": "github:KindSpells/astro-sri-csp",
"repository": {
"type": "git",
"url": "git+https://github.com/KindSpells/astro-sri-csp.git"
},
"homepage": "https://github.com/kindspells/astro-sri-csp?tab=readme-ov-file#readme",
"bugs": "https://github.com/KindSpells/astro-sri-csp/issues",
"funding": [
{
"type": "opencollective",
Expand Down
31 changes: 24 additions & 7 deletions tests/core.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,11 @@ describe('updateSriHashes', () => {

expect(updated).toEqual(expected)
expect(h.inlineScriptHashes.size).toBe(1)
expect(h.inlineScriptHashes.has('sha256-TWupyvVdPa1DyFqLnQMqRpuUWdS3nKPnz70IcS/1o3Q=')).toBe(true)
expect(
h.inlineScriptHashes.has(
'sha256-TWupyvVdPa1DyFqLnQMqRpuUWdS3nKPnz70IcS/1o3Q=',
),
).toBe(true)
expect(h.inlineStyleHashes.size).toBe(0)
expect(h.extScriptHashes.size).toBe(0)
expect(h.extStyleHashes.size).toBe(0)
Expand Down Expand Up @@ -170,7 +174,11 @@ describe('updateSriHashes', () => {

expect(updated).toEqual(expected)
expect(h.inlineStyleHashes.size).toBe(1)
expect(h.inlineStyleHashes.has('sha256-VATw/GI1Duwve1FGJ+z3c4gwulpBbeoGo1DqO20SdxM=')).toBe(true)
expect(
h.inlineStyleHashes.has(
'sha256-VATw/GI1Duwve1FGJ+z3c4gwulpBbeoGo1DqO20SdxM=',
),
).toBe(true)
expect(h.inlineScriptHashes.size).toBe(0)
expect(h.extScriptHashes.size).toBe(0)
expect(h.extStyleHashes.size).toBe(0)
Expand All @@ -191,7 +199,7 @@ describe('updateSriHashes', () => {
<title>My Test Page</title>
</head>
<body>
<script type="module" src="/core.mjs" integrity="sha256-GlpkA8WAeGW9d6jr04eDhYbHj9yNtaB4+Q/5HwOc05M="></script>
<script type="module" src="/core.mjs" integrity="sha256-S6eKDKBDQlWQK9iS6q12Tz4pn1xZUIq11GbJ1Kj3iA8="></script>
</body>
</html>`

Expand All @@ -205,14 +213,19 @@ describe('updateSriHashes', () => {

expect(updated).toEqual(expected)
expect(h.extScriptHashes.size).toBe(1)
expect(h.extScriptHashes.has('sha256-GlpkA8WAeGW9d6jr04eDhYbHj9yNtaB4+Q/5HwOc05M=')).toBe(true)
expect(
h.extScriptHashes.has(
'sha256-S6eKDKBDQlWQK9iS6q12Tz4pn1xZUIq11GbJ1Kj3iA8=',
),
).toBe(true)
expect(h.inlineScriptHashes.size).toBe(0)
expect(h.inlineStyleHashes.size).toBe(0)
expect(h.extStyleHashes.size).toBe(0)
})

it('adds sri hash to external script (cross origin)', async () => {
const remoteScript = 'https://raw.githubusercontent.com/KindSpells/astro-sri-csp/ae9521048f2129f633c075b7f7ef24e11bbd1884/main.mjs'
const remoteScript =
'https://raw.githubusercontent.com/KindSpells/astro-sri-csp/ae9521048f2129f633c075b7f7ef24e11bbd1884/main.mjs'
const content = `<html>
<head>
<title>My Test Page</title>
Expand All @@ -227,7 +240,7 @@ describe('updateSriHashes', () => {
<title>My Test Page</title>
</head>
<body>
<script type="module" src="${remoteScript}" integrity="sha256-i4WR4ifasidZIuS67Rr6Knsy7/hK1xbVTc8ZAmnAv1Q="></script>
<script type="module" src="${remoteScript}" integrity="sha256-i4WR4ifasidZIuS67Rr6Knsy7/hK1xbVTc8ZAmnAv1Q=" crossorigin="anonymous"></script>
</body>
</html>`

Expand All @@ -241,7 +254,11 @@ describe('updateSriHashes', () => {

expect(updated).toEqual(expected)
expect(h.extScriptHashes.size).toBe(1)
expect(h.extScriptHashes.has('sha256-i4WR4ifasidZIuS67Rr6Knsy7/hK1xbVTc8ZAmnAv1Q=')).toBe(true)
expect(
h.extScriptHashes.has(
'sha256-i4WR4ifasidZIuS67Rr6Knsy7/hK1xbVTc8ZAmnAv1Q=',
),
).toBe(true)
expect(h.inlineScriptHashes.size).toBe(0)
expect(h.inlineStyleHashes.size).toBe(0)
expect(h.extStyleHashes.size).toBe(0)
Expand Down
2 changes: 1 addition & 1 deletion vitest.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default defineConfig({
include: ['*.mjs'],
exclude: ['tests/**/*'],
thresholds: {
branches: 55.00,
branches: 60.0,
lines: 50.0,
functions: 50.0,
statements: 60.0,
Expand Down

0 comments on commit e5ebb22

Please sign in to comment.