class RailsCompatibleCookiesUtils

Constants

InvalidSignature
VERSION

Public Class Methods

new(secret_key_base, serializer: JSON, encrypted_salt: 'encrypted cookie', encrypted_signed_salt: 'signed encrypted cookie', signed_salt: 'signed cookie', iterations: 1000, key_size: 64, cipher: 'aes-256-cbc', digest: 'SHA1') click to toggle source

Initializes it by providing the required secret_key_base as defined by your Rails app. The default Rails serializer in recent versions is JSON, but Marshal used to be the default. If your Rails application is old and still uses Marshal, set the serializer argument to Marshal: RailsCompatibleCookiesUtils.new(secret_key_base, serializer: Marshal).

# File lib/rails_compatible_cookies_utils.rb, line 15
def initialize(secret_key_base, serializer: JSON, encrypted_salt: 'encrypted cookie',
     encrypted_signed_salt: 'signed encrypted cookie', signed_salt: 'signed cookie',
     iterations: 1000, key_size: 64, cipher: 'aes-256-cbc', digest: 'SHA1')
  @secret_key_base, @serializer, @encrypted_salt, @encrypted_signed_salt,
      @signed_salt, @iterations, @key_size, @cipher, @digest =
    secret_key_base, serializer, encrypted_salt, encrypted_signed_salt,
      signed_salt, iterations, key_size, cipher, digest
end

Public Instance Methods

cookies(cookie) click to toggle source

Returns a hash with the first value for each key from the raw cookie string.

# File lib/rails_compatible_cookies_utils.rb, line 85
def cookies(cookie)
  Hash[CGI::Cookie::parse(cookie).map{|k, v| [k, v.first]}]
end
decrypt(value) click to toggle source

Decrypts an unescaped value and return nil if invalid.

# File lib/rails_compatible_cookies_utils.rb, line 42
def decrypt(value)
  return nil unless encoded_encrypted = verify_and_decode(value, encrypted_signed_secret)
  cipher = new_cipher
  encrypted, iv = encoded_encrypted.split('--').map{|v| decode v }
  cipher.decrypt
  cipher.key = encrypted_secret
  cipher.iv = iv
  decrypted = cipher.update encrypted
  decrypted << cipher.final
  @serializer.load decrypted
end
decrypt!(value) click to toggle source

Decrypt an unescaped value and raise RailsCompatibleCookiesUtils::InvalidSignature if invalid.

# File lib/rails_compatible_cookies_utils.rb, line 37
def decrypt!(value)
  decrypt value or raise InvalidSignature
end
encrypt(value) click to toggle source

Returns signed encrypted value.

# File lib/rails_compatible_cookies_utils.rb, line 90
def encrypt(value)
  sign_and_encode _encrypt(value), encrypted_signed_secret
end
encrypted_secret() click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 63
def encrypted_secret
  @encrypted_secret ||= generate_key(@encrypted_salt)[0, OpenSSL::Cipher.new(@cipher).key_len]
end
encrypted_signed_secret() click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 71
def encrypted_signed_secret
  @encrypted_signed_secret ||= generate_key @encrypted_signed_salt
end
generate_key(salt) click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 67
def generate_key(salt)
  OpenSSL::PKCS5.pbkdf2_hmac_sha1 @secret_key_base, salt, @iterations, @key_size
end
serialize_and_sign(value) click to toggle source

Serializes and sign value (session.signed = value)

# File lib/rails_compatible_cookies_utils.rb, line 125
def serialize_and_sign(value)
  sign_and_encode @serializer.dump(value), signed_secret
end
sign_and_encode(value, secret) click to toggle source

Signs and encode value only, without encrypting (session.signed = value).

# File lib/rails_compatible_cookies_utils.rb, line 95
def sign_and_encode(value, secret)
  data = encode value
  "#{data}--#{generate_digest data, secret}"
end
signed_secret() click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 75
def signed_secret
  @signed_secret ||= generate_key @signed_salt
end
verify_and_decode(value, secret) click to toggle source

Decodes value, returning nil if it's invalid.

# File lib/rails_compatible_cookies_utils.rb, line 55
def verify_and_decode(value, secret)
  return nil if value.nil? || !value.valid_encoding? || value.strip.empty?
  data, digest = value.split '--'
  return nil if [data, digest].any?{|v| v.nil? || v.strip.empty?}
  return nil unless generate_digest(data, secret) == digest
  decode data
end
verify_and_deserialize(value) click to toggle source

Decodes and deserializes a signed value, returning nil if invalid.

# File lib/rails_compatible_cookies_utils.rb, line 119
def verify_and_deserialize(value)
  return nil unless decoded = verify_and_decode(value, signed_secret)
  @serializer.load decoded
end
verify_and_deserialize!(value) click to toggle source

Decodes and deserializes a signed value. Raises RailsCompatibleCookiesUtils::InvalidSignature if invalid.

# File lib/rails_compatible_cookies_utils.rb, line 114
def verify_and_deserialize!(value)
  verify_and_deserialize value or raise InvalidSignature
end

Private Instance Methods

_encrypt(value) click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 147
def _encrypt(value)
  cipher = new_cipher
  cipher.encrypt
  cipher.key = encrypted_secret
  iv = cipher.random_iv

  encrypted = cipher.update @serializer.dump value
  encrypted << cipher.final
  "#{encode encrypted}--#{encode iv}"
end
decode(data) click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 139
def decode(data)
  ::Base64.strict_decode64 data
end
encode(data) click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 135
def encode(data)
  ::Base64.strict_encode64 data
end
generate_digest(data, secret) click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 131
def generate_digest(data, secret)
  OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, secret, data)
end
new_cipher() click to toggle source
# File lib/rails_compatible_cookies_utils.rb, line 143
def new_cipher
  OpenSSL::Cipher.new @cipher
end