class Rage::Cookies::EncryptedJar
def build_key(secret)
def build_key(secret) RbNaCl::Hash.blake2b("", key: [secret].pack("H*"), digest_size: 32, personal: INFO) end
def dump(value)
def dump(value) # add two bytes to hold meta information, e.g. in case we # need to change the encryption algorithm in the future Base64.urlsafe_encode64(PADDING + primary_box.encrypt(value.to_s)) end
def fallback_boxes
def fallback_boxes @fallback_boxes ||= begin fallbacks = Rage.config.fallback_secret_key_base.map do |key| RbNaCl::SimpleBox.from_secret_key(build_key(key)) end fallbacks << RbNaCl::SimpleBox.from_secret_key( RbNaCl::Hash.blake2b(Rage.config.secret_key_base, digest_size: 32, salt: INFO) ) end end
def load(value)
def load(value) box = primary_box begin box.decrypt(Base64.urlsafe_decode64(value).byteslice(2..)) rescue ArgumentError Rage.logger.debug("Failed to decode encrypted cookie") nil rescue RbNaCl::CryptoError Rage.logger.debug("Failed to decrypt encrypted cookie") i ||= 0 if (box = fallback_boxes[i]) Rage.logger.debug { "Trying to decrypt with fallback key ##{i + 1}" } i += 1 retry end end end
def primary_box
def primary_box @primary_box ||= begin if !defined?(RbNaCl) || !(Gem::Version.create(RbNaCl::VERSION) >= Gem::Version.create("3.3.0") && Gem::Version.create(RbNaCl::VERSION) < Gem::Version.create("8.0.0")) fail <<~ERR Rage depends on `rbnacl` [>= 3.3, < 8.0] to encrypt cookies. Ensure the following line is added to your Gemfile: gem "rbnacl" ERR end unless Rage.config.secret_key_base raise "Rage.config.secret_key_base should be set to use encrypted cookies" end RbNaCl::SimpleBox.from_secret_key(build_key(Rage.config.secret_key_base)) end end