@@ -117,6 +117,9 @@ def permanent
117117 # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
118118 # cookie was tampered with by the user (or a 3rd party), nil will be returned.
119119 #
120+ # If +config.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
121+ # legacy cookies signed with the old key generator will be transparently upgraded.
122+ #
120123 # This jar requires that you set a suitable secret for the verification on your app's +config.secret_key_base+.
121124 #
122125 # Example:
@@ -126,23 +129,20 @@ def permanent
126129 #
127130 # cookies.signed[:discount] # => 45
128131 def signed
129- @signed ||= begin
130- if @options [ :upgrade_legacy_signed_cookie_jar ]
132+ @signed ||=
133+ if @options [ :upgrade_legacy_signed_cookies ]
131134 UpgradeLegacySignedCookieJar . new ( self , @key_generator , @options )
132135 else
133136 SignedCookieJar . new ( self , @key_generator , @options )
134137 end
135- end
136- end
137-
138- # Only needed for supporting the +UpgradeSignatureToEncryptionCookieStore+, users and plugin authors should not use this
139- def signed_using_old_secret #:nodoc:
140- @signed_using_old_secret ||= SignedCookieJar . new ( self , ActiveSupport ::DummyKeyGenerator . new ( @options [ :secret_token ] ) , @options )
141138 end
142139
143140 # Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
144141 # If the cookie was tampered with by the user (or a 3rd party), nil will be returned.
145142 #
143+ # If +config.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
144+ # legacy cookies signed with the old key generator will be transparently upgraded.
145+ #
146146 # This jar requires that you set a suitable secret for the verification on your app's +config.secret_key_base+.
147147 #
148148 # Example:
@@ -152,7 +152,38 @@ def signed_using_old_secret #:nodoc:
152152 #
153153 # cookies.encrypted[:discount] # => 45
154154 def encrypted
155- @encrypted ||= EncryptedCookieJar . new ( self , @key_generator , @options )
155+ @encrypted ||=
156+ if @options [ :upgrade_legacy_signed_cookies ]
157+ UpgradeLegacyEncryptedCookieJar . new ( self , @key_generator , @options )
158+ else
159+ EncryptedCookieJar . new ( self , @key_generator , @options )
160+ end
161+ end
162+
163+ # Returns the +signed+ or +encrypted jar, preferring +encrypted+ if +secret_key_base+ is set.
164+ # Used by ActionDispatch::Session::CookieStore to avoid the need to introduce new cookie stores.
165+ def signed_or_encrypted
166+ @signed_or_encrypted ||=
167+ if @options [ :secret_key_base ] . present?
168+ encrypted
169+ else
170+ signed
171+ end
172+ end
173+ end
174+
175+ module VerifyAndUpgradeLegacySignedMessage
176+ def initialize ( *args )
177+ super
178+ @legacy_verifier = ActiveSupport ::MessageVerifier . new ( @options [ :secret_token ] )
179+ end
180+
181+ def verify_and_upgrade_legacy_signed_message ( name , signed_message )
182+ @legacy_verifier . verify ( signed_message ) . tap do |value |
183+ self [ name ] = value
184+ end
185+ rescue ActiveSupport ::MessageVerifier ::InvalidSignature
186+ nil
156187 end
157188 end
158189
@@ -179,7 +210,7 @@ def self.options_for_env(env) #:nodoc:
179210 encrypted_signed_cookie_salt : env [ ENCRYPTED_SIGNED_COOKIE_SALT ] || '' ,
180211 secret_token : env [ SECRET_TOKEN ] ,
181212 secret_key_base : env [ SECRET_KEY_BASE ] ,
182- upgrade_legacy_signed_cookie_jar : env [ SECRET_TOKEN ] . present? && env [ SECRET_KEY_BASE ] . present?
213+ upgrade_legacy_signed_cookies : env [ SECRET_TOKEN ] . present? && env [ SECRET_KEY_BASE ] . present?
183214 }
184215 end
185216
@@ -354,10 +385,8 @@ def initialize(parent_jar, key_generator, options = {})
354385
355386 def []( name )
356387 if signed_message = @parent_jar [ name ]
357- @verifier . verify ( signed_message )
388+ verify ( signed_message )
358389 end
359- rescue ActiveSupport ::MessageVerifier ::InvalidSignature
360- nil
361390 end
362391
363392 def []=( key , options )
@@ -371,46 +400,37 @@ def []=(key, options)
371400 raise CookieOverflow if options [ :value ] . size > MAX_COOKIE_SIZE
372401 @parent_jar [ key ] = options
373402 end
403+
404+ private
405+
406+ def verify ( signed_message )
407+ @verifier . verify ( signed_message )
408+ rescue ActiveSupport ::MessageVerifier ::InvalidSignature
409+ nil
410+ end
374411 end
375412
376413 # UpgradeLegacySignedCookieJar is used instead of SignedCookieJar if
377414 # config.secret_token and config.secret_key_base are both set. It reads
378415 # legacy cookies signed with the old dummy key generator and re-saves
379416 # them using the new key generator to provide a smooth upgrade path.
380417 class UpgradeLegacySignedCookieJar < SignedCookieJar #:nodoc:
381- def initialize ( *args )
382- super
383- @legacy_verifier = ActiveSupport ::MessageVerifier . new ( @options [ :secret_token ] )
384- end
418+ include VerifyAndUpgradeLegacySignedMessage
385419
386420 def []( name )
387421 if signed_message = @parent_jar [ name ]
388- verify_signed_message ( signed_message ) || verify_and_upgrade_legacy_signed_message ( name , signed_message )
422+ verify ( signed_message ) || verify_and_upgrade_legacy_signed_message ( name , signed_message )
389423 end
390424 end
391-
392- def verify_signed_message ( signed_message )
393- @verifier . verify ( signed_message )
394- rescue ActiveSupport ::MessageVerifier ::InvalidSignature
395- nil
396- end
397-
398- def verify_and_upgrade_legacy_signed_message ( name , signed_message )
399- @legacy_verifier . verify ( signed_message ) . tap do |value |
400- self [ name ] = value
401- end
402- rescue ActiveSupport ::MessageVerifier ::InvalidSignature
403- nil
404- end
405425 end
406426
407427 class EncryptedCookieJar #:nodoc:
408428 include ChainedCookieJars
409429
410430 def initialize ( parent_jar , key_generator , options = { } )
411431 if ActiveSupport ::DummyKeyGenerator === key_generator
412- raise "Encrypted Cookies must be used in conjunction with config.secret_key_base. " +
413- "Set config.secret_key_base in config/initializers/secret_token.rb "
432+ raise "You didn't set config.secret_key_base, which is required for this cookie jar. " +
433+ "Read the upgrade documentation to learn more about this new config option. "
414434 end
415435
416436 @parent_jar = parent_jar
@@ -422,11 +442,8 @@ def initialize(parent_jar, key_generator, options = {})
422442
423443 def []( key )
424444 if encrypted_message = @parent_jar [ key ]
425- @encryptor . decrypt_and_verify ( encrypted_message )
445+ decrypt_and_verify ( encrypted_message )
426446 end
427- rescue ActiveSupport ::MessageVerifier ::InvalidSignature ,
428- ActiveSupport ::MessageEncryptor ::InvalidMessage
429- nil
430447 end
431448
432449 def []=( key , options )
@@ -440,6 +457,28 @@ def []=(key, options)
440457 raise CookieOverflow if options [ :value ] . size > MAX_COOKIE_SIZE
441458 @parent_jar [ key ] = options
442459 end
460+
461+ private
462+
463+ def decrypt_and_verify ( encrypted_message )
464+ @encryptor . decrypt_and_verify ( encrypted_message )
465+ rescue ActiveSupport ::MessageVerifier ::InvalidSignature , ActiveSupport ::MessageEncryptor ::InvalidMessage
466+ nil
467+ end
468+ end
469+
470+ # UpgradeLegacyEncryptedCookieJar is used by ActionDispatch::Session::CookieStore
471+ # instead of EncryptedCookieJar if config.secret_token and config.secret_key_base
472+ # are both set. It reads legacy cookies signed with the old dummy key generator and
473+ # encrypts and re-saves them using the new key generator to provide a smooth upgrade path.
474+ class UpgradeLegacyEncryptedCookieJar < EncryptedCookieJar #:nodoc:
475+ include VerifyAndUpgradeLegacySignedMessage
476+
477+ def []( name )
478+ if encrypted_or_signed_message = @parent_jar [ name ]
479+ decrypt_and_verify ( encrypted_or_signed_message ) || verify_and_upgrade_legacy_signed_message ( name , encrypted_or_signed_message )
480+ end
481+ end
443482 end
444483
445484 def initialize ( app )
0 commit comments