Skip to content

Commit fa56adc

Browse files
committed
extract cookies configuration validation to separate class
1 parent 075e495 commit fa56adc

File tree

2 files changed

+74
-59
lines changed

2 files changed

+74
-59
lines changed

lib/secure_headers/headers/cookie.rb

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,13 @@
11
require 'cgi'
2+
require 'secure_headers/utils/cookies_config'
23

34
module SecureHeaders
45
class CookiesConfigError < StandardError; end
56
class Cookie
67

78
class << self
89
def validate_config!(config)
9-
return if config.nil? || config == OPT_OUT
10-
raise CookiesConfigError.new("config must be a hash.") unless config.is_a? Hash
11-
12-
# secure and httponly - validate only boolean or Hash configuration
13-
[:secure, :httponly].each do |attribute|
14-
if config[attribute] && !(config[attribute].is_a?(Hash) || config[attribute].is_a?(TrueClass) || config[attribute].is_a?(FalseClass))
15-
raise CookiesConfigError.new("#{attribute} cookie config must be a hash or boolean")
16-
end
17-
end
18-
19-
# secure and httponly - validate exclusive use of only or except but not both at the same time
20-
[:secure, :httponly].each do |attribute|
21-
if config[attribute].is_a?(Hash)
22-
if config[attribute].key?(:only) && config[attribute].key?(:except)
23-
raise CookiesConfigError.new("#{attribute} cookie config is invalid, simultaneous use of conditional arguments `only` and `except` is not permitted.")
24-
end
25-
26-
if (intersection = (config[attribute].fetch(:only, []) & config[attribute].fetch(:only, []))).any?
27-
raise CookiesConfigError.new("#{attribute} cookie config is invalid, cookies #{intersection.join(', ')} cannot be enforced as lax and strict")
28-
end
29-
end
30-
end
31-
32-
if config[:samesite]
33-
raise CookiesConfigError.new("samesite cookie config must be a hash") unless config[:samesite].is_a?(Hash)
34-
35-
# when configuring with booleans, only one enforcement is permitted
36-
if config[:samesite].key?(:lax) && config[:samesite][:lax].is_a?(TrueClass) && config[:samesite].key?(:strict)
37-
raise CookiesConfigError.new("samesite cookie config is invalid, combination use of booleans and Hash to configure lax and strict enforcement is not permitted.")
38-
elsif config[:samesite].key?(:strict) && config[:samesite][:strict].is_a?(TrueClass) && config[:samesite].key?(:lax)
39-
raise CookiesConfigError.new("samesite cookie config is invalid, combination use of booleans and Hash to configure lax and strict enforcement is not permitted.")
40-
end
41-
42-
# validate Hash-based samesite configuration
43-
if config[:samesite].key?(:lax) && config[:samesite][:lax].is_a?(Hash)
44-
# validate exclusive use of only or except but not both at the same time
45-
if config[:samesite][:lax].key?(:only) && config[:samesite][:lax].key?(:except)
46-
raise CookiesConfigError.new("samesite lax cookie config is invalid, simultaneous use of conditional arguments `only` and `except` is not permitted.")
47-
end
48-
49-
if config[:samesite].key?(:strict)
50-
# validate exclusivity of only and except members
51-
if (intersection = (config[:samesite][:lax].fetch(:only, []) & config[:samesite][:strict].fetch(:only, []))).any?
52-
raise CookiesConfigError.new("samesite cookie config is invalid, cookie(s) #{intersection.join(', ')} cannot be enforced as lax and strict")
53-
end
54-
55-
if (intersection = (config[:samesite][:lax].fetch(:except, []) & config[:samesite][:strict].fetch(:except, []))).any?
56-
raise CookiesConfigError.new("samesite cookie config is invalid, cookie(s) #{intersection.join(', ')} cannot be enforced as lax and strict")
57-
end
58-
end
59-
end
60-
61-
if config[:samesite].key?(:strict) && config[:samesite][:strict].is_a?(Hash)
62-
# validate exclusive use of only or except but not both at the same time
63-
if config[:samesite][:strict].key?(:only) && config[:samesite][:strict].key?(:except)
64-
raise CookiesConfigError.new("samesite strict cookie config is invalid, simultaneous use of conditional arguments `only` and `except` is not permitted.")
65-
end
66-
end
67-
end
10+
CookiesConfig.new(config).valid?
6811
end
6912
end
7013

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
module SecureHeaders
2+
class CookiesConfig
3+
4+
attr_reader :config
5+
6+
def initialize(config)
7+
@config = config
8+
end
9+
10+
def valid?
11+
return if config.nil? || config == OPT_OUT
12+
raise CookiesConfigError.new("config must be a hash.") unless config.is_a? Hash
13+
14+
# secure and httponly - validate only boolean or Hash configuration
15+
[:secure, :httponly].each do |attribute|
16+
if config[attribute] && !(config[attribute].is_a?(Hash) || config[attribute].is_a?(TrueClass) || config[attribute].is_a?(FalseClass))
17+
raise CookiesConfigError.new("#{attribute} cookie config must be a hash or boolean")
18+
end
19+
end
20+
21+
# secure and httponly - validate exclusive use of only or except but not both at the same time
22+
[:secure, :httponly].each do |attribute|
23+
if config[attribute].is_a?(Hash)
24+
if config[attribute].key?(:only) && config[attribute].key?(:except)
25+
raise CookiesConfigError.new("#{attribute} cookie config is invalid, simultaneous use of conditional arguments `only` and `except` is not permitted.")
26+
end
27+
28+
if (intersection = (config[attribute].fetch(:only, []) & config[attribute].fetch(:only, []))).any?
29+
raise CookiesConfigError.new("#{attribute} cookie config is invalid, cookies #{intersection.join(', ')} cannot be enforced as lax and strict")
30+
end
31+
end
32+
end
33+
34+
if config[:samesite]
35+
raise CookiesConfigError.new("samesite cookie config must be a hash") unless config[:samesite].is_a?(Hash)
36+
37+
# when configuring with booleans, only one enforcement is permitted
38+
if config[:samesite].key?(:lax) && config[:samesite][:lax].is_a?(TrueClass) && config[:samesite].key?(:strict)
39+
raise CookiesConfigError.new("samesite cookie config is invalid, combination use of booleans and Hash to configure lax and strict enforcement is not permitted.")
40+
elsif config[:samesite].key?(:strict) && config[:samesite][:strict].is_a?(TrueClass) && config[:samesite].key?(:lax)
41+
raise CookiesConfigError.new("samesite cookie config is invalid, combination use of booleans and Hash to configure lax and strict enforcement is not permitted.")
42+
end
43+
44+
# validate Hash-based samesite configuration
45+
if config[:samesite].key?(:lax) && config[:samesite][:lax].is_a?(Hash)
46+
# validate exclusive use of only or except but not both at the same time
47+
if config[:samesite][:lax].key?(:only) && config[:samesite][:lax].key?(:except)
48+
raise CookiesConfigError.new("samesite lax cookie config is invalid, simultaneous use of conditional arguments `only` and `except` is not permitted.")
49+
end
50+
51+
if config[:samesite].key?(:strict)
52+
# validate exclusivity of only and except members
53+
if (intersection = (config[:samesite][:lax].fetch(:only, []) & config[:samesite][:strict].fetch(:only, []))).any?
54+
raise CookiesConfigError.new("samesite cookie config is invalid, cookie(s) #{intersection.join(', ')} cannot be enforced as lax and strict")
55+
end
56+
57+
if (intersection = (config[:samesite][:lax].fetch(:except, []) & config[:samesite][:strict].fetch(:except, []))).any?
58+
raise CookiesConfigError.new("samesite cookie config is invalid, cookie(s) #{intersection.join(', ')} cannot be enforced as lax and strict")
59+
end
60+
end
61+
end
62+
63+
if config[:samesite].key?(:strict) && config[:samesite][:strict].is_a?(Hash)
64+
# validate exclusive use of only or except but not both at the same time
65+
if config[:samesite][:strict].key?(:only) && config[:samesite][:strict].key?(:except)
66+
raise CookiesConfigError.new("samesite strict cookie config is invalid, simultaneous use of conditional arguments `only` and `except` is not permitted.")
67+
end
68+
end
69+
end
70+
end
71+
end
72+
end

0 commit comments

Comments
 (0)