Class: SecureHeaders::PublicKeyPins

Inherits:
Header
  • Object
show all
Includes:
Constants
Defined in:
lib/secure_headers/headers/public_key_pins.rb

Defined Under Namespace

Modules: Constants

Constant Summary

Constants included from Constants

Constants::CONFIG_KEY, Constants::DIRECTIVES, Constants::ENV_KEY, Constants::HASH_ALGORITHMS, Constants::HPKP_HEADER_NAME

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = nil) ⇒ PublicKeyPins

Returns a new instance of PublicKeyPins.



18
19
20
21
22
23
24
25
26
27
# File 'lib/secure_headers/headers/public_key_pins.rb', line 18

def initialize(config=nil)
  @config = validate_config(config)

  @pins = @config.fetch(:pins, nil)
  @report_uri = @config.fetch(:report_uri, nil)
  @app_name = @config.fetch(:app_name, nil)
  @enforce = !!@config.fetch(:enforce, nil)
  @include_subdomains = !!@config.fetch(:include_subdomains, nil)
  @tag_report_uri = !!@config.fetch(:tag_report_uri, nil)
end

Class Method Details

.symbol_to_hyphen_case(sym) ⇒ Object



12
13
14
# File 'lib/secure_headers/headers/public_key_pins.rb', line 12

def symbol_to_hyphen_case sym
  sym.to_s.gsub('_', '-')
end

Instance Method Details

#build_directive(key) ⇒ Object



76
77
78
# File 'lib/secure_headers/headers/public_key_pins.rb', line 76

def build_directive(key)
  "#{self.class.symbol_to_hyphen_case(key)}=#{@config[key]}"
end

#generic_directivesObject



70
71
72
73
74
# File 'lib/secure_headers/headers/public_key_pins.rb', line 70

def generic_directives
  DIRECTIVES.collect do |directive_name|
    build_directive(directive_name) if @config[directive_name]
  end.join('; ')
end

#nameObject



29
30
31
32
33
34
35
# File 'lib/secure_headers/headers/public_key_pins.rb', line 29

def name
  base = HPKP_HEADER_NAME
  if !@enforce
    base += "-Report-Only"
  end
  base
end

#pin_directivesObject



61
62
63
64
65
66
67
68
# File 'lib/secure_headers/headers/public_key_pins.rb', line 61

def pin_directives
  return nil if @pins.nil?
  @pins.collect do |pin|
    pin.map do |token, hash|
      "pin-#{token}=\"#{hash}\"" if HASH_ALGORITHMS.include?(token)
    end
  end.join('; ')
end

#report_uri_directiveObject



80
81
82
83
84
85
86
87
88
89
# File 'lib/secure_headers/headers/public_key_pins.rb', line 80

def report_uri_directive
  return nil if @report_uri.nil?

  if @tag_report_uri
    @report_uri = "#{@report_uri}?enforce=#{@enforce}"
    @report_uri += "&app_name=#{@app_name}" if @app_name
  end

  "report-uri=\"#{@report_uri}\""
end

#subdomain_directiveObject



92
93
94
# File 'lib/secure_headers/headers/public_key_pins.rb', line 92

def subdomain_directive
  @include_subdomains ? 'includeSubDomains' : nil
end

#validate_config(config) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/secure_headers/headers/public_key_pins.rb', line 46

def validate_config(config)
  raise PublicKeyPinsBuildError.new("config must be a hash.") unless config.is_a? Hash

  if !config[:max_age]
    raise PublicKeyPinsBuildError.new("max-age is a required directive.")
  elsif config[:max_age].to_s !~ /\A\d+\z/
    raise PublicKeyPinsBuildError.new("max-age must be a number.
                                      #{config[:max_age]} was supplied.")
  elsif config[:pins] && config[:pins].length < 2
    raise PublicKeyPinsBuildError.new("A minimum of 2 pins are required.")
  end

  config
end

#valueObject



37
38
39
40
41
42
43
44
# File 'lib/secure_headers/headers/public_key_pins.rb', line 37

def value
  header_value = [
    generic_directives,
    pin_directives,
    report_uri_directive,
    subdomain_directive
  ].compact.join('; ').strip
end