Skip to content

Commit

Permalink
feat: create provisional hashes module
Browse files Browse the repository at this point in the history
When the following conditions are met:
- loading the SRI middleware
- generating the hashes module is enabled
- the hashes module does not exist yet
Then:
Make the SRI middleware loader to generate a provisional hashes module
file based on the scripts and stylesheets found in /public/.

It likely won't help much because in real scenarios we'll have tons of
CSS and JS that are inside /src/ and pre-processed by Astro/Vite/Rollup,
but it's a good nice-to-have for simple sites.

Signed-off-by: Andres Correa Casablanca <[email protected]>
  • Loading branch information
castarco committed Mar 18, 2024
1 parent 9703f4e commit 3276183
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 15 deletions.
10 changes: 3 additions & 7 deletions e2e/e2e.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,9 @@ describe('middleware (hybrid)', () => {
['run', 'build'],
execOpts,
)
expect(buildStdout).toMatch(/run the build step again/)
const { stdout: buildStdout2 } = await execFile(
'pnpm',
['run', 'build'],
execOpts,
)
expect(buildStdout2).not.toMatch(/run the build step again/)
// TODO: Once we introduce more complex scripts, we might have to check
// again for the "run the build step again" message
expect(buildStdout).not.toMatch(/run the build step again/)
})

beforeEach(async () => {
Expand Down
52 changes: 46 additions & 6 deletions src/core.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import { createHash } from 'node:crypto'
import { readFile, writeFile } from 'node:fs/promises'
import { extname, resolve, relative } from 'node:path'
import { fileURLToPath } from 'node:url'

import { doesFileExist, scanDirectory } from './fs.mjs'

/**
Expand Down Expand Up @@ -624,7 +626,6 @@ export const processStaticFiles = async (
file => extname(file) === '.html',
)

// TODO: Remove temporary hack
await scanForNestedResources(logger, distDir, h)

if (!sriHashesModule) {
Expand All @@ -649,8 +650,6 @@ export const getMiddlewareHandler = globalHashes => {
const response = await next()
const content = await response.text()

// TODO: Use a "good & async" function, as updateDynamicPageSriHashes cannot
// perform certain async actions, like fetching external resources.
const { updatedContent } = await updateDynamicPageSriHashes(
console,
content,
Expand All @@ -676,16 +675,46 @@ const resolvedHashesVirtualModuleId = `\0${hashesVirtualModuleId}`
* @param {Logger} logger
* @param {boolean} enableStatic_SRI
* @param {string | undefined} sriHashesModule
* @param {string} publicDir
* @returns {Promise<string>}
*/
const loadVirtualMiddlewareModule = async (
logger,
enableStatic_SRI,
sriHashesModule,
publicDir,
) => {
let extraImports = ''
let staticHashesModuleLoader = ''

if (
enableStatic_SRI &&
sriHashesModule &&
!(await doesFileExist(sriHashesModule))
) {
const h = /** @satisfies {HashesCollection} */ {
inlineScriptHashes: new Set(),
inlineStyleHashes: new Set(),
extScriptHashes: new Set(),
extStyleHashes: new Set(),
perPageSriHashes: new Map(),
perResourceSriHashes: {
scripts: new Map(),
styles: new Map(),
},
}

// We generate a provisional hashes module. It won't contain the hashes for
// resources created by Astro, but it can be useful nonetheless.
await scanForNestedResources(logger, publicDir, h)
await generateSRIHashesModule(
logger,
h,
sriHashesModule,
false, // So we don't get redundant warnings
)
}

if (
enableStatic_SRI &&
sriHashesModule &&
Expand All @@ -711,8 +740,10 @@ try {
}
`
} else if (enableStatic_SRI && sriHashesModule) {
// Highly unlikely that this happens because of the provisional hashes
// module, but the world is a strange place.
logger.warn(
`The SRI hashes module "${sriHashesModule}" did not exist at build time, run the build step again`,
`The SRI hashes module "${sriHashesModule}" did not exist at build time. You may have to run the build step again`,
)
}

Expand Down Expand Up @@ -759,9 +790,15 @@ export const perResourceSriHashes = { scripts: {}, styles: {} }
* @param {Logger} logger
* @param {boolean} enableStatic_SRI
* @param {string | undefined} sriHashesModule
* @param {string} publicDir
* @return {import('vite').Plugin}
*/
const getViteMiddlewarePlugin = (logger, enableStatic_SRI, sriHashesModule) => {
const getViteMiddlewarePlugin = (
logger,
enableStatic_SRI,
sriHashesModule,
publicDir,
) => {
return {
name: 'vite-plugin-astro-shield',
resolveId(id) {
Expand All @@ -777,6 +814,7 @@ const getViteMiddlewarePlugin = (logger, enableStatic_SRI, sriHashesModule) => {
logger,
enableStatic_SRI,
sriHashesModule,
publicDir,
)
case resolvedHashesVirtualModuleId:
return await loadVirtualHashesModule(
Expand All @@ -798,11 +836,13 @@ const getViteMiddlewarePlugin = (logger, enableStatic_SRI, sriHashesModule) => {
*/
export const getAstroConfigSetup = (enableStatic_SRI, sriHashesModule) => {
/** @type {Required<Integration['hooks']>['astro:config:setup']} */
return async ({ logger, addMiddleware, updateConfig }) => {
return async ({ logger, addMiddleware, config, updateConfig }) => {
const publicDir = fileURLToPath(config.publicDir)
const plugin = getViteMiddlewarePlugin(
logger,
enableStatic_SRI,
sriHashesModule,
publicDir,
)
updateConfig({ vite: { plugins: [plugin] } })

Expand Down
4 changes: 2 additions & 2 deletions tests/core.test.mts
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ describe('updateStaticPageSriHashes', () => {
<title>My Test Page</title>
</head>
<body>
<script type="module" src="/core.mjs" integrity="sha256-KnjtswtmvdHQSShp8mURE9kt/62bvYGd5jCdjmbFDiI="></script>
<script type="module" src="/core.mjs" integrity="sha256-uuKlJNUZR/rbyOWMRTscDFZxsoXSYghDzld4ilR8Lrw="></script>
</body>
</html>`

Expand All @@ -379,7 +379,7 @@ describe('updateStaticPageSriHashes', () => {
expect(h.extScriptHashes.size).toBe(1)
expect(
h.extScriptHashes.has(
'sha256-KnjtswtmvdHQSShp8mURE9kt/62bvYGd5jCdjmbFDiI=',
'sha256-uuKlJNUZR/rbyOWMRTscDFZxsoXSYghDzld4ilR8Lrw=',
),
).toBe(true)
expect(h.inlineScriptHashes.size).toBe(0)
Expand Down

0 comments on commit 3276183

Please sign in to comment.