class SafeCookies::Middleware

Constants

Public Class Methods

new(app) click to toggle source
# File lib/safe_cookies.rb, line 30
def initialize(app)
  @app = app
  @config = SafeCookies.configuration or raise "Don't know what to do without configuration"
end

Public Instance Methods

call(env) click to toggle source
# File lib/safe_cookies.rb, line 35
def call(env)
  reset_instance_variables
  
  @request = Rack::Request.new(env)
  check_if_request_has_unknown_cookies

  # call the next middleware up the stack
  status, @headers, body = @app.call(env)
  cache_application_cookies_string
  
  enhance_application_cookies!
  store_application_cookie_names
  
  delete_cookies_on_bad_path if fix_cookie_paths?
  rewrite_request_cookies unless cookies_have_been_rewritten_before?

  [ status, @headers, body ]
end

Private Instance Methods

check_if_request_has_unknown_cookies() click to toggle source
# File lib/safe_cookies.rb, line 61
def check_if_request_has_unknown_cookies
  request_cookie_names = request_cookies.keys.map(&:to_s)
  unknown_cookie_names = request_cookie_names - known_cookie_names
  
  if unknown_cookie_names.any?
    message = "Request for '#{@request.url}' had unknown cookies: #{unknown_cookie_names.join(', ')}"
    log(message) if @config.log_unknown_cookies

    handle_unknown_cookies(unknown_cookie_names)
  end
end
enhance_application_cookies!() click to toggle source

Overwrites @header!

# File lib/safe_cookies.rb, line 74
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.
    cookies = cookies.
      map(&:strip).
      select{ |c| c.length > 0}.
      map(&method(:secure)).
      map(&method(:http_only))

    # Unfortunately there is no pretty way to touch a "Set-Cookie" header.
    # It contains more information than the "HTTP_COOKIE" header from the
    # 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
handle_unknown_cookies(cookie_names) click to toggle source

API method

# File lib/safe_cookies.rb, line 132
def handle_unknown_cookies(cookie_names)
end
log(error_message) click to toggle source
# File lib/safe_cookies.rb, line 135
def log(error_message)
  message = '** [SafeCookies] '
  message << error_message
  
  Rails.logger.error(message) if defined?(Rails)
end
reset_instance_variables() click to toggle source

Instance variables survive requests because the middleware is a singleton.

# File lib/safe_cookies.rb, line 57
def reset_instance_variables
  @request, @headers, @application_cookies_string = nil
end
rewrite_request_cookies() click to toggle source

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.

# File lib/safe_cookies.rb, line 112
def rewrite_request_cookies
  rewritable_cookies = rewritable_request_cookies
  
  # don't rewrite request cookies that the application is setting in the response
  if @application_cookies_string
    app_cookie_names = @application_cookies_string.scan(COOKIE_NAME_REGEX)
    Util.except!(rewritable_cookies, *app_cookie_names)
  end
  
  if rewritable_cookies.any?
    rewritable_cookies.each do |cookie_name, value|
      options = @config.registered_cookies[cookie_name]
      set_cookie!(cookie_name, value, options)
    end
  
    set_cookie!(SECURED_COOKIE_NAME, Time.now.gmtime.rfc2822, :expire_after => HELPER_COOKIES_LIFETIME)
  end
end