CI / Test (pull_request) Successful in 42s
- Enqueue the expiry job and the "app connected" notification on after_commit instead of after_create, so they only fire once the (now transactional) code exchange commits - Enforce the PKCE code_challenge format (43-128 unreserved chars, S256) with model validations, not only at the controller - Drop the now-unused RsAuthorizationCode#expired? - Cover the client_id-vs-stored-client_id check Part of #254
34 lines
796 B
Ruby
34 lines
796 B
Ruby
class RsAuthorizationCode < ApplicationRecord
|
|
belongs_to :user
|
|
|
|
CODE_TTL = 60.seconds
|
|
|
|
serialize :permissions, coder: JSON
|
|
|
|
attr_accessor :code
|
|
|
|
before_validation :generate_code
|
|
|
|
validates :code_challenge, presence: true,
|
|
format: { with: /\A[A-Za-z0-9\-._~]{43,128}\z/ }
|
|
validates :code_challenge_method, inclusion: { in: %w[S256] }
|
|
|
|
scope :active, -> { where(expires_at: Time.current..) }
|
|
|
|
def self.find_by_code(raw_code)
|
|
return nil if raw_code.blank?
|
|
|
|
active.find_by(code_digest: Digest::SHA256.hexdigest(raw_code))
|
|
end
|
|
|
|
private
|
|
|
|
def generate_code
|
|
return if code_digest.present?
|
|
|
|
self.code = SecureRandom.urlsafe_base64(32)
|
|
self.code_digest = Digest::SHA256.hexdigest(code)
|
|
self.expires_at ||= CODE_TTL.from_now
|
|
end
|
|
end
|