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