-
Notifications
You must be signed in to change notification settings - Fork 2
/
index.ts
70 lines (59 loc) · 2.05 KB
/
index.ts
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
60
61
62
63
64
65
66
67
68
69
70
import { createHash } from 'crypto'
import { resolve } from 'path'
import { promises as fs } from 'fs'
import type { Plugin, Manifest } from 'vite'
export type Algorithm = 'sha256' | 'sha384' | 'sha512'
export interface Options {
/**
* Which hashing algorithms to use when calculate the integrity hash for each
* asset in the manifest.
*
* @default ['sha384']
*/
algorithms?: Algorithm[]
/**
* Path of the manifest files that should be read and augmented with the
* integrity hash, relative to `outDir`.
*
* @default ['manifest.json', 'manifest-assets.json']
*/
manifestPaths?: string[]
}
declare module 'vite' {
interface ManifestChunk {
integrity: string
}
}
export default function manifestSRI (options: Options = {}): Plugin {
const {
algorithms = ['sha384'],
manifestPaths = ['manifest.json', 'manifest-assets.json'],
} = options
return {
name: 'vite-plugin-manifest-sri',
apply: 'build',
enforce: 'post',
async writeBundle ({ dir }) {
await Promise.all(manifestPaths.map(path => augmentManifest(path, algorithms, dir!)))
},
}
}
async function augmentManifest (manifestPath: string, algorithms: string[], outDir: string) {
const resolveInOutDir = (path: string) => resolve(outDir, path)
manifestPath = resolveInOutDir(manifestPath)
const manifest: Manifest | undefined
= await fs.readFile(manifestPath, 'utf-8').then(JSON.parse, () => undefined)
if (manifest) {
await Promise.all(Object.values(manifest).map(async (chunk) => {
chunk.integrity = integrityForAsset(await fs.readFile(resolveInOutDir(chunk.file)), algorithms)
}))
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2))
}
}
function integrityForAsset (source: Buffer, algorithms: string[]) {
return algorithms.map(algorithm => calculateIntegrityHash(source, algorithm)).join(' ')
}
export function calculateIntegrityHash (source: Buffer, algorithm: string) {
const hash = createHash(algorithm).update(source).digest().toString('base64')
return `${algorithm.toLowerCase()}-${hash}`
}