module SafeCookies module CookiePathFix # Previously, the SafeCookies gem would not set a path when rewriting # cookies. Browsers then would assume and store the current "directory", # leading to multiple cookies per domain. # # If cookies had been secured before the configured datetime, the method # `fix_cookie_paths` deletes all cookies coming with the request, and the # SECURED_COOKIE_NAME helper cookie. # The middleware still sees the request cookies and will rewrite them as # if it hadn't seen them before. def fix_cookie_paths registered_cookies_in_request.keys.each do |registered_cookie| delete_cookie_for_current_directory(registered_cookie) end delete_cookie_for_current_directory(SafeCookies::SECURED_COOKIE_NAME) # Delete this cookie here, so the middleware will secure all cookies anew. @request.cookies.delete(SafeCookies::SECURED_COOKIE_NAME) end private def fix_cookie_paths? @configuration.fix_cookie_paths or return false cookies_need_path_fix = (secured_old_cookies_timestamp < @configuration.correct_cookie_paths_timestamp) cookies_have_been_rewritten_before and cookies_need_path_fix end # Delete cookies by giving them an expiry in the past, # cf. https://tools.ietf.org/html/rfc6265#section-4.1.2. # # Most important, as specified in # https://tools.ietf.org/html/rfc6265#section-4.1.2.4 and in section 5.1.4, # cookies set without a path will be set for the current "directory", that is: # # > ... the characters of the uri-path from the first character up # > to, but not including, the right-most %x2F ("/"). # # However, Firefox includes the right-most slash when guessing the cookie path, # so we must resort to letting browsers estimate the deletion cookie path again. def delete_cookie_for_current_directory(cookie_name) current_directory_is_not_root = @request.path[%r(^/[^/]+/[^\?]+), 0] if current_directory_is_not_root one_week = (7 * 24 * 60 * 60) set_cookie!(cookie_name, "", :path => nil, :expire_after => -one_week) end end def secured_old_cookies_timestamp Time.rfc2822(@request.cookies[SafeCookies::SECURED_COOKIE_NAME]) rescue ArgumentError # If we cannot parse the secured_old_cookies time, # assume it was before we noticed the bug to ensure # broken cookie paths will be fixed. Time.parse "2013-08-25 0:00" end end end