UNPKG

vite-plugin-html-security

Version:
59 lines (58 loc) 2.86 kB
import * as __WEBPACK_EXTERNAL_MODULE_crypto__ from "crypto"; import * as __WEBPACK_EXTERNAL_MODULE_fs__ from "fs"; import * as __WEBPACK_EXTERNAL_MODULE_path__ from "path"; import * as __WEBPACK_EXTERNAL_MODULE_lodash__ from "lodash"; const sriAssetsMap = []; const integrityAttrValueShaKey = "integrityAttrValueSha"; function getSRIHash(filePath) { try { const fileContent = (0, __WEBPACK_EXTERNAL_MODULE_fs__.readFileSync)(filePath); const hash = (0, __WEBPACK_EXTERNAL_MODULE_crypto__.createHash)("sha384"); hash.update(fileContent); return `sha384-${hash.digest("base64")}`; } catch (e) { return null; } } function src(options) { const config = (0, __WEBPACK_EXTERNAL_MODULE_lodash__.merge)({ outputDir: "dist" }, options); return { name: "vite-plugin-sri", apply: "build", enforce: "post", closeBundle () { sriAssetsMap.forEach((item)=>{ const htmlPath = (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(process.cwd(), config.outputDir, item.path); const sriHash = getSRIHash(/node_modules/.test(item.filePath) ? (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(process.cwd(), "node_modules", item.filePath.replace(/.*?node_modules/, "")) : item.filePath); let newHtml = (0, __WEBPACK_EXTERNAL_MODULE_fs__.readFileSync)(htmlPath, "utf-8"); if (sriHash) newHtml = newHtml.replace(item.match, (0, __WEBPACK_EXTERNAL_MODULE_lodash__.template)(item.matchTag)({ [integrityAttrValueShaKey]: sriHash })); (0, __WEBPACK_EXTERNAL_MODULE_fs__.writeFileSync)(htmlPath, newHtml); }); }, transformIndexHtml: { enforce: "post", transform (html, { bundle, path }) { if (!bundle) return html; const newHtml = html.replace(/<(link|script) ([^>]*?)(href|src)=("([^"]+)"|'([^']+)')([^>]*?)>/g, (match, tag, before, attr, quoteWrappedUrl, url1, url2)=>{ const url = (url1 || url2 || "").replace(/^(\.|\/)+/, ""); const asset = Object.values(bundle).find((b)=>b.fileName === url); const filePath = (0, __WEBPACK_EXTERNAL_MODULE_path__.join)(process.cwd(), config.outputDir, url); sriAssetsMap.push({ filePath, asset: !!asset, path, match, matchTag: `<${tag} ${before}${attr}=${quoteWrappedUrl} integrity="<%=${integrityAttrValueShaKey}%>" crossorigin="anonymous"${match.endsWith("/>") ? "/" : ""}>` }); return match; }); return newHtml; } } }; } export { src as default };