http-security 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +21 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +17 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +20 -0
- data/README.md +90 -0
- data/Rakefile +34 -0
- data/http-security.gemspec +23 -0
- data/lib/http/security.rb +2 -0
- data/lib/http/security/exceptions.rb +8 -0
- data/lib/http/security/headers.rb +12 -0
- data/lib/http/security/headers/cache_control.rb +36 -0
- data/lib/http/security/headers/content_security_policy.rb +71 -0
- data/lib/http/security/headers/content_security_policy_report_only.rb +10 -0
- data/lib/http/security/headers/pragma.rb +24 -0
- data/lib/http/security/headers/public_key_pins.rb +60 -0
- data/lib/http/security/headers/public_key_pins_report_only.rb +10 -0
- data/lib/http/security/headers/set_cookie.rb +75 -0
- data/lib/http/security/headers/strict_transport_security.rb +29 -0
- data/lib/http/security/headers/x_content_type_options.rb +24 -0
- data/lib/http/security/headers/x_frame_options.rb +39 -0
- data/lib/http/security/headers/x_permitted_cross_domain_policies.rb +47 -0
- data/lib/http/security/headers/x_xss_protection.rb +34 -0
- data/lib/http/security/http_date.rb +13 -0
- data/lib/http/security/malformed_header.rb +33 -0
- data/lib/http/security/parsers.rb +14 -0
- data/lib/http/security/parsers/cache_control.rb +62 -0
- data/lib/http/security/parsers/content_security_policy.rb +128 -0
- data/lib/http/security/parsers/content_security_policy_report_only.rb +10 -0
- data/lib/http/security/parsers/expires.rb +19 -0
- data/lib/http/security/parsers/parser.rb +408 -0
- data/lib/http/security/parsers/pragma.rb +25 -0
- data/lib/http/security/parsers/public_key_pins.rb +43 -0
- data/lib/http/security/parsers/public_key_pins_report_only.rb +10 -0
- data/lib/http/security/parsers/set_cookie.rb +62 -0
- data/lib/http/security/parsers/strict_transport_security.rb +42 -0
- data/lib/http/security/parsers/x_content_type_options.rb +19 -0
- data/lib/http/security/parsers/x_frame_options.rb +47 -0
- data/lib/http/security/parsers/x_permitted_cross_domain_policies.rb +33 -0
- data/lib/http/security/parsers/x_xss_protection.rb +27 -0
- data/lib/http/security/response.rb +323 -0
- data/lib/http/security/version.rb +5 -0
- data/spec/data/alexa.csv +100 -0
- data/spec/headers/cache_control_spec.rb +40 -0
- data/spec/headers/content_security_policy_spec.rb +46 -0
- data/spec/headers/pragma_spec.rb +26 -0
- data/spec/headers/public_key_pins_spec.rb +68 -0
- data/spec/headers/set_cookie_spec.rb +122 -0
- data/spec/headers/strict_transport_security_spec.rb +39 -0
- data/spec/headers/x_content_type_options_spec.rb +26 -0
- data/spec/headers/x_frame_options_spec.rb +86 -0
- data/spec/headers/x_permitted_cross_domain_policies_spec.rb +108 -0
- data/spec/headers/x_xss_protection_spec.rb +59 -0
- data/spec/parsers/cache_control_spec.rb +26 -0
- data/spec/parsers/content_security_policy_report_only_spec.rb +48 -0
- data/spec/parsers/content_security_policy_spec.rb +74 -0
- data/spec/parsers/expires_spec.rb +71 -0
- data/spec/parsers/parser_spec.rb +317 -0
- data/spec/parsers/pragma_spec.rb +10 -0
- data/spec/parsers/public_key_pins_spec.rb +81 -0
- data/spec/parsers/set_cookie_spec.rb +55 -0
- data/spec/parsers/strict_transport_security_spec.rb +62 -0
- data/spec/parsers/x_content_type_options_spec.rb +10 -0
- data/spec/parsers/x_frame_options_spec.rb +24 -0
- data/spec/parsers/x_permitted_cross_domain_policies_spec.rb +34 -0
- data/spec/parsers/x_xss_protection_spec.rb +39 -0
- data/spec/response_spec.rb +262 -0
- data/spec/spec_helper.rb +13 -0
- data/tasks/alexa.rb +40 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 097f834633f8dfec6c6946ed5a1d6df6eb099dcf
|
4
|
+
data.tar.gz: 593a835d602354c2d1f815c211b743c53038e370
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5b2832989c451f162a1b0e5d41c9bca6be583f28a9d0f69e363ceed62e11b35f034d9a15db62ce35735a0209f6a3a48ccabb9ffdd3e781ba16094a7d7a831b7c
|
7
|
+
data.tar.gz: f70ba9dd6f347fc95c635ade11b081dd180a2bdd18a648ea20e80ba939d70a1fec4963927d9ab6786c3d6ae694dd45181c706e82d91da64f4cc7c5f0cc790ba3
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
language: ruby
|
2
|
+
sudo: false
|
3
|
+
rvm:
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0
|
6
|
+
- 2.1
|
7
|
+
- ruby-head
|
8
|
+
- jruby-19mode
|
9
|
+
- jruby-head
|
10
|
+
- rbx-2
|
11
|
+
matrix:
|
12
|
+
allow_failures:
|
13
|
+
- rvm: rbx-2
|
14
|
+
- rvm: jruby-19mode
|
15
|
+
- rvm: jruby-head
|
16
|
+
addons:
|
17
|
+
code_climate:
|
18
|
+
repo_token: 4e8013e9105e3dd8153da54825ce8fab58c7408dce36fa351ef35c51bb9b0b05
|
19
|
+
notifications:
|
20
|
+
slack:
|
21
|
+
secure: awgcYPnPALqyAn3H58d+qzQYezzEyuqr71GmU9AsXuOa3sGM1JVqmUOqgoXeykBcV8EV5DEO+65fCkc+GnBxyPjnyYyvzW7VEcj3xQdxyVgn9fK0a76Mp+ywoWOPG7t4Z8dIK3PCT12QO+XgGWiLA9YG10eRtGRRD1V2PCKv41Y=
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "Security Headers Documentation" --protected
|
data/ChangeLog.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
### 0.1.0 / 2015-07-09
|
2
|
+
|
3
|
+
* Initial release:
|
4
|
+
* `Cache-Control`
|
5
|
+
* `Content-Security-Policy`
|
6
|
+
* `Content-Security-Policy-Report-Only`
|
7
|
+
* `Expires`
|
8
|
+
* `Pragma`
|
9
|
+
* `Public-Key-Pins`
|
10
|
+
* `Public-Key-Pins-Report-Only`
|
11
|
+
* `Set-Cookie`
|
12
|
+
* `Strict-Transport-Security`
|
13
|
+
* `X-Content-Type-Options`
|
14
|
+
* `X-Frame-Options`
|
15
|
+
* `X-Permitted-Cross-Domain-Policies`
|
16
|
+
* `X-XSS-Protection
|
17
|
+
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem 'nokogiri'
|
7
|
+
|
8
|
+
gem 'rake'
|
9
|
+
gem 'rubygems-tasks', '~> 0.2'
|
10
|
+
|
11
|
+
gem 'rspec', '~> 3.0'
|
12
|
+
|
13
|
+
gem 'kramdown'
|
14
|
+
gem 'yard', '~> 0.8'
|
15
|
+
end
|
16
|
+
|
17
|
+
gem "codeclimate-test-reporter", group: :test, require: nil
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Trail of Bits
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# HTTP Security
|
2
|
+
|
3
|
+
* [Source](https://github.com/trailofbits/http-security)
|
4
|
+
* [Issues](https://github.com/trailofbits/http-security/issues)
|
5
|
+
* [Documentation](https://rubydoc.info/gems/http-security/frames)
|
6
|
+
|
7
|
+
[![Code Climate](https://codeclimate.com/github/trailofbits/http-security.png)](https://codeclimate.com/github/trailofbits/http-security) [![Build Status](https://travis-ci.org/trailofbits/http-security.svg)](https://travis-ci.org/trailofbits/http-security) [![Test Coverage](https://codeclimate.com/github/trailofbits/http-security/badges/coverage.svg)](https://codeclimate.com/github/trailofbits/http-security)
|
8
|
+
|
9
|
+
Security Headers is a parser for security-relevant HTTP headers. Each header
|
10
|
+
value is parsed and validated according to the syntax specified in its relevant
|
11
|
+
RFC.
|
12
|
+
|
13
|
+
Security Headers relies on [parslet] for constructing its parsing grammar.
|
14
|
+
|
15
|
+
Currently parsed security headers are:
|
16
|
+
|
17
|
+
* `Cache-Control`
|
18
|
+
* `Content-Security-Policy`
|
19
|
+
* `Content-Security-Policy-Report-Only`
|
20
|
+
* `Expires`
|
21
|
+
* `Pragma`
|
22
|
+
* `Public-Key-Pins`
|
23
|
+
* `Public-Key-Pins-Report-Only`
|
24
|
+
* `Set-Cookie`
|
25
|
+
* `Strict-Transport-Security`
|
26
|
+
* `X-Content-Type-Options`
|
27
|
+
* `X-Frame-Options`
|
28
|
+
* `X-Permitted-Cross-Domain-Policies`
|
29
|
+
* `X-XSS-Protection
|
30
|
+
|
31
|
+
## Example
|
32
|
+
|
33
|
+
require 'net/https'
|
34
|
+
response = Net::HTTP.get_response(URI('https://twitter.com/'))
|
35
|
+
|
36
|
+
require 'http/security'
|
37
|
+
headers = HTTP::Security::Response.parse(response)
|
38
|
+
|
39
|
+
headers.cache_control
|
40
|
+
# => #<HTTP::Security::Headers::CacheControl:0x00000002f65778 @private=nil, @max_age=nil, @no_cache=true>
|
41
|
+
|
42
|
+
headers.content_security_policy
|
43
|
+
# => #<HTTP::Security::Headers::ContentSecurityPolicy:0x00000002d8e238 @default_src="https:"@12, @script_src="'unsafe-inline' 'unsafe-eval' https:"@172, @object_src="https:"@153, @style_src="'unsafe-inline' https:"@220, @img_src="https: blob: data:"@98, @media_src="https: blob:"@128, @frame_src="https: twitter:"@73, @font_src="https: data:"@49, @connect_src="https:"@32, @report_uri=[#<URI::HTTPS:0x00000002d94250 URL:https://twitter.com/i/csp_report?a=NVQWGYLXFVZXO2LGOQ%3D%3D%3D%3D%3D%3D&ro=false;>], @sandbox=nil>
|
44
|
+
|
45
|
+
headers.expires
|
46
|
+
# => #<HTTP::Security::HTTPDate: Tue, 31 Mar 1981 00:00:00 GMT ((2444695j,0s,0n),+0s,2299161j)>
|
47
|
+
|
48
|
+
headers.pragma
|
49
|
+
# => #<HTTP::Security::Headers::Pragma:0x00000002ccc5e8 @no_cache=true>
|
50
|
+
|
51
|
+
headers.strict_transport_security
|
52
|
+
# => #<HTTP::Security::Headers::StrictTransportSecurity:0x00000002c928c0 @max_age=631138519, @include_sub_domains=nil>
|
53
|
+
|
54
|
+
headers.x_content_type_options
|
55
|
+
# => #<HTTP::Security::Headers::XContentTypeOptions:0x00000002a46e40 @no_sniff=true>
|
56
|
+
|
57
|
+
headers.x_frame_options
|
58
|
+
# => #<HTTP::Security::Headers::XFrameOptions:0x000000028163c8 @deny=nil, @same_origin=true, @allow_from=nil, @allow_all=nil>
|
59
|
+
|
60
|
+
headers.x_permitted_cross_domain_policies
|
61
|
+
# => nil
|
62
|
+
|
63
|
+
headers.x_xss_protection
|
64
|
+
# => #<HTTP::Security::Headers::XXSSProtection:0x0000000297a408 @enabled=true, @mode="block"@8, @report=nil>
|
65
|
+
|
66
|
+
## Requirements
|
67
|
+
|
68
|
+
* [ruby] >= 1.9.1
|
69
|
+
* [parslet] ~> 1.5
|
70
|
+
|
71
|
+
## Install
|
72
|
+
|
73
|
+
$ gem install http-security
|
74
|
+
|
75
|
+
## Testing
|
76
|
+
|
77
|
+
To run the RSpec tests:
|
78
|
+
|
79
|
+
$ rake spec
|
80
|
+
|
81
|
+
To test the parser against the Alexa Top 100:
|
82
|
+
|
83
|
+
$ rake spec:gauntlet
|
84
|
+
|
85
|
+
## License
|
86
|
+
|
87
|
+
See the {file:LICENSE.txt} file.
|
88
|
+
|
89
|
+
[ruby]: https://www.ruby-lang.org/
|
90
|
+
[parslet]: http://kschiess.github.io/parslet/
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler/setup'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e.message
|
9
|
+
warn "Run `gem install bundler` to install Bundler."
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rake'
|
14
|
+
require 'rubygems/tasks'
|
15
|
+
Gem::Tasks.new
|
16
|
+
|
17
|
+
require 'rspec/core/rake_task'
|
18
|
+
RSpec::Core::RakeTask.new
|
19
|
+
|
20
|
+
namespace :spec do
|
21
|
+
desc "Tests SecurityHeaders::Parser against Alexa Top 500"
|
22
|
+
RSpec::Core::RakeTask.new(:gauntlet) do |t|
|
23
|
+
t.rspec_opts = '--tag gauntlet'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
task :test => :spec
|
28
|
+
task :default => :spec
|
29
|
+
|
30
|
+
require 'yard'
|
31
|
+
YARD::Rake::YardocTask.new
|
32
|
+
task :doc => :yard
|
33
|
+
|
34
|
+
require_relative 'tasks/alexa'
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'http/security/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "http-security"
|
8
|
+
gem.version = HTTP::Security::VERSION
|
9
|
+
gem.authors = ["Dominic Owen", "Hal Brodigan"]
|
10
|
+
gem.email = ["dwowen20@gmail.com", "hal@trailofbits.com"]
|
11
|
+
gem.summary = %q{HTTP Security Header Parser}
|
12
|
+
gem.description = %q{HTTP Security Header Parser}
|
13
|
+
gem.homepage = "https://github.com/trailofbits/http-security#readme"
|
14
|
+
gem.license = "MIT"
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.required_ruby_version = '>= 1.9.1'
|
20
|
+
|
21
|
+
gem.add_dependency 'parslet', '~> 1.5'
|
22
|
+
gem.add_development_dependency "bundler", "~> 1.0"
|
23
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'http/security/headers/cache_control'
|
2
|
+
require 'http/security/headers/content_security_policy'
|
3
|
+
require 'http/security/headers/content_security_policy_report_only'
|
4
|
+
require 'http/security/headers/pragma'
|
5
|
+
require 'http/security/headers/public_key_pins'
|
6
|
+
require 'http/security/headers/public_key_pins_report_only'
|
7
|
+
require 'http/security/headers/set_cookie'
|
8
|
+
require 'http/security/headers/strict_transport_security'
|
9
|
+
require 'http/security/headers/x_content_type_options'
|
10
|
+
require 'http/security/headers/x_frame_options'
|
11
|
+
require 'http/security/headers/x_permitted_cross_domain_policies'
|
12
|
+
require 'http/security/headers/x_xss_protection'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module HTTP
|
2
|
+
module Security
|
3
|
+
module Headers
|
4
|
+
class CacheControl
|
5
|
+
|
6
|
+
attr_reader :max_age
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@private = options[:private]
|
10
|
+
@max_age = options[:max_age]
|
11
|
+
@no_cache = options[:no_cache]
|
12
|
+
end
|
13
|
+
|
14
|
+
def private?
|
15
|
+
!!@private
|
16
|
+
end
|
17
|
+
|
18
|
+
def no_cache?
|
19
|
+
!!@no_cache
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
directives = []
|
24
|
+
|
25
|
+
|
26
|
+
directives << "private" if @private
|
27
|
+
directives << "max-age=#{@max_age}" if @max_age
|
28
|
+
directives << "no-cache" if @no_cache
|
29
|
+
|
30
|
+
return directives.join(', ')
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module HTTP
|
2
|
+
module Security
|
3
|
+
module Headers
|
4
|
+
class ContentSecurityPolicy
|
5
|
+
|
6
|
+
attr_reader :default_src
|
7
|
+
|
8
|
+
attr_reader :script_src
|
9
|
+
|
10
|
+
attr_reader :object_src
|
11
|
+
|
12
|
+
attr_reader :style_src
|
13
|
+
|
14
|
+
attr_reader :img_src
|
15
|
+
|
16
|
+
attr_reader :media_src
|
17
|
+
|
18
|
+
attr_reader :frame_src
|
19
|
+
|
20
|
+
attr_reader :font_src
|
21
|
+
|
22
|
+
attr_reader :connect_src
|
23
|
+
|
24
|
+
# @return [Array<URI>]
|
25
|
+
attr_reader :report_uri
|
26
|
+
|
27
|
+
attr_reader :sandbox
|
28
|
+
|
29
|
+
def initialize(directives={})
|
30
|
+
@default_src = directives[:default_src]
|
31
|
+
@script_src = directives[:script_src]
|
32
|
+
@object_src = directives[:object_src]
|
33
|
+
@style_src = directives[:style_src]
|
34
|
+
@img_src = directives[:img_src]
|
35
|
+
@media_src = directives[:media_src]
|
36
|
+
@frame_src = directives[:frame_src]
|
37
|
+
@font_src = directives[:font_src]
|
38
|
+
@connect_src = directives[:connect_src]
|
39
|
+
|
40
|
+
@report_uri = Array(directives[:report_uri])
|
41
|
+
@sandbox = directives[:sandbox]
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
directives = []
|
46
|
+
|
47
|
+
directives << "default-src #{@default_src}" if @default_src
|
48
|
+
directives << "script-src #{@script_src}" if @script_src
|
49
|
+
directives << "object-src #{@object_src}" if @object_src
|
50
|
+
directives << "style-src #{@style_src}" if @style_src
|
51
|
+
directives << "img-src #{@img_src}" if @img_src
|
52
|
+
directives << "media-src #{@media_src}" if @media_src
|
53
|
+
directives << "frame-src #{@frame_src}" if @frame_src
|
54
|
+
directives << "font-src #{@font_src}" if @font_src
|
55
|
+
directives << "connect-src #{@connect_src}" if @connect_src
|
56
|
+
|
57
|
+
if @sandbox
|
58
|
+
directives << "sandbox #{@sandbox}"
|
59
|
+
end
|
60
|
+
|
61
|
+
unless @report_uri.empty?
|
62
|
+
directives << "report-uri #{@report_uri.join(' ')}"
|
63
|
+
end
|
64
|
+
|
65
|
+
return directives.join('; ')
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module HTTP
|
2
|
+
module Security
|
3
|
+
module Headers
|
4
|
+
class Pragma
|
5
|
+
|
6
|
+
def initialize(directives={})
|
7
|
+
@no_cache = directives[:no_cache]
|
8
|
+
end
|
9
|
+
|
10
|
+
def no_cache?
|
11
|
+
!!@no_cache
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
str = ''
|
16
|
+
str << 'no-cache' if @no_cache
|
17
|
+
|
18
|
+
return str
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module HTTP
|
2
|
+
module Security
|
3
|
+
module Headers
|
4
|
+
class PublicKeyPins
|
5
|
+
|
6
|
+
# @return [Hash{Symbol,String => Array<String>}]
|
7
|
+
attr_reader :pin
|
8
|
+
|
9
|
+
# @return [Integer]
|
10
|
+
attr_reader :max_age
|
11
|
+
|
12
|
+
# @return [URI::HTTP]
|
13
|
+
attr_reader :report_uri
|
14
|
+
|
15
|
+
def initialize(options={})
|
16
|
+
@pin = {}
|
17
|
+
|
18
|
+
options.each do |key,value|
|
19
|
+
if (key.kind_of?(Symbol) && key =~ /^pin_/)
|
20
|
+
@pin[key[4..-1].to_sym] = Array(value)
|
21
|
+
elsif (key.kind_of?(String) && key.start_with?('pin-'))
|
22
|
+
@pin[key[4..-1]] = Array(value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
@max_age = options[:max_age]
|
27
|
+
@include_sub_domains = options[:includesubdomains]
|
28
|
+
@report_uri = options[:report_uri]
|
29
|
+
@strict = options[:strict]
|
30
|
+
end
|
31
|
+
|
32
|
+
def include_sub_domains?
|
33
|
+
!!@include_sub_domains
|
34
|
+
end
|
35
|
+
|
36
|
+
def strict?
|
37
|
+
!!@strict
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
directives = []
|
42
|
+
|
43
|
+
@pin.each do |algorithm,fingerprints|
|
44
|
+
Array(fingerprints).each do |fingerprint|
|
45
|
+
directives << "pin-#{algorithm}=#{fingerprint.dump}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
directives << "max-age=#{@max_age}" if @max_age
|
50
|
+
directives << "includeSubdomains" if @include_sub_domains
|
51
|
+
directives << "report-uri=\"#{@report_uri}\"" if @report_uri
|
52
|
+
directives << "strict" if @strict
|
53
|
+
|
54
|
+
return directives.join('; ')
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|