secure_headers 6.3.4 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +2 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +8 -0
- data/lib/secure_headers/configuration.rb +6 -5
- data/lib/secure_headers/headers/content_security_policy.rb +20 -34
- data/lib/secure_headers/headers/content_security_policy_config.rb +2 -0
- data/lib/secure_headers/headers/policy_management.rb +40 -7
- data/lib/secure_headers/version.rb +1 -1
- data/lib/secure_headers/view_helper.rb +7 -6
- data/secure_headers.gemspec +3 -3
- data/spec/lib/secure_headers/headers/content_security_policy_spec.rb +29 -4
- data/spec/lib/secure_headers/headers/policy_management_spec.rb +8 -0
- data/spec/lib/secure_headers/view_helpers_spec.rb +5 -4
- metadata +12 -10
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: bafd5e6390db0f1975599ab34f1293986a5c0a1ced14f6cfeca47fd114ce87d4
         | 
| 4 | 
            +
              data.tar.gz: 177dc27fa8238fe1a8baa238f6baa244b2c03393f61269e9b417e5ea3a4a4bba
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 7a24f853958892e2780dec3cfd8f631d394c959cda6d3f8be5d701792fc1ce57d4141ca88e7b0980fcac979cc855a0c5bc9165a05b314fe281ce092a438f1fe1
         | 
| 7 | 
            +
              data.tar.gz: c082a3ee192452712f8e9c7ed18d5c21b5b3eb1712c3d9a4df44220093cf1be09a8e5384f5c8a8909820f1e0048c6d3b6915cc29081288bcf13361bf8cf7dbed
         | 
    
        data/.github/workflows/build.yml
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            name: Build + Test
         | 
| 2 | 
            -
            on: [pull_request]
         | 
| 2 | 
            +
            on: [pull_request, push]
         | 
| 3 3 |  | 
| 4 4 | 
             
            jobs:
         | 
| 5 5 | 
             
              build:
         | 
| @@ -7,7 +7,7 @@ jobs: | |
| 7 7 | 
             
                runs-on: ubuntu-latest
         | 
| 8 8 | 
             
                strategy:
         | 
| 9 9 | 
             
                  matrix:
         | 
| 10 | 
            -
                    ruby: [ '2. | 
| 10 | 
            +
                    ruby: [ '2.6', '2.7', '3.0', '3.1' ]
         | 
| 11 11 |  | 
| 12 12 | 
             
                steps:
         | 
| 13 13 | 
             
                - uses: actions/checkout@v2
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            3.1.1
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,11 @@ | |
| 1 | 
            +
            ## 6.5.0
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            - CSP: Remove source expression deduplication. (@lgarron) https://github.com/github/secure_headers/pull/499
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## 6.4.0
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            - CSP: Add support for trusted-types, require-trusted-types-for directive (@JackMc): https://github.com/github/secure_headers/pull/486
         | 
| 8 | 
            +
             | 
| 1 9 | 
             
            ## 6.3.4
         | 
| 2 10 |  | 
| 3 11 | 
             
            - CSP: Do not deduplicate alternate schema source expressions (@keithamus): https://github.com/github/secure_headers/pull/478
         | 
| @@ -84,11 +84,12 @@ module SecureHeaders | |
| 84 84 | 
             
                  def deep_copy(config)
         | 
| 85 85 | 
             
                    return unless config
         | 
| 86 86 | 
             
                    config.each_with_object({}) do |(key, value), hash|
         | 
| 87 | 
            -
                      hash[key] = | 
| 88 | 
            -
                        value. | 
| 89 | 
            -
             | 
| 90 | 
            -
                         | 
| 91 | 
            -
             | 
| 87 | 
            +
                      hash[key] =
         | 
| 88 | 
            +
                        if value.is_a?(Array)
         | 
| 89 | 
            +
                          value.dup
         | 
| 90 | 
            +
                        else
         | 
| 91 | 
            +
                          value
         | 
| 92 | 
            +
                        end
         | 
| 92 93 | 
             
                    end
         | 
| 93 94 | 
             
                  end
         | 
| 94 95 |  | 
| @@ -7,17 +7,18 @@ module SecureHeaders | |
| 7 7 | 
             
                include PolicyManagement
         | 
| 8 8 |  | 
| 9 9 | 
             
                def initialize(config = nil)
         | 
| 10 | 
            -
                  @config = | 
| 11 | 
            -
                    if config | 
| 12 | 
            -
                       | 
| 10 | 
            +
                  @config =
         | 
| 11 | 
            +
                    if config.is_a?(Hash)
         | 
| 12 | 
            +
                      if config[:report_only]
         | 
| 13 | 
            +
                        ContentSecurityPolicyReportOnlyConfig.new(config || DEFAULT_CONFIG)
         | 
| 14 | 
            +
                      else
         | 
| 15 | 
            +
                        ContentSecurityPolicyConfig.new(config || DEFAULT_CONFIG)
         | 
| 16 | 
            +
                      end
         | 
| 17 | 
            +
                    elsif config.nil?
         | 
| 18 | 
            +
                      ContentSecurityPolicyConfig.new(DEFAULT_CONFIG)
         | 
| 13 19 | 
             
                    else
         | 
| 14 | 
            -
                       | 
| 20 | 
            +
                      config
         | 
| 15 21 | 
             
                    end
         | 
| 16 | 
            -
                  elsif config.nil?
         | 
| 17 | 
            -
                    ContentSecurityPolicyConfig.new(DEFAULT_CONFIG)
         | 
| 18 | 
            -
                  else
         | 
| 19 | 
            -
                    config
         | 
| 20 | 
            -
                  end
         | 
| 21 22 |  | 
| 22 23 | 
             
                  @preserve_schemes = @config.preserve_schemes
         | 
| 23 24 | 
             
                  @script_nonce = @config.script_nonce
         | 
| @@ -34,11 +35,12 @@ module SecureHeaders | |
| 34 35 | 
             
                ##
         | 
| 35 36 | 
             
                # Return the value of the CSP header
         | 
| 36 37 | 
             
                def value
         | 
| 37 | 
            -
                  @value ||= | 
| 38 | 
            -
                     | 
| 39 | 
            -
             | 
| 40 | 
            -
                     | 
| 41 | 
            -
             | 
| 38 | 
            +
                  @value ||=
         | 
| 39 | 
            +
                    if @config
         | 
| 40 | 
            +
                      build_value
         | 
| 41 | 
            +
                    else
         | 
| 42 | 
            +
                      DEFAULT_VALUE
         | 
| 43 | 
            +
                    end
         | 
| 42 44 | 
             
                end
         | 
| 43 45 |  | 
| 44 46 | 
             
                private
         | 
| @@ -51,7 +53,9 @@ module SecureHeaders | |
| 51 53 | 
             
                def build_value
         | 
| 52 54 | 
             
                  directives.map do |directive_name|
         | 
| 53 55 | 
             
                    case DIRECTIVE_VALUE_TYPES[directive_name]
         | 
| 54 | 
            -
                    when :source_list, | 
| 56 | 
            +
                    when :source_list,
         | 
| 57 | 
            +
                         :require_sri_for_list, # require_sri is a simple set of strings that don't need to deal with symbol casing
         | 
| 58 | 
            +
                         :require_trusted_types_for_list
         | 
| 55 59 | 
             
                      build_source_list_directive(directive_name)
         | 
| 56 60 | 
             
                    when :boolean
         | 
| 57 61 | 
             
                      symbol_to_hyphen_case(directive_name) if @config.directive_value(directive_name)
         | 
| @@ -129,7 +133,7 @@ module SecureHeaders | |
| 129 133 | 
             
                    unless directive == REPORT_URI || @preserve_schemes
         | 
| 130 134 | 
             
                      source_list = strip_source_schemes(source_list)
         | 
| 131 135 | 
             
                    end
         | 
| 132 | 
            -
                     | 
| 136 | 
            +
                    source_list.uniq
         | 
| 133 137 | 
             
                  end
         | 
| 134 138 | 
             
                end
         | 
| 135 139 |  | 
| @@ -147,24 +151,6 @@ module SecureHeaders | |
| 147 151 | 
             
                  end
         | 
| 148 152 | 
             
                end
         | 
| 149 153 |  | 
| 150 | 
            -
                # Removes duplicates and sources that already match an existing wild card.
         | 
| 151 | 
            -
                #
         | 
| 152 | 
            -
                # e.g. *.github.com asdf.github.com becomes *.github.com
         | 
| 153 | 
            -
                def dedup_source_list(sources)
         | 
| 154 | 
            -
                  sources = sources.uniq
         | 
| 155 | 
            -
                  wild_sources = sources.select { |source| source =~ STAR_REGEXP }
         | 
| 156 | 
            -
             | 
| 157 | 
            -
                  if wild_sources.any?
         | 
| 158 | 
            -
                    schemes = sources.map { |source| [source, URI(source).scheme] }.to_h
         | 
| 159 | 
            -
                    sources.reject do |source|
         | 
| 160 | 
            -
                      !wild_sources.include?(source) &&
         | 
| 161 | 
            -
                        wild_sources.any? { |pattern| schemes[pattern] == schemes[source] && File.fnmatch(pattern, source) }
         | 
| 162 | 
            -
                    end
         | 
| 163 | 
            -
                  else
         | 
| 164 | 
            -
                    sources
         | 
| 165 | 
            -
                  end
         | 
| 166 | 
            -
                end
         | 
| 167 | 
            -
             | 
| 168 154 | 
             
                # Private: append a nonce to the script/style directories if script_nonce
         | 
| 169 155 | 
             
                # or style_nonce are provided.
         | 
| 170 156 | 
             
                def populate_nonces(directive, source_list)
         | 
| @@ -35,6 +35,7 @@ module SecureHeaders | |
| 35 35 | 
             
                  @report_only = nil
         | 
| 36 36 | 
             
                  @report_uri = nil
         | 
| 37 37 | 
             
                  @require_sri_for = nil
         | 
| 38 | 
            +
                  @require_trusted_types_for = nil
         | 
| 38 39 | 
             
                  @sandbox = nil
         | 
| 39 40 | 
             
                  @script_nonce = nil
         | 
| 40 41 | 
             
                  @script_src = nil
         | 
| @@ -44,6 +45,7 @@ module SecureHeaders | |
| 44 45 | 
             
                  @style_src = nil
         | 
| 45 46 | 
             
                  @style_src_elem = nil
         | 
| 46 47 | 
             
                  @style_src_attr = nil
         | 
| 48 | 
            +
                  @trusted_types = nil
         | 
| 47 49 | 
             
                  @worker_src = nil
         | 
| 48 50 | 
             
                  @upgrade_insecure_requests = nil
         | 
| 49 51 | 
             
                  @disable_nonce_backwards_compatibility = nil
         | 
| @@ -98,7 +98,19 @@ module SecureHeaders | |
| 98 98 | 
             
                  STYLE_SRC_ATTR
         | 
| 99 99 | 
             
                ].flatten.freeze
         | 
| 100 100 |  | 
| 101 | 
            -
                 | 
| 101 | 
            +
                # Experimental directives - these vary greatly in support
         | 
| 102 | 
            +
                # See MDN for details.
         | 
| 103 | 
            +
                # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types
         | 
| 104 | 
            +
                TRUSTED_TYPES = :trusted_types
         | 
| 105 | 
            +
                # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/require-trusted-types-for
         | 
| 106 | 
            +
                REQUIRE_TRUSTED_TYPES_FOR = :require_trusted_types_for
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                DIRECTIVES_EXPERIMENTAL = [
         | 
| 109 | 
            +
                  TRUSTED_TYPES,
         | 
| 110 | 
            +
                  REQUIRE_TRUSTED_TYPES_FOR,
         | 
| 111 | 
            +
                ].flatten.freeze
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                ALL_DIRECTIVES = (DIRECTIVES_1_0 + DIRECTIVES_2_0 + DIRECTIVES_3_0 + DIRECTIVES_EXPERIMENTAL).uniq.sort
         | 
| 102 114 |  | 
| 103 115 | 
             
                # Think of default-src and report-uri as the beginning and end respectively,
         | 
| 104 116 | 
             
                # everything else is in between.
         | 
| @@ -121,6 +133,7 @@ module SecureHeaders | |
| 121 133 | 
             
                  OBJECT_SRC                => :source_list,
         | 
| 122 134 | 
             
                  PLUGIN_TYPES              => :media_type_list,
         | 
| 123 135 | 
             
                  REQUIRE_SRI_FOR           => :require_sri_for_list,
         | 
| 136 | 
            +
                  REQUIRE_TRUSTED_TYPES_FOR => :require_trusted_types_for_list,
         | 
| 124 137 | 
             
                  REPORT_URI                => :source_list,
         | 
| 125 138 | 
             
                  PREFETCH_SRC              => :source_list,
         | 
| 126 139 | 
             
                  SANDBOX                   => :sandbox_list,
         | 
| @@ -130,6 +143,7 @@ module SecureHeaders | |
| 130 143 | 
             
                  STYLE_SRC                 => :source_list,
         | 
| 131 144 | 
             
                  STYLE_SRC_ELEM            => :source_list,
         | 
| 132 145 | 
             
                  STYLE_SRC_ATTR            => :source_list,
         | 
| 146 | 
            +
                  TRUSTED_TYPES             => :source_list,
         | 
| 133 147 | 
             
                  WORKER_SRC                => :source_list,
         | 
| 134 148 | 
             
                  UPGRADE_INSECURE_REQUESTS => :boolean,
         | 
| 135 149 | 
             
                }.freeze
         | 
| @@ -175,6 +189,7 @@ module SecureHeaders | |
| 175 189 | 
             
                ].freeze
         | 
| 176 190 |  | 
| 177 191 | 
             
                REQUIRE_SRI_FOR_VALUES = Set.new(%w(script style))
         | 
| 192 | 
            +
                REQUIRE_TRUSTED_TYPES_FOR_VALUES = Set.new(%w('script'))
         | 
| 178 193 |  | 
| 179 194 | 
             
                module ClassMethods
         | 
| 180 195 | 
             
                  # Public: generate a header name, value array that is user-agent-aware.
         | 
| @@ -270,7 +285,8 @@ module SecureHeaders | |
| 270 285 | 
             
                    source_list?(directive) ||
         | 
| 271 286 | 
             
                      sandbox_list?(directive) ||
         | 
| 272 287 | 
             
                      media_type_list?(directive) ||
         | 
| 273 | 
            -
                      require_sri_for_list?(directive)
         | 
| 288 | 
            +
                      require_sri_for_list?(directive) ||
         | 
| 289 | 
            +
                      require_trusted_types_for_list?(directive)
         | 
| 274 290 | 
             
                  end
         | 
| 275 291 |  | 
| 276 292 | 
             
                  # For each directive in additions that does not exist in the original config,
         | 
| @@ -278,11 +294,12 @@ module SecureHeaders | |
| 278 294 | 
             
                  def populate_fetch_source_with_default!(original, additions)
         | 
| 279 295 | 
             
                    # in case we would be appending to an empty directive, fill it with the default-src value
         | 
| 280 296 | 
             
                    additions.each_key do |directive|
         | 
| 281 | 
            -
                      directive = | 
| 282 | 
            -
                        directive.to_s. | 
| 283 | 
            -
             | 
| 284 | 
            -
                         | 
| 285 | 
            -
             | 
| 297 | 
            +
                      directive =
         | 
| 298 | 
            +
                        if directive.to_s.end_with?("_nonce")
         | 
| 299 | 
            +
                          directive.to_s.gsub(/_nonce/, "_src").to_sym
         | 
| 300 | 
            +
                        else
         | 
| 301 | 
            +
                          directive
         | 
| 302 | 
            +
                        end
         | 
| 286 303 | 
             
                      # Don't set a default if directive has an existing value
         | 
| 287 304 | 
             
                      next if original[directive]
         | 
| 288 305 | 
             
                      if FETCH_SOURCES.include?(directive)
         | 
| @@ -307,6 +324,10 @@ module SecureHeaders | |
| 307 324 | 
             
                    DIRECTIVE_VALUE_TYPES[directive] == :require_sri_for_list
         | 
| 308 325 | 
             
                  end
         | 
| 309 326 |  | 
| 327 | 
            +
                  def require_trusted_types_for_list?(directive)
         | 
| 328 | 
            +
                    DIRECTIVE_VALUE_TYPES[directive] == :require_trusted_types_for_list
         | 
| 329 | 
            +
                  end
         | 
| 330 | 
            +
             | 
| 310 331 | 
             
                  # Private: Validates that the configuration has a valid type, or that it is a valid
         | 
| 311 332 | 
             
                  # source expression.
         | 
| 312 333 | 
             
                  def validate_directive!(directive, value)
         | 
| @@ -324,6 +345,8 @@ module SecureHeaders | |
| 324 345 | 
             
                      validate_media_type_expression!(directive, value)
         | 
| 325 346 | 
             
                    when :require_sri_for_list
         | 
| 326 347 | 
             
                      validate_require_sri_source_expression!(directive, value)
         | 
| 348 | 
            +
                    when :require_trusted_types_for_list
         | 
| 349 | 
            +
                      validate_require_trusted_types_for_source_expression!(directive, value)
         | 
| 327 350 | 
             
                    else
         | 
| 328 351 | 
             
                      raise ContentSecurityPolicyConfigError.new("Unknown directive #{directive}")
         | 
| 329 352 | 
             
                    end
         | 
| @@ -368,6 +391,16 @@ module SecureHeaders | |
| 368 391 | 
             
                    end
         | 
| 369 392 | 
             
                  end
         | 
| 370 393 |  | 
| 394 | 
            +
                  # Private: validates that a require trusted types for expression:
         | 
| 395 | 
            +
                  # 1. is an array of strings
         | 
| 396 | 
            +
                  # 2. is a subset of ["'script'"]
         | 
| 397 | 
            +
                  def validate_require_trusted_types_for_source_expression!(directive, require_trusted_types_for_expression)
         | 
| 398 | 
            +
                    ensure_array_of_strings!(directive, require_trusted_types_for_expression)
         | 
| 399 | 
            +
                    unless require_trusted_types_for_expression.to_set.subset?(REQUIRE_TRUSTED_TYPES_FOR_VALUES)
         | 
| 400 | 
            +
                      raise ContentSecurityPolicyConfigError.new(%(require-trusted-types-for for must be a subset of #{REQUIRE_TRUSTED_TYPES_FOR_VALUES.to_a} but was #{require_trusted_types_for_expression}))
         | 
| 401 | 
            +
                    end
         | 
| 402 | 
            +
                  end
         | 
| 403 | 
            +
             | 
| 371 404 | 
             
                  # Private: validates that a source expression:
         | 
| 372 405 | 
             
                  # 1. is an array of strings
         | 
| 373 406 | 
             
                  # 2. does not contain any deprecated, now invalid values (inline, eval, self, none)
         | 
| @@ -147,12 +147,13 @@ module SecureHeaders | |
| 147 147 |  | 
| 148 148 | 
             
                def nonced_tag(type, content_or_options, block)
         | 
| 149 149 | 
             
                  options = {}
         | 
| 150 | 
            -
                  content = | 
| 151 | 
            -
                     | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 154 | 
            -
                     | 
| 155 | 
            -
             | 
| 150 | 
            +
                  content =
         | 
| 151 | 
            +
                    if block
         | 
| 152 | 
            +
                      options = content_or_options
         | 
| 153 | 
            +
                      capture(&block)
         | 
| 154 | 
            +
                    else
         | 
| 155 | 
            +
                      content_or_options.html_safe # :'(
         | 
| 156 | 
            +
                    end
         | 
| 156 157 | 
             
                  content_tag type, content, options.merge(nonce: _content_security_policy_nonce(type))
         | 
| 157 158 | 
             
                end
         | 
| 158 159 |  | 
    
        data/secure_headers.gemspec
    CHANGED
    
    | @@ -9,12 +9,12 @@ Gem::Specification.new do |gem| | |
| 9 9 | 
             
              gem.version       = SecureHeaders::VERSION
         | 
| 10 10 | 
             
              gem.authors       = ["Neil Matatall"]
         | 
| 11 11 | 
             
              gem.email         = ["neil.matatall@gmail.com"]
         | 
| 12 | 
            -
              gem. | 
| 13 | 
            -
              gem. | 
| 12 | 
            +
              gem.summary       = "Manages application of security headers with many safe defaults."
         | 
| 13 | 
            +
              gem.description   = 'Add easily configured security headers to responses
         | 
| 14 14 | 
             
                including content-security-policy, x-frame-options,
         | 
| 15 15 | 
             
                strict-transport-security, etc.'
         | 
| 16 16 | 
             
              gem.homepage      = "https://github.com/twitter/secureheaders"
         | 
| 17 | 
            -
              gem.license       = " | 
| 17 | 
            +
              gem.license       = "MIT"
         | 
| 18 18 | 
             
              gem.files         = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
         | 
| 19 19 | 
             
              gem.executables   = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
         | 
| 20 20 | 
             
              gem.test_files    = gem.files.grep(%r{^(test|spec|features)/})
         | 
| @@ -48,12 +48,12 @@ module SecureHeaders | |
| 48 48 | 
             
                    expect(csp.value).to eq("default-src * 'unsafe-inline' 'unsafe-eval' data: blob:")
         | 
| 49 49 | 
             
                  end
         | 
| 50 50 |  | 
| 51 | 
            -
                  it " | 
| 51 | 
            +
                  it "does not minify source expressions based on overlapping wildcards" do
         | 
| 52 52 | 
             
                    config = {
         | 
| 53 53 | 
             
                      default_src: %w(a.example.org b.example.org *.example.org https://*.example.org)
         | 
| 54 54 | 
             
                    }
         | 
| 55 55 | 
             
                    csp = ContentSecurityPolicy.new(config)
         | 
| 56 | 
            -
                    expect(csp.value).to eq("default-src *.example.org")
         | 
| 56 | 
            +
                    expect(csp.value).to eq("default-src a.example.org b.example.org *.example.org")
         | 
| 57 57 | 
             
                  end
         | 
| 58 58 |  | 
| 59 59 | 
             
                  it "removes http/s schemes from hosts" do
         | 
| @@ -101,8 +101,13 @@ module SecureHeaders | |
| 101 101 | 
             
                    expect(csp.value).to eq("default-src example.org; block-all-mixed-content")
         | 
| 102 102 | 
             
                  end
         | 
| 103 103 |  | 
| 104 | 
            -
                  it " | 
| 105 | 
            -
                    csp = ContentSecurityPolicy.new(default_src: %w(example.org | 
| 104 | 
            +
                  it "handles wildcard subdomain with wildcard port" do
         | 
| 105 | 
            +
                    csp = ContentSecurityPolicy.new(default_src: %w(https://*.example.org:*))
         | 
| 106 | 
            +
                    expect(csp.value).to eq("default-src *.example.org:*")
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                  it "deduplicates source expressions that match exactly (after scheme stripping)" do
         | 
| 110 | 
            +
                    csp = ContentSecurityPolicy.new(default_src: %w(example.org https://example.org example.org))
         | 
| 106 111 | 
             
                    expect(csp.value).to eq("default-src example.org")
         | 
| 107 112 | 
             
                  end
         | 
| 108 113 |  | 
| @@ -146,6 +151,11 @@ module SecureHeaders | |
| 146 151 | 
             
                    expect(csp.value).to eq("default-src 'self'; require-sri-for script style")
         | 
| 147 152 | 
             
                  end
         | 
| 148 153 |  | 
| 154 | 
            +
                  it "allows style as a require-trusted-types-for source" do
         | 
| 155 | 
            +
                    csp = ContentSecurityPolicy.new(default_src: %w('self'), require_trusted_types_for: %w(script))
         | 
| 156 | 
            +
                    expect(csp.value).to eq("default-src 'self'; require-trusted-types-for script")
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
             | 
| 149 159 | 
             
                  it "includes prefetch-src" do
         | 
| 150 160 | 
             
                    csp = ContentSecurityPolicy.new(default_src: %w('self'), prefetch_src: %w(foo.com))
         | 
| 151 161 | 
             
                    expect(csp.value).to eq("default-src 'self'; prefetch-src foo.com")
         | 
| @@ -185,6 +195,21 @@ module SecureHeaders | |
| 185 195 | 
             
                    csp = ContentSecurityPolicy.new({style_src: %w('self'), style_src_attr: %w('self')})
         | 
| 186 196 | 
             
                    expect(csp.value).to eq("style-src 'self'; style-src-attr 'self'")
         | 
| 187 197 | 
             
                  end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                  it "supports trusted-types directive" do
         | 
| 200 | 
            +
                    csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy)})
         | 
| 201 | 
            +
                    expect(csp.value).to eq("trusted-types blahblahpolicy")
         | 
| 202 | 
            +
                  end
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                  it "supports trusted-types directive with 'none'" do
         | 
| 205 | 
            +
                    csp = ContentSecurityPolicy.new({trusted_types: %w('none')})
         | 
| 206 | 
            +
                    expect(csp.value).to eq("trusted-types 'none'")
         | 
| 207 | 
            +
                  end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                  it "allows duplicate policy names in trusted-types directive" do
         | 
| 210 | 
            +
                    csp = ContentSecurityPolicy.new({trusted_types: %w(blahblahpolicy 'allow-duplicates')})
         | 
| 211 | 
            +
                    expect(csp.value).to eq("trusted-types blahblahpolicy 'allow-duplicates'")
         | 
| 212 | 
            +
                  end
         | 
| 188 213 | 
             
                end
         | 
| 189 214 | 
             
              end
         | 
| 190 215 | 
             
            end
         | 
| @@ -45,6 +45,7 @@ module SecureHeaders | |
| 45 45 | 
             
                      plugin_types: %w(application/x-shockwave-flash),
         | 
| 46 46 | 
             
                      prefetch_src: %w(fetch.com),
         | 
| 47 47 | 
             
                      require_sri_for: %w(script style),
         | 
| 48 | 
            +
                      require_trusted_types_for: %w('script'),
         | 
| 48 49 | 
             
                      script_src: %w('self'),
         | 
| 49 50 | 
             
                      style_src: %w('unsafe-inline'),
         | 
| 50 51 | 
             
                      upgrade_insecure_requests: true, # see https://www.w3.org/TR/upgrade-insecure-requests/
         | 
| @@ -53,6 +54,7 @@ module SecureHeaders | |
| 53 54 | 
             
                      script_src_attr: %w(example.com),
         | 
| 54 55 | 
             
                      style_src_elem: %w(example.com),
         | 
| 55 56 | 
             
                      style_src_attr: %w(example.com),
         | 
| 57 | 
            +
                      trusted_types: %w(abcpolicy),
         | 
| 56 58 |  | 
| 57 59 | 
             
                      report_uri: %w(https://example.com/uri-directive),
         | 
| 58 60 | 
             
                    }
         | 
| @@ -120,6 +122,12 @@ module SecureHeaders | |
| 120 122 | 
             
                    end.to raise_error(ContentSecurityPolicyConfigError)
         | 
| 121 123 | 
             
                  end
         | 
| 122 124 |  | 
| 125 | 
            +
                  it "rejects style for trusted types" do
         | 
| 126 | 
            +
                    expect do
         | 
| 127 | 
            +
                      ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(style_src: %w('self'), require_trusted_types_for: %w(script style), trusted_types: %w(abcpolicy))))
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 123 131 | 
             
                  # this is mostly to ensure people don't use the antiquated shorthands common in other configs
         | 
| 124 132 | 
             
                  it "performs light validation on source lists" do
         | 
| 125 133 | 
             
                    expect do
         | 
| @@ -6,7 +6,7 @@ class Message < ERB | |
| 6 6 | 
             
              include SecureHeaders::ViewHelpers
         | 
| 7 7 |  | 
| 8 8 | 
             
              def self.template
         | 
| 9 | 
            -
            <<-TEMPLATE
         | 
| 9 | 
            +
                <<-TEMPLATE
         | 
| 10 10 | 
             
            <% hashed_javascript_tag(raise_error_on_unrecognized_hash = true) do %>
         | 
| 11 11 | 
             
              console.log(1)
         | 
| 12 12 | 
             
            <% end %>
         | 
| @@ -62,9 +62,10 @@ TEMPLATE | |
| 62 62 | 
             
              end
         | 
| 63 63 |  | 
| 64 64 | 
             
              def content_tag(type, content = nil, options = nil, &block)
         | 
| 65 | 
            -
                content = | 
| 66 | 
            -
                   | 
| 67 | 
            -
             | 
| 65 | 
            +
                content =
         | 
| 66 | 
            +
                  if block_given?
         | 
| 67 | 
            +
                    capture(block)
         | 
| 68 | 
            +
                  end
         | 
| 68 69 |  | 
| 69 70 | 
             
                if options.is_a?(Hash)
         | 
| 70 71 | 
             
                  options = options.map { |k, v| " #{k}=#{v}" }
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: secure_headers
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 6. | 
| 4 | 
            +
              version: 6.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Neil Matatall
         | 
| 8 | 
            -
            autorequire: | 
| 8 | 
            +
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022- | 
| 11 | 
            +
            date: 2022-10-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rake
         | 
| @@ -24,7 +24,10 @@ dependencies: | |
| 24 24 | 
             
                - - ">="
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: '0'
         | 
| 27 | 
            -
            description:  | 
| 27 | 
            +
            description: |-
         | 
| 28 | 
            +
              Add easily configured security headers to responses
         | 
| 29 | 
            +
                  including content-security-policy, x-frame-options,
         | 
| 30 | 
            +
                  strict-transport-security, etc.
         | 
| 28 31 | 
             
            email:
         | 
| 29 32 | 
             
            - neil.matatall@gmail.com
         | 
| 30 33 | 
             
            executables: []
         | 
| @@ -99,9 +102,9 @@ files: | |
| 99 102 | 
             
            - spec/spec_helper.rb
         | 
| 100 103 | 
             
            homepage: https://github.com/twitter/secureheaders
         | 
| 101 104 | 
             
            licenses:
         | 
| 102 | 
            -
            -  | 
| 105 | 
            +
            - MIT
         | 
| 103 106 | 
             
            metadata: {}
         | 
| 104 | 
            -
            post_install_message: | 
| 107 | 
            +
            post_install_message:
         | 
| 105 108 | 
             
            rdoc_options: []
         | 
| 106 109 | 
             
            require_paths:
         | 
| 107 110 | 
             
            - lib
         | 
| @@ -116,11 +119,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 116 119 | 
             
                - !ruby/object:Gem::Version
         | 
| 117 120 | 
             
                  version: '0'
         | 
| 118 121 | 
             
            requirements: []
         | 
| 119 | 
            -
            rubygems_version: 3. | 
| 120 | 
            -
            signing_key: | 
| 122 | 
            +
            rubygems_version: 3.3.7
         | 
| 123 | 
            +
            signing_key:
         | 
| 121 124 | 
             
            specification_version: 4
         | 
| 122 | 
            -
            summary:  | 
| 123 | 
            -
              x-frame-options, strict-transport-security, etc.
         | 
| 125 | 
            +
            summary: Manages application of security headers with many safe defaults.
         | 
| 124 126 | 
             
            test_files:
         | 
| 125 127 | 
             
            - spec/lib/secure_headers/configuration_spec.rb
         | 
| 126 128 | 
             
            - spec/lib/secure_headers/headers/clear_site_data_spec.rb
         |