lib/safe_cookies.rb in safe_cookies-0.1.5 vs lib/safe_cookies.rb in safe_cookies-0.1.6
- old
+ new
@@ -7,12 +7,10 @@
require "rack"
# Naming:
# - application_cookies: cookies received from the application. The 'Set-Cookie' header is a string
# - request_cookies: cookies received from the client. Rack::Request#cookies returns a Hash of { 'name' => 'value' }
-# - response_cookies: cookies to be sent to the client
-# (= application_cookies + any cookies set in the middleware)
module SafeCookies
UnknownCookieError = Class.new(StandardError)
@@ -37,49 +35,44 @@
reset_instance_variables
@request = Rack::Request.new(env)
ensure_no_unknown_cookies_in_request!
+ # calling the next middleware
status, @headers, body = @app.call(env)
cache_application_cookies_string
- remove_application_cookies_from_request_cookies
- rewrite_application_cookies
+ enhance_application_cookies!
store_application_cookie_names
- fix_cookie_paths if fix_cookie_paths?
+
+ delete_cookies_on_bad_path if fix_cookie_paths?
rewrite_request_cookies unless cookies_have_been_rewritten_before?
[ status, @headers, body ]
end
private
def reset_instance_variables
- @request, @headers, @application_cookies = nil
+ @request, @headers, @application_cookies_string = nil
end
-
+
+ # Make sure we get notified if a client comes with an unregistered cookie,
+ # because we do not want any cookie not to be secured.
def ensure_no_unknown_cookies_in_request!
request_cookie_names = request_cookies.keys.map(&:to_s)
unknown_cookie_names = request_cookie_names - known_cookie_names
if unknown_cookie_names.any?
handle_unknown_cookies(unknown_cookie_names)
end
end
-
- def remove_application_cookies_from_request_cookies
- if @application_cookies
- application_cookie_names = @application_cookies.scan(COOKIE_NAME_REGEX)
- application_cookie_names.each do |cookie|
- request_cookies.delete(cookie)
- end
- end
- end
-
- def rewrite_application_cookies
- if @application_cookies
- cookies = @application_cookies.split("\n")
+
+ # Overwrites @header['Set-Cookie']
+ def enhance_application_cookies!
+ if @application_cookies_string
+ cookies = @application_cookies_string.split("\n")
# On Rack 1.1, cookie values sometimes contain trailing newlines.
# Example => ["foo=1; path=/\n", "bar=2; path=/"]
# Note that they also mess up browsers, when this array is merged
# again and the "Set-Cookie" header then contains double newlines.
@@ -94,27 +87,37 @@
# browser's request contained, so a `Rack::Request` can't parse it for
# us. A `Rack::Response` doesn't offer a way either.
@headers['Set-Cookie'] = cookies.join("\n")
end
end
-
+
+ # Store the names of cookies that are set by the application. We are already
+ # securing those and therefore do not need to rewrite them.
def store_application_cookie_names
- if @application_cookies
- application_cookie_names = stored_application_cookie_names + @application_cookies.scan(COOKIE_NAME_REGEX)
+ if @application_cookies_string
+ application_cookie_names = stored_application_cookie_names + @application_cookies_string.scan(COOKIE_NAME_REGEX)
application_cookies_string = application_cookie_names.uniq.join(KNOWN_COOKIES_DIVIDER)
set_cookie!(STORE_COOKIE_NAME, application_cookies_string, :expire_after => HELPER_COOKIES_LIFETIME)
end
end
- # This method takes all cookies sent with the request and rewrites them,
+ # This method takes the cookies sent with the request and rewrites them,
# making them both secure and http-only (unless specified otherwise in
# the configuration).
# With the SECURED_COOKIE_NAME cookie we remember the exact time that we
# rewrote the cookies.
def rewrite_request_cookies
- if request_cookies.any?
+ cookies_to_rewrite = request_cookies || []
+
+ # don't rewrite request cookies that the application is setting in the response
+ if @application_cookies_string
+ application_cookie_names = @application_cookies_string.scan(COOKIE_NAME_REGEX)
+ Util.except!(cookies_to_rewrite, *application_cookie_names)
+ end
+
+ if cookies_to_rewrite.any?
registered_cookies_in_request.each do |cookie_name, options|
value = request_cookies[cookie_name]
set_cookie!(cookie_name, value, options)
end
@@ -122,9 +125,10 @@
formatted_now = Rack::Utils.rfc2822(Time.now.gmtime)
set_cookie!(SECURED_COOKIE_NAME, formatted_now, :expire_after => HELPER_COOKIES_LIFETIME)
end
end
+ # API method
def handle_unknown_cookies(cookie_names)
raise SafeCookies::UnknownCookieError.new("Request for '#{@request.url}' had unknown cookies: #{cookie_names.join(', ')}")
end
end