Sprockets supported subresource integrity out of the box. It would be nice if
javascript_pack_tag 'vendor', integrity: true, crossorigin: 'anonymous'
worked the same. There is a webpack plugin but I am not sure how to hook it up to Rails to put the integrity hashes into the template.
@Gargron Will take a look at this 👍
Any new on this ? ^-^
This ticket is three days old. Gaurav is doing an excellent job
investigating the many requests put forward here, but let's not burn him
out with incessant pestering on issues that were just opened but have not
yet progressed. If you want to contribute a PR with a proposed solution,
that's awesome. But otherwise please have some patience. Thanks!
On Sun, May 7, 2017 at 5:01 PM, Technowix notifications@github.com wrote:
Any new on this ? ^-^
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/rails/webpacker/issues/323#issuecomment-299712030,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAKtdEzZp6Tj5JWYawOuFWtnAH92CFQks5r3dzhgaJpZM4NQFuj
.
Just to update everyone here, this feature is on hold for now as I couldn't find any straightforward solution to this problem (something that doesn't make things complicated).
Feel free to leave any suggestions/ideas here though 👍
I just looked at my production Sprockets manifest and I can see that it contains the SRI digest for my packs:
{
"files": {
"manifest-d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6.js": {
"logical_path": "manifest.js",
"mtime": "2017-03-23T17:25:57+00:00",
"size": 0,
"digest": "d0ff5974b6aa52cf562bea5921840c032a860a91a3512f7fe8f768f6bbe005f6",
"integrity": "sha256-0P9ZdLaqUs9WK+pZIYQMAyqGCpGjUS9/6Pdo9rvgBfY="
},
}
I know that Webpacker does not depend on Sprockets, but this seems the way to go. I am not sure why this is generated, but I think we should use the same mechanism: put the SRI digests (and in the future other informations?) in the manifest generated by Webpack.
The current webpack-manifest-plugin has a different format which does not allow other informations than the full path, but I dont think it would be hard to fork it and improve the manifest format, or output another manifest.
Some Webpack plugins already store the SRI attributes in Webpack'sstats object:
https://github.com/mikechau/sri-stats-webpack-plugin
https://github.com/waysact/webpack-subresource-integrity
I wont have time to work on this, but hopefully here are some ideas!
A new reduce option has been added to webpack-manifest-plugin.
This allows to customize the manifest, for example to include the SRI hash: https://github.com/danethurber/webpack-manifest-plugin/issues/35#issuecomment-313637413
Webpacker could ship with a webpack-manifest-plugin configuration that adds the needed attributes to the manifest, and then pass them to javascript_include_tag and stylesheet_pack_tag.
I would like to +1 @renchap's suggestion to use the new feature of webpack-manifest-plugin to generate multi-dimensional hashes in manifest.json. This approach strikes me as highly robust, with use cases extending beyond SRI hashes.
With a simple change of the structure of manifest.json from:
{
"application.js": "/packs/application-[DIGEST].js"
}
.. to:
{
"application.js": {
"path": "/packs/application-[DIGEST].js"
}
}
.. it immediately becomes possible to add all kinds of metadata into the manifest that could be appended by webpack plugins and then accessed through a universal interface provided by helpers.
Integrity hashes is just one piece of data that could be passed in here. Other data that comes to mind includes:
image_tag and even the alt attribute could gathered EXIF data.*_pack_tag any images/etc the stylesheet/javascript depends on can be optionally prefectched with <link rel="preload" href="[FOO]" as="[BAR]"> tags being inserted alongside the stylesheet/javascript include.I can probably think of more, (and I'm sure there are many custom situations) but you get the jist.
@gauravtiwari what are your thoughts on my comment above? I might be interested in making a PR (at least to preliminarily change the format of manifest.json and changing the ruby library to parse the different manifest format, but I don't want to step on your toes, nor do I don't want to submit a PR if it is going to be viewed as "too complicated".
Bump here. I think this would be awesome to first use the new structure for the manifest file, and then add others features based on it, starting with SRI :)
This does not look like a big change.
The new manifest plugin used in Webpacker 4 (https://github.com/webdeveric/webpack-assets-manifest) supports an integrity option. This adds all the needed hashes to the manifest, which can then be passed to the *_tag Rails helpers.
Yep, that's why used it so we can get this feature too at some point. Initially, I added the option but then it changes the manifest schema, which means rethinking the way the manifest class is structured in the gem and it's responsibilities (integration with the helper module) so this feature is slightly more involved.
@gauravtiwari, would a PR be accepted that implements this feature? Or does more discussion need to take place first (regarding the helper module, etc -- perhaps with the Rails team)? If the latter, where would be the best place to start it?
Any updates?
@jebenois
you can try my way.
in environment.js add next lines:
const manifestPlugin = environment.plugins.get('Manifest');
manifestPlugin.options.integrity = true;
and i created the new helper to replace stylesheet_pack_tag and javascript_pack_tag
def webpack_stylesheet_pack_tag filename, fallback = ""
if current_webpacker_instance.config.extract_css?
if Webpacker.manifest.lookup(filename)
stylesheet_link_tag(Webpacker.manifest.lookup(filename)["src"], integrity: Webpacker.manifest.lookup(filename)["integrity"], crossorigin: "anonymous")
else
stylesheet_link_tag(Webpacker.manifest.lookup(fallback)["src"], integrity: Webpacker.manifest.lookup(fallback)["integrity"], crossorigin: "anonymous")
end
end
end
def webpack_javascript_pack_tag filename, fallback = ""
if Webpacker.manifest.lookup(filename)
javascript_include_tag(Webpacker.manifest.lookup(filename)["src"], integrity: Webpacker.manifest.lookup(filename)["integrity"], crossorigin: "anonymous")
else
javascript_include_tag(Webpacker.manifest.lookup(fallback)["src"], integrity: Webpacker.manifest.lookup(fallback)["integrity"], crossorigin: "anonymous")
end
end
and use this methoud instead of webpacker methods.
But currently, it generated incorrect SHA sum :-(
I think there is a problem in the manifest plugin.
@gauravtiwari any news on making SRI functional with webpacker? i am willing to help with a PR if you can point to what needs addressing.
fwiw, we are using this somewhat hacky monkeypatch to make it work:
app/helpers/asset_helper.rb:
module AssetHelper
# this monkeypatch is needed to set the integrity attr to html tags for SRI
class Webpacker::Manifest
alias original_lookup lookup
def lookup(name, pack_type = {})
asset = original_lookup(name, pack_type)
(asset.respond_to?(:dig) && asset.dig('src')) || asset
end
def lookup_integrity(name, pack_type = {})
asset = original_lookup(name, pack_type)
(asset.respond_to?(:dig) && asset.dig('integrity')) || nil
end
end
module Webpacker::Helper
def javascript_pack_tag(*names, **options)
generic_packs_with_chunks_tag(:javascript, false, *names, **options)
end
def javascript_packs_with_chunks_tag(*names, **options)
generic_packs_with_chunks_tag(:javascript, true, *names, **options)
end
def stylesheet_pack_tag(*names, **options)
generic_packs_with_chunks_tag(:stylesheet, false, *names, **options)
end
def stylesheet_packs_with_chunks_tag(*names, **options)
generic_packs_with_chunks_tag(:stylesheet, true, *names, **options)
end
private
def generic_packs_with_chunks_tag(type, chunks, *names, **options)
return if type == :stylesheet && !current_webpacker_instance.config.extract_css?
entries = if chunks
sources_from_manifest_entrypoints(names, type: type)
else
sources_from_manifest_entries(names, type: type)
end
entries.map do |entry|
name = entry.match(%r{\A.+/([^/]+)(?:-[a-z0-9]{8,20})(?:\.chunk)?\.(?:js|css)\z}) && Regexp.last_match(1)
if name
integrity = Webpacker.manifest.lookup_integrity(name, type: type)
if integrity
options = options.merge(integrity: integrity, crossorigin: 'anonymous')
end
else
logger.error { "ERROR failed to find #{entry} in manifest" }
end
case type
when :stylesheet
stylesheet_link_tag(entry, **options)
when :javascript
javascript_include_tag(entry, **options)
else
raise "unknown type: #{type}"
end
end.join("\n").html_safe # rubocop:disable Rails/OutputSafety
end
end
end
config/webpack/environment.js:
// Webpacker uses this plugin to generate its manifest but
// at present it does not generate the integrity for each asset.
const manifestPlugin = environment.plugins.get('Manifest');
manifestPlugin.options.integrity = true;
manifestPlugin.options.integrityHashes = ['sha256'];
@gsar, thanks for your solution. Unfortunately, it wasn't working for me. I'm on Rails 6.0.2.1
Any plans to officially support this?
Most helpful comment
Any updates?