Gli agenti autenticati con token Bearer possono leggere today/pipeline e annotare attività, con host MCP allineati a quelli di produzione. Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.0 KiB
Ruby
55 lines
1.0 KiB
Ruby
class ApiToken < ApplicationRecord
|
|
PREFIX = "crm_"
|
|
|
|
belongs_to :user
|
|
|
|
attr_accessor :plaintext
|
|
|
|
validates :name, presence: true
|
|
validates :token_digest, presence: true, uniqueness: true
|
|
validates :token_prefix, presence: true
|
|
|
|
scope :active, -> { where(revoked_at: nil) }
|
|
|
|
def self.digest(token)
|
|
Digest::SHA256.hexdigest(token.to_s)
|
|
end
|
|
|
|
def self.authenticate(plaintext)
|
|
return if plaintext.blank?
|
|
|
|
token = active.find_by(token_digest: digest(plaintext))
|
|
return unless token&.user&.active?
|
|
|
|
token
|
|
end
|
|
|
|
def self.issue!(user:, name:)
|
|
raw = "#{PREFIX}#{SecureRandom.urlsafe_base64(32)}"
|
|
record = create!(
|
|
user: user,
|
|
name: name.to_s.strip.presence || "Agente",
|
|
token_digest: digest(raw),
|
|
token_prefix: raw[0, 8]
|
|
)
|
|
record.plaintext = raw
|
|
record
|
|
end
|
|
|
|
def revoked?
|
|
revoked_at.present?
|
|
end
|
|
|
|
def revoke!
|
|
update!(revoked_at: Time.current)
|
|
end
|
|
|
|
def touch_last_used!
|
|
update_column(:last_used_at, Time.current)
|
|
end
|
|
|
|
def masked
|
|
"#{token_prefix}…"
|
|
end
|
|
end
|