Class: Otto::Security::Config::SecurityHeaders
- Inherits:
-
Hash
- Object
- Hash
- Otto::Security::Config::SecurityHeaders
- Defined in:
- lib/otto/security/config.rb
Overview
Hash-compatible storage that keeps the generic security-header API and the dedicated referrer_policy setting on one validated code path. Existing callers may continue to mutate Config#security_headers like a Hash. Every destructive Hash operation keeps the required Referrer-Policy entry canonical, validates any replacement before committing it, and prevents removal of the dedicated setting.
Constant Summary collapse
- REFERRER_POLICY_HEADER =
'referrer-policy'- REFERRER_POLICY_REMOVAL_MESSAGE =
'referrer-policy cannot be removed; assign a valid referrer_policy token instead'
Instance Method Summary collapse
- #[]=(header, value) ⇒ Object (also: #store)
-
#clear ⇒ Object
Clearing custom security headers must not remove Otto's required, dedicated referrer_policy setting.
-
#compare_by_identity ⇒ Object
Identity comparison would make normal String lookups miss the canonical Referrer-Policy key and create apparent duplicates.
- #delete(header) ⇒ Object
- #delete_if(&block) ⇒ Object
-
#initialize(referrer_policy_validator) ⇒ SecurityHeaders
constructor
A new instance of SecurityHeaders.
- #keep_if(&block) ⇒ Object
- #merge!(*other_hashes) ⇒ Object (also: #update)
- #reject!(&block) ⇒ Object
- #replace(other_hash) ⇒ Object
- #select!(&block) ⇒ Object (also: #filter!)
-
#shift ⇒ Object
Remove the first non-Referrer-Policy entry, keeping the dedicated setting even when it is the only entry left.
-
#transform_keys!(*args, &block) ⇒ Object
Hash#transform_keys! accepts an optional key-mapping Hash, a block, or both (the mapping wins for keys it contains).
- #transform_values! ⇒ Object
Constructor Details
#initialize(referrer_policy_validator) ⇒ SecurityHeaders
Returns a new instance of SecurityHeaders.
59 60 61 62 |
# File 'lib/otto/security/config.rb', line 59 def initialize(referrer_policy_validator) @referrer_policy_validator = referrer_policy_validator super() end |
Instance Method Details
#[]=(header, value) ⇒ Object Also known as: store
64 65 66 67 68 69 70 71 |
# File 'lib/otto/security/config.rb', line 64 def []=(header, value) if referrer_policy_header?(header) validated = @referrer_policy_validator.call(value).dup.freeze super(REFERRER_POLICY_HEADER, validated) else super end end |
#clear ⇒ Object
Clearing custom security headers must not remove Otto's required, dedicated referrer_policy setting.
104 105 106 107 108 109 |
# File 'lib/otto/security/config.rb', line 104 def clear policy = self[REFERRER_POLICY_HEADER] super self[REFERRER_POLICY_HEADER] = policy self end |
#compare_by_identity ⇒ Object
Identity comparison would make normal String lookups miss the canonical Referrer-Policy key and create apparent duplicates.
185 186 187 |
# File 'lib/otto/security/config.rb', line 185 def compare_by_identity raise ArgumentError, 'security_headers cannot use identity comparison' end |
#delete(header) ⇒ Object
111 112 113 114 115 |
# File 'lib/otto/security/config.rb', line 111 def delete(header, &) raise ArgumentError, REFERRER_POLICY_REMOVAL_MESSAGE if referrer_policy_header?(header) super end |
#delete_if(&block) ⇒ Object
117 118 119 120 121 |
# File 'lib/otto/security/config.rb', line 117 def delete_if(&block) return enum_for(__method__) unless block filter_entries!(remove_when: true, return_nil_when_unchanged: false, &block) end |
#keep_if(&block) ⇒ Object
129 130 131 132 133 |
# File 'lib/otto/security/config.rb', line 129 def keep_if(&block) return enum_for(__method__) unless block filter_entries!(remove_when: false, return_nil_when_unchanged: false, &block) end |
#merge!(*other_hashes) ⇒ Object Also known as: update
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/otto/security/config.rb', line 74 def merge!(*other_hashes) raise FrozenError, "can't modify frozen #{self.class}" if frozen? replacement = dup other_hashes.each do |other_hash| converted = Hash.try_convert(other_hash) raise TypeError, "no implicit conversion of #{other_hash.class} into Hash" unless converted converted.each_pair do |header, value| key = referrer_policy_header?(header) ? REFERRER_POLICY_HEADER : header value = yield(key, replacement[key], value) if block_given? && replacement.key?(key) replacement[key] = value end end super(replacement, &nil) end |
#reject!(&block) ⇒ Object
123 124 125 126 127 |
# File 'lib/otto/security/config.rb', line 123 def reject!(&block) return enum_for(__method__) unless block filter_entries!(remove_when: true, return_nil_when_unchanged: true, &block) end |
#replace(other_hash) ⇒ Object
93 94 95 96 97 98 99 100 |
# File 'lib/otto/security/config.rb', line 93 def replace(other_hash) replacement = self.class.new(@referrer_policy_validator) replacement.merge!(other_hash) replacement[REFERRER_POLICY_HEADER] = self[REFERRER_POLICY_HEADER] unless replacement.key?( REFERRER_POLICY_HEADER ) super(replacement) end |
#select!(&block) ⇒ Object Also known as: filter!
135 136 137 138 139 |
# File 'lib/otto/security/config.rb', line 135 def select!(&block) return enum_for(__method__) unless block filter_entries!(remove_when: false, return_nil_when_unchanged: true, &block) end |
#shift ⇒ Object
Remove the first non-Referrer-Policy entry, keeping the dedicated setting even when it is the only entry left.
144 145 146 147 148 149 150 151 |
# File 'lib/otto/security/config.rb', line 144 def shift raise FrozenError, "can't modify frozen #{self.class}" if frozen? header = each_key.find { |key| !referrer_policy_header?(key) } return nil unless header [header, delete(header)] end |
#transform_keys!(*args, &block) ⇒ Object
Hash#transform_keys! accepts an optional key-mapping Hash, a block, or both (the mapping wins for keys it contains). Referrer-Policy may change case but cannot be renamed to a different field.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/otto/security/config.rb', line 164 def transform_keys!(*args, &block) if args.empty? && !block return enum_for(__method__, *args) elsif args.length > 1 raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 0..1)" end mapping = args.first replacement = self.class.new(@referrer_policy_validator) each_pair do |header, value| transformed = transformed_header(header, mapping, block) raise ArgumentError, REFERRER_POLICY_REMOVAL_MESSAGE if referrer_policy_header?(header) && !referrer_policy_header?(transformed) replacement[transformed] = value end replace(replacement) end |
#transform_values! ⇒ Object
153 154 155 156 157 158 159 |
# File 'lib/otto/security/config.rb', line 153 def transform_values! return enum_for(__method__) unless block_given? replacement = self.class.new(@referrer_policy_validator) each_pair { |header, value| replacement[header] = yield(value) } replace(replacement) end |