shellscape / webpack-manifest-plugin

webpack plugin for generating asset manifests
MIT License
1.44k stars 184 forks source link

output file hash to manifest #35

Closed enapupe closed 7 years ago

enapupe commented 7 years ago

What do you guys think about adding hash information to manifest file so we can make use of SRI? https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity?

Subresource Integrity (SRI) is a security feature that enables browsers to verify that files they fetch (for example, from a CDN) are delivered without unexpected manipulation. It works by allowing you to provide a cryptographic hash that a fetched file must match.

mastilver commented 7 years ago

@enapupe Can you give me an output example?

enapupe commented 7 years ago

I could but I realize it's probably not webpack-manifest-plugin job.. I can totally accomplish it with just node. I have the assets path on my express server, I just need to calculate and serve it.

Anyway, I think a good output format would require changing the json object to something more complex like:

{
  "production.js": {
    "file": "production.0b86f4ea34734cae00b2.js",
    "hash": "[hash here]"
  }
}

I'll share my server implementation later.

enapupe commented 7 years ago

This is what I ended up with: https://github.com/CheesecakeLabs/react-redux-boilerplate/pull/41/files

I'm probably going to improve it a bit but overall that's the idea.

mastilver commented 7 years ago

I will probably add a reduce option that would allow you to do (in combination with https://github.com/waysact/webpack-subresource-integrity) :

reduce: (manifest, {chunkName, fileName, source}) => {
  return {
    ...manifest,
    [chunkName]: {
      file: fileName,
      hash: source.integrity
    }
  }; 
}
enapupe commented 7 years ago

Thank you sir!

mastilver commented 7 years ago

@enapupe NP, let me know how you manage to get it to work this: https://github.com/waysact/webpack-subresource-integrity

mastilver commented 7 years ago

Also would be awesome if you could send us a PR, to add an example under: examples/subresource-integrity ;)

enapupe commented 7 years ago

This would be a quick version of SRI hash impementation:

const path = require('path')
const fs = require('fs')
const crypto = require('crypto')

const checksum = (str, algorithm = 'sha384', encoding = 'base64') =>
  crypto.createHash(algorithm).update(str, 'utf8').digest(encoding)

const fileSum = (file, algorithm) =>
  checksum(fs.readFileSync(file), algorithm)

const calculateSRI = (file, algorithm = 'sha384') =>
  `${algorithm}-${fileSum(path.join('.', 'dist', file), algorithm)}`

[...]

new ManifestPlugin({
  fileName: 'production.stats.json',
  reduce: (manifest, { path: filePath, name }) => Object.assign({}, manifest, {
    [name]: {
      file: filePath,
      integrity: calculateSRI(filePath),
    },
  }),
}), 

And an example manifest json file for the above reduce:

{
  "production.css": {
    "file": "production.0a223be5ea0a5e9b73df.css",
    "integrity": "sha384-ghrMahQRvdaAOeuXUx8vTGYaJ4hOamp1x+TMFY6PM6PkNCnHEDEmgZCmcbiGQKTg"
  },
  "production.css.map": {
    "file": "production.0a223be5ea0a5e9b73df.css.map",
    "integrity": "sha384-T1VD7crFyHHqourMswVItpFz/U/b6r039gA9BWSCUD7VlV/8qWvj//ddxyQYwoC/"
  },
  "production.js": {
    "file": "production.0a223be5ea0a5e9b73df.js",
    "integrity": "sha384-HBAJ+je7l8y29QXxU+cJVK3+l4enaVpMNilziQYuyehDBq/SMvfYYR7NtAQV7ikv"
  },
  "production.js.map": {
    "file": "production.0a223be5ea0a5e9b73df.js.map",
    "integrity": "sha384-V4iQc+wLch9RpT8r/N2W16s4x/0Xv3Dpl894m0bAWWoCnfDUFf2VUMwkjTlDWihk"
  }
}
mastilver commented 7 years ago

Cool 👍 , I guess this wouldn't work with webpack-dev-server though

enapupe commented 7 years ago

Yeah, it reads from FS so no. But I'm not sure why it should... It seems unnecessary. Do you have any other ideas on how to get this? I looked into the second argument but I couldn't find any Stream or similar in-memory source.

RinkAttendant6 commented 6 years ago

@enapupe I tried the above code but it seems to run before the files are written to the file system?

Here's the error:

Error: ENOENT: no such file or directory, open '/media/GitHub/app1/public/blog/assets/js/contact-form.min.js'
    at Object.fs.openSync (fs.js:646:18)
    at Object.fs.readFileSync (fs.js:551:33)
    at fileSum (/media/GitHub/app1/webpack.config.js:26:77)
    at calculateSRI (/media/GitHub/app1/webpack.config.js:27:70)
    at files.reduce (/media/GitHub/app1/webpack.config.js:234:40)
    at Array.reduce (<anonymous>)
    at Object.generate (/media/GitHub/app1/webpack.config.js:228:46)
    at ManifestPlugin.<anonymous> (/media/GitHub/app1/node_modules/webpack-manifest-plugin/lib/plugin.js:153:28)
UXDart commented 6 years ago

I have the same problem as @RinkAttendant6 , the files are not there yet... using webpack 4... and using 'generate'... any idea? TIA