Skip to content

Commit

Permalink
Merge pull request #301 from alphagov/add-sri
Browse files Browse the repository at this point in the history
Add SRI
  • Loading branch information
elenatanasoiu authored May 15, 2017
2 parents 10d2348 + 4d58b1a commit ef86d0b
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Development

- Adds SRI to js and css assets ([PR #301](https://github.com/alphagov/govuk_template/pull/301)). This requires `sprockets-rails` >= 3.0 in the projects using this gem.

# 0.20.1
- Fix invalid html from Apple touch icons syntax ([PR #300]https://github.com/alphagov/govuk_template/pull/300) and
update icon sizes to match Apple specs
Expand Down
50 changes: 50 additions & 0 deletions build_tools/compiler/template_processor.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
require 'erb'
require 'active_support/core_ext/hash'
require 'active_support/core_ext/array'

module Compiler
class TemplateProcessor
Expand Down Expand Up @@ -39,5 +41,53 @@ def asset_path(file, options={})
def method_missing(name, *args)
puts "#{name} #{args.inspect}"
end

def stylesheet_link_tag(*sources)
options = exclude_sri_fields(sources.extract_options!)
sources.uniq.map { |source|
link_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => asset_path(source)
}.merge!(options)
tag(:link, tag_options(link_options))
}.join("\n")
end

def javascript_include_tag(*sources)
options = exclude_sri_fields(sources.extract_options!)
sources.uniq.map { |source|
script_options = {
"src" => asset_path(source)
}.merge!(options)
content_tag(:script, tag_options(script_options))
}.join("\n")
end

def exclude_sri_fields(options)
options.stringify_keys.except("integrity", "crossorigin")
end

def content_tag(name, options = nil)
"<#{name}#{options}></#{name}>"
end

def tag(name, options)
"<#{name}#{options}/>"
end

def tag_options(options)
return if options.empty?
output = "".dup
sep = " "
options.each_pair do |key, value|
if !value.nil?
output << sep
output << %(#{key}="#{value}")
end
end
output unless output.empty?
end

end
end
17 changes: 17 additions & 0 deletions docs/using-with-rails.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,20 @@ Or to add content to `<head>`, for stylesheets or similar:
```

Check out the [full list of blocks](template-blocks.md) you can use to customise the template.

## SRI

`govuk_template` >= 20.0.0 can be used together with `sprockets-rails` >= 3.0.0 in order to make use of the SRI

You can read more about SRI [here](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).

SRI will add an `integrity` attribute on your script tags:

`<script src="https://example.com/example.css"
integrity="sha384oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
crossorigin="anonymous"></script>`

The example above is generated automatically by sprockets-rails in your project if the integrity option is set to true:

`<%= stylesheet_script_tag 'example', integrity: true %>`

9 changes: 5 additions & 4 deletions source/views/layouts/govuk_template.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
<meta charset="utf-8" />
<title><%= content_for?(:page_title) ? yield(:page_title) : "GOV.UK - The best place to find government services and information" %></title>

<!--[if gt IE 8]><!--><link href="<%= asset_path "govuk-template.css" %>" media="screen" rel="stylesheet" /><!--<![endif]-->
<!--[if gt IE 8]><!--><%= stylesheet_link_tag "govuk-template.css", integrity: true, crossorigin: "anonymous" %><!--<![endif]-->
<!--[if IE 6]><link href="<%= asset_path "govuk-template-ie6.css" %>" media="screen" rel="stylesheet" /><![endif]-->
<!--[if IE 7]><link href="<%= asset_path "govuk-template-ie7.css" %>" media="screen" rel="stylesheet" /><![endif]-->
<!--[if IE 8]><link href="<%= asset_path "govuk-template-ie8.css" %>" media="screen" rel="stylesheet" /><![endif]-->
<link href="<%= asset_path "govuk-template-print.css" %>" media="print" rel="stylesheet" />
<%= stylesheet_link_tag "govuk-template-print.css", media: "print", integrity: true, crossorigin: "anonymous" %>

<!--[if IE 8]><link href="<%= asset_path "fonts-ie8.css" %>" media="all" rel="stylesheet" /><![endif]-->
<!--[if gte IE 9]><!--><link href="<%= asset_path "fonts.css" %>" media="all" rel="stylesheet" /><!--<![endif]-->
<!--[if lt IE 9]><script src="<%= asset_path "ie.js" %>"></script><![endif]-->
<!--[if gte IE 9]><!--><%= stylesheet_link_tag "fonts.css", media: "all", integrity: true, crossorigin: "anonymous" %><!--<![endif]-->
<!--[if gte IE 9]><!--><%= stylesheet_link_tag "fonts.css", media: "all", integrity: true, crossorigin: "anonymous" %><!--<![endif]-->
<!--[if lt IE 9]><%= javascript_include_tag "ie.js", integrity: true, crossorigin: "anonymous" %><![endif]-->

<link rel="shortcut icon" href="<%= asset_path 'favicon.ico' %>" type="image/x-icon" />
<%# the colour used for mask-icon is the standard palette $black from
Expand Down
1 change: 1 addition & 0 deletions spec/build_tools/compiler/django_processor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def valid_sections
let(:file) {"some/file.erb"}
subject {described_class.new(file)}

it_behaves_like "a processor"

describe "#handle_yield" do
valid_sections.each do |key, content|
Expand Down
1 change: 1 addition & 0 deletions spec/build_tools/compiler/ejs_processor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def valid_sections
let(:file) {"some/file.erb"}
subject {described_class.new(file)}

it_behaves_like "a processor"

describe "#handle_yield" do
valid_sections.each do |key, content|
Expand Down
1 change: 1 addition & 0 deletions spec/build_tools/compiler/jinja_processor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def valid_sections
let(:file) {"some/file.erb"}
subject {described_class.new(file)}

it_behaves_like "a processor"

describe "#handle_yield" do
valid_sections.each do |key, content|
Expand Down
11 changes: 11 additions & 0 deletions spec/build_tools/compiler/liquid_processor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'spec_helper'
require File.join(PROJECT_ROOT, 'build_tools/compiler/liquid_processor.rb')

describe Compiler::LiquidProcessor do

let(:file) {"some/file.erb"}
subject {described_class.new(file)}

it_behaves_like "a processor"

end
11 changes: 11 additions & 0 deletions spec/build_tools/compiler/mustache_inheritance_processor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'spec_helper'
require File.join(PROJECT_ROOT, 'build_tools/compiler/mustache_inheritance_processor.rb')

describe Compiler::MustacheInheritanceProcessor do

let(:file) {"some/file.erb"}
subject {described_class.new(file)}

it_behaves_like "a processor"

end
3 changes: 1 addition & 2 deletions spec/build_tools/compiler/mustache_processor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ def valid_sections
end

describe Compiler::MustacheProcessor do

let(:file) {"some/file.erb"}
subject {described_class.new(file)}

it_behaves_like "a processor"

describe "#handle_yield" do
valid_sections.each do |key, content|
Expand Down Expand Up @@ -64,5 +64,4 @@ def valid_sections
end
end
end

end
11 changes: 11 additions & 0 deletions spec/build_tools/compiler/plain_processor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'spec_helper'
require File.join(PROJECT_ROOT, 'build_tools/compiler/plain_processor.rb')

describe Compiler::PlainProcessor do

let(:file) {"some/file.erb"}
subject {described_class.new(file)}

it_behaves_like "a processor"

end
2 changes: 2 additions & 0 deletions spec/build_tools/compiler/play_processor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def expected_parameter_names
describe Compiler::PlayProcessor do
subject { described_class.new("dummy filename") }

it_behaves_like "a processor"

describe "top_of_page" do
it "declares all of the template parameters" do
expected_parameter_names.each do |parameter_name|
Expand Down
80 changes: 80 additions & 0 deletions spec/support/examples/processor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
require 'spec_helper'
require 'set'

shared_examples_for "a processor" do
let(:html_erb_file) { "a/file.css" }
let(:processor) { described_class.new(html_erb_file) }

describe "convert rails tags into html" do

let(:css_source) { "govuk-template.css" }
let(:js_source) { "ie.js" }

describe "#stylesheet_link_tag" do
let(:css_options) { {"media" => "print"} }
let(:sri_attributes) { {"integrity" => true, "crossorigin" => "anonymous"} }

it "should parse the stylesheet tag" do
expect(processor.stylesheet_link_tag(css_source)).to eql("<link rel=\"stylesheet\" media=\"screen\" href=\"#{processor.asset_path(css_source)}\"/>")
end

context "if css file is for print" do
it "should parse the stylesheet tag and extra options" do
expect(processor.stylesheet_link_tag(css_source, css_options)).to eql("<link rel=\"stylesheet\" media=\"print\" href=\"#{processor.asset_path(css_source)}\"/>")
end
end

context "if sri attributes are present, it should ignore them" do
it "should parse the stylesheet tag without the integrity attribute" do
expect(processor.stylesheet_link_tag(css_source, sri_attributes)).to eql("<link rel=\"stylesheet\" media=\"screen\" href=\"#{processor.asset_path(css_source)}\"/>")
end
end
end

describe "#javascript_include_tag" do
let(:js_options) { {"charset" => "UTF-8"} }
let(:sri_attributes) { {"integrity" => true, "crossorigin" => "anonymous"} }

it "should parse the javascript tag" do
expect(processor.javascript_include_tag(js_source)).to eql("<script src=\"#{processor.asset_path(js_source)}\"></script>")
end

it "should parse the javascript tag and extra options" do
expect(processor.javascript_include_tag(js_source, js_options)).to eql("<script src=\"#{processor.asset_path(js_source)}\" charset=\"UTF-8\"></script>")
end

it "if sri attributes are present, it should ignore them" do
expect(processor.javascript_include_tag(js_source, sri_attributes)).to eql("<script src=\"#{processor.asset_path(js_source)}\"></script>")
end
end

describe "#content_tag" do
it "should return the correct html script tag" do
expect(processor.content_tag(:script, " src=\"#{processor.asset_path(js_source)}\"")).to eql("<script src=\"#{processor.asset_path(js_source)}\"></script>")
end
end

describe "#tag" do
it "should return the correct html link tag" do
expect(processor.tag(:link, " rel=\"stylesheet\" media=\"screen\" href=\"#{processor.asset_path(css_source)}\"")).to eql("<link rel=\"stylesheet\" media=\"screen\" href=\"#{processor.asset_path(css_source)}\"/>")
end
end

describe "#tag_options" do
let(:options) { {"rel"=>"stylesheet", "media"=>"screen", "href"=>processor.asset_path(css_source) } }

it "flattens the hash into a string of quoted html attributes" do
expect(processor.tag_options(options)).to eql(" rel=\"stylesheet\" media=\"screen\" href=\"#{processor.asset_path(css_source)}\"")
end
end

describe "#exclude_sri_fields" do
let(:options) { {"rel"=>"stylesheet", "media"=>"screen", "href"=>processor.asset_path(css_source), "integrity" => true, "crossorigin" => "anonymous" } }

it "should remove the integrity and crossorigin keys from the hash" do
expect(processor.exclude_sri_fields(options)).to eql({"href" => processor.asset_path(css_source), "media" => "screen", "rel" => "stylesheet"})
end
end

end
end
6 changes: 6 additions & 0 deletions spec/support/uses_of_yield.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ def asset_path(*args)
def method_missing(name, *args)
puts "#{name} #{args.inspect}"
end

def stylesheet_link_tag(*sources)
end

def javascript_include_tag(*sources)
end
end

# return an array of unique values passed to yield in the templates
Expand Down

0 comments on commit ef86d0b

Please sign in to comment.