66 lines
1.5 KiB
Ruby
66 lines
1.5 KiB
Ruby
class AccessKey < ApplicationRecord
|
|
DEFAULT_ROTATION_FREQUENCY_DAYS = 30
|
|
KEY_LENGTH = 32
|
|
|
|
validates :raw_key, presence: true
|
|
validates :generated_at, presence: true
|
|
validates :auto_rotation_frequency_days,
|
|
numericality: { only_integer: true, greater_than: 0 }
|
|
|
|
def self.current
|
|
order(generated_at: :desc, id: :desc).first || create_current!
|
|
end
|
|
|
|
def self.create_current!
|
|
create!(
|
|
raw_key: generate_raw_key,
|
|
generated_at: Time.current,
|
|
auto_rotate: true,
|
|
auto_rotation_frequency_days: DEFAULT_ROTATION_FREQUENCY_DAYS
|
|
)
|
|
end
|
|
|
|
def self.rotate!
|
|
previous_key = current
|
|
|
|
transaction do
|
|
UserSession.delete_all
|
|
create!(
|
|
raw_key: generate_raw_key,
|
|
generated_at: Time.current,
|
|
auto_rotate: previous_key.auto_rotate,
|
|
auto_rotation_frequency_days: previous_key.auto_rotation_frequency_days
|
|
)
|
|
end
|
|
end
|
|
|
|
def self.rotate_if_needed!
|
|
key = current
|
|
return key unless key.auto_rotate? && key.expired?
|
|
|
|
rotate!
|
|
end
|
|
|
|
def self.generate_raw_key
|
|
SecureRandom.urlsafe_base64(KEY_LENGTH)
|
|
end
|
|
|
|
def matches?(submitted_key)
|
|
ActiveSupport::SecurityUtils.secure_compare(raw_key, submitted_key.to_s)
|
|
rescue ArgumentError
|
|
false
|
|
end
|
|
|
|
def expired?
|
|
generated_at <= auto_rotation_frequency_days.days.ago
|
|
end
|
|
|
|
def disable_auto_rotation!
|
|
update!(auto_rotate: false)
|
|
end
|
|
|
|
def enable_auto_rotation!
|
|
update!(auto_rotate: true)
|
|
end
|
|
end
|