lib/doorkeeper/models/concerns/secret_storable.rb
# frozen_string_literal: true module Doorkeeper module Models ## # Storable finder to provide lookups for input plaintext values which are # mapped to their stored versions (e.g., hashing, encryption) before lookup. module SecretStorable extend ActiveSupport::Concern delegate :secret_strategy, :fallback_secret_strategy, to: :class # :nodoc module ClassMethods # Compare the given plaintext with the secret # # @param input [String] # The plain input to compare. # # @param secret [String] # The secret value to compare with. # # @return [Boolean] # Whether input matches secret as per the secret strategy # delegate :secret_matches?, to: :secret_strategy # Returns an instance of the Doorkeeper::AccessToken with # specific token value. # # @param attr [Symbol] # The token attribute we're looking with. # # @param token [#to_s] # token value (any object that responds to `#to_s`) # # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil # if there is no record with such token # def find_by_plaintext_token(attr, token) token = token.to_s find_by(attr => secret_strategy.transform_secret(token)) || find_by_fallback_token(attr, token) end # Allow looking up previously plain tokens as a fallback # IFF a fallback strategy has been defined # # @param attr [Symbol] # The token attribute we're looking with. # # @param plain_secret [#to_s] # plain secret value (any object that responds to `#to_s`) # # @return [Doorkeeper::AccessToken, nil] AccessToken object or nil # if there is no record with such token # def find_by_fallback_token(attr, plain_secret) return nil unless fallback_secret_strategy # Use the previous strategy to look up stored_token = fallback_secret_strategy.transform_secret(plain_secret) find_by(attr => stored_token).tap do |resource| return nil unless resource upgrade_fallback_value resource, attr, plain_secret end end # Allow implementations in ORMs to replace a plain # value falling back to to avoid it remaining as plain text. # # @param instance # An instance of this model with a plain value token. # # @param attr # The secret attribute name to upgrade. # # @param plain_secret # The plain secret to upgrade. # def upgrade_fallback_value(instance, attr, plain_secret) upgraded = secret_strategy.store_secret(instance, attr, plain_secret) instance.update(attr => upgraded) end ## # Determines the secret storing transformer # Unless configured otherwise, uses the plain secret strategy def secret_strategy ::Doorkeeper::SecretStoring::Plain end ## # Determine the fallback storing strategy # Unless configured, there will be no fallback def fallback_secret_strategy nil end end end end end