lib/doorkeeper/models/application_mixin.rb
# frozen_string_literal: true
module Doorkeeper
module ApplicationMixin
extend ActiveSupport::Concern
include OAuth::Helpers
include Models::Orderable
include Models::SecretStorable
include Models::Scopes
# :nodoc
module ClassMethods
# Returns an instance of the Doorkeeper::Application with
# specific UID and secret.
#
# Public/Non-confidential applications will only find by uid if secret is
# blank.
#
# @param uid [#to_s] UID (any object that responds to `#to_s`)
# @param secret [#to_s] secret (any object that responds to `#to_s`)
#
# @return [Doorkeeper::Application, nil]
# Application instance or nil if there is no record with such credentials
#
def by_uid_and_secret(uid, secret)
app = by_uid(uid)
return unless app
return app if secret.blank? && !app.confidential?
return unless app.secret_matches?(secret)
app
end
# Returns an instance of the Doorkeeper::Application with specific UID.
#
# @param uid [#to_s] UID (any object that responds to `#to_s`)
#
# @return [Doorkeeper::Application, nil] Application instance or nil
# if there is no record with such UID
#
def by_uid(uid)
find_by(uid: uid.to_s)
end
##
# Determines the secret storing transformer
# Unless configured otherwise, uses the plain secret strategy
def secret_strategy
::Doorkeeper.config.application_secret_strategy
end
##
# Determine the fallback storing strategy
# Unless configured, there will be no fallback
def fallback_secret_strategy
::Doorkeeper.config.application_secret_fallback_strategy
end
end
# Set an application's valid redirect URIs.
#
# @param uris [String, Array<String>] Newline-separated string or array the URI(s)
#
# @return [String] The redirect URI(s) separated by newlines.
#
def redirect_uri=(uris)
super(uris.is_a?(Array) ? uris.join("\n") : uris)
end
# Check whether the given plain text secret matches our stored secret
#
# @param input [#to_s] Plain secret provided by user
# (any object that responds to `#to_s`)
#
# @return [Boolean] Whether the given secret matches the stored secret
# of this application.
#
def secret_matches?(input)
# return false if either is nil, since secure_compare depends on strings
# but Application secrets MAY be nil depending on confidentiality.
return false if input.nil? || secret.nil?
# When matching the secret by comparer function, all is well.
return true if secret_strategy.secret_matches?(input, secret)
# When fallback lookup is enabled, ensure applications
# with plain secrets can still be found
if fallback_secret_strategy
fallback_secret_strategy.secret_matches?(input, secret)
else
false
end
end
end
end