Class: Spree::ApiKey

Inherits:
Object
  • Object
show all
Defined in:
app/models/spree/api_key.rb

Constant Summary collapse

KEY_TYPES =
%w[publishable secret].freeze
PREFIXES =
{ 'publishable' => 'pk_', 'secret' => 'sk_' }.freeze
TOKEN_LENGTH =
24
SCOPES =

Admin API authorization scopes. Granted to secret keys at creation; checked by ScopedAuthorization on every admin request. See docs/plans/5.5-admin-api-key-scopes.md for the full design.

%w[
  read_orders write_orders
  read_products write_products
  read_customers write_customers
  read_payments write_payments
  read_fulfillments write_fulfillments
  read_refunds write_refunds
  read_gift_cards write_gift_cards
  read_store_credits write_store_credits
  read_stock write_stock
  read_categories write_categories
  read_custom_field_definitions write_custom_field_definitions
  read_exports write_exports
  read_settings write_settings
  read_webhooks write_webhooks
  read_dashboard
  read_all write_all
].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.compute_token_digest(plaintext) ⇒ String

Computes the HMAC-SHA256 hex digest for a given plaintext token.

Parameters:

  • plaintext (String)

    the raw token value

Returns:

  • (String)

    the hex-encoded HMAC-SHA256 digest



84
85
86
# File 'app/models/spree/api_key.rb', line 84

def self.compute_token_digest(plaintext)
  OpenSSL::HMAC.hexdigest('SHA256', hmac_secret, plaintext)
end

.find_by_secret_token(plaintext) ⇒ Spree::ApiKey?

Finds an active secret API key by computing the HMAC-SHA256 digest of the provided plaintext token and looking up by token_digest.

Parameters:

  • plaintext (String)

    the raw secret key (e.g. “sk_abc123…”)

Returns:

  • (Spree::ApiKey, nil)

    the matching active secret key, or nil



73
74
75
76
77
78
# File 'app/models/spree/api_key.rb', line 73

def self.find_by_secret_token(plaintext)
  return nil if plaintext.blank?

  digest = compute_token_digest(plaintext)
  active.secret.find_by(token_digest: digest)
end

.hmac_secretString

Returns the HMAC secret used for token hashing.

Returns:

  • (String)

    the application’s secret key base



91
92
93
# File 'app/models/spree/api_key.rb', line 91

def self.hmac_secret
  Rails.application.secret_key_base
end

Instance Method Details

#active?Boolean

Returns whether this key has not been revoked.

Returns:

  • (Boolean)

    whether this key has not been revoked



106
107
108
# File 'app/models/spree/api_key.rb', line 106

def active?
  revoked_at.nil?
end

#has_scope?(scope) ⇒ Boolean

Whether this key carries the given scope. ‘write_*` implies the matching `read_*`; `read_all` / `write_all` aliases expand to every read / read+write scope respectively.

Parameters:

  • scope (String)

Returns:

  • (Boolean)


124
125
126
127
128
129
130
131
132
# File 'app/models/spree/api_key.rb', line 124

def has_scope?(scope)
  scope = scope.to_s
  return true if scopes.include?(scope)
  return true if scope.start_with?('read_') && scopes.include?("write_#{scope.delete_prefix('read_')}")
  return true if scopes.include?('write_all')
  return true if scope.start_with?('read_') && scopes.include?('read_all')

  false
end

#plaintext_tokenString?

Returns the raw token value. For publishable keys this is the persisted token column. For secret keys it is only available in memory immediately after creation (not persisted).

Returns:

  • (String, nil)


44
45
46
# File 'app/models/spree/api_key.rb', line 44

def plaintext_token
  publishable? ? token : @plaintext_token
end

#publishable?Boolean

Returns whether this is a publishable (Store API) key.

Returns:

  • (Boolean)

    whether this is a publishable (Store API) key



96
97
98
# File 'app/models/spree/api_key.rb', line 96

def publishable?
  key_type == 'publishable'
end

#revoke!(user = nil) ⇒ Boolean

Revokes this API key by setting revoked_at to the current time.

Parameters:

  • user (Object, nil) (defaults to: nil)

    the user who performed the revocation

Returns:

  • (Boolean)

    true if the update succeeded



114
115
116
# File 'app/models/spree/api_key.rb', line 114

def revoke!(user = nil)
  update!(revoked_at: Time.current, revoked_by: user)
end

#scopes=(value) ⇒ Object



35
36
37
# File 'app/models/spree/api_key.rb', line 35

def scopes=(value)
  super(Array(value).map(&:to_s).reject(&:blank?))
end

#secret?Boolean

Returns whether this is a secret (Admin API) key.

Returns:

  • (Boolean)

    whether this is a secret (Admin API) key



101
102
103
# File 'app/models/spree/api_key.rb', line 101

def secret?
  key_type == 'secret'
end