Class: ApiKeys::Services::Digestor

Inherits:
Object
  • Object
show all
Defined in:
lib/api_keys/services/digestor.rb

Overview

Handles hashing (digesting) and verifying tokens based on configured strategy.

Class Method Summary collapse

Class Method Details

.digest(token:, strategy: ApiKeys.configuration.hash_strategy) ⇒ Hash

Creates a digest of the given token using the configured strategy.

Parameters:

  • token (String)

    The plaintext token.

  • strategy (Symbol) (defaults to: ApiKeys.configuration.hash_strategy)

    The hashing strategy (:bcrypt or :sha256).

Returns:

  • (Hash)

    A hash containing the digest and the algorithm used. e.g., { digest: “…”, algorithm: “bcrypt” }



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/api_keys/services/digestor.rb', line 16

def self.digest(token:, strategy: ApiKeys.configuration.hash_strategy)
  case strategy
  when :bcrypt
    # BCrypt handles salt generation internally
    digest = BCrypt::Password.create(token, cost: BCrypt::Engine.cost)
    { digest: digest.to_s, algorithm: "bcrypt" }
  when :sha256
    # Note: Simple SHA256 without salt/pepper. Consider enhancing if needed.
    # BCrypt is generally preferred for password/token hashing.
    digest = Digest::SHA256.hexdigest(token)
    { digest: digest, algorithm: "sha256" }
  else
    raise ArgumentError, "Unsupported hash strategy: #{strategy}. Use :bcrypt or :sha256."
  end
end

.match?(token:, stored_digest:, strategy: ApiKeys.configuration.hash_strategy, comparison_proc: ApiKeys.configuration.secure_compare_proc) ⇒ Boolean

Securely compares a plaintext token against a stored digest. Uses the configured secure comparison proc and hash strategy.

Parameters:

  • token (String)

    The plaintext token provided by the user/client.

  • stored_digest (String)

    The hashed digest stored in the database.

  • strategy (Symbol) (defaults to: ApiKeys.configuration.hash_strategy)

    The hashing strategy used to create the stored_digest.

  • comparison_proc (Proc) (defaults to: ApiKeys.configuration.secure_compare_proc)

    The secure comparison function.

Returns:

  • (Boolean)

    True if the token matches the digest, false otherwise.



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/api_keys/services/digestor.rb', line 40

def self.match?(token:, stored_digest:, strategy: ApiKeys.configuration.hash_strategy, comparison_proc: ApiKeys.configuration.secure_compare_proc)
  return false if token.blank? || stored_digest.blank?

  case strategy
  when :bcrypt
    begin
      bcrypt_object = BCrypt::Password.new(stored_digest)
      # BCrypt's `==` operator is designed for secure comparison
      bcrypt_object == token
    rescue BCrypt::Errors::InvalidHash
      # If the stored digest isn't a valid BCrypt hash, comparison fails
      false
    end
  when :sha256
    # Directly compare the SHA256 hash of the input token with the stored digest
    comparison_proc.call(stored_digest, Digest::SHA256.hexdigest(token))
  else
    # Strategy mismatch or unsupported strategy should fail comparison safely
    Rails.logger.error "[ApiKeys] Digestor comparison failed: Unsupported hash strategy '#{strategy}' for digest check." if defined?(Rails.logger)
    false
  end
rescue ArgumentError => e
  # Catch potential errors from Digest or comparison proc
  Rails.logger.error "[ApiKeys] Digestor comparison error: #{e.message}" if defined?(Rails.logger)
  false
end