module ActiveModel::OneTimePassword::InstanceMethodsOnActivation

Public Instance Methods

authenticate_otp(code, options = {}) click to toggle source
# File lib/active_model/one_time_password.rb, line 74
def authenticate_otp(code, options = {})
  return true if backup_codes_enabled? && authenticate_backup_code(code)

  if otp_counter_based
    otp_counter == authenticate_hotp(code, options)
  else
    authenticate_totp(code, options).present?
  end
end
backup_codes_enabled?() click to toggle source
# File lib/active_model/one_time_password.rb, line 147
def backup_codes_enabled?
  self.class.attribute_method?(self.class.otp_backup_codes_column_name)
end
otp_code(options = {}) click to toggle source
# File lib/active_model/one_time_password.rb, line 84
def otp_code(options = {})
  if otp_counter_based
    hotp_code(options)
  else
    totp_code(options)
  end
end
otp_column() click to toggle source
# File lib/active_model/one_time_password.rb, line 107
def otp_column
  self.public_send(self.class.otp_column_name)
end
otp_column=(attr) click to toggle source
# File lib/active_model/one_time_password.rb, line 111
def otp_column=(attr)
  self.public_send("#{self.class.otp_column_name}=", attr)
end
otp_counter() click to toggle source
Calls superclass method
# File lib/active_model/one_time_password.rb, line 115
def otp_counter
  if self.class.otp_counter_column_name != "otp_counter"
    self.public_send(self.class.otp_counter_column_name)
  else
    super
  end
end
otp_counter=(attr) click to toggle source
Calls superclass method
# File lib/active_model/one_time_password.rb, line 123
def otp_counter=(attr)
  if self.class.otp_counter_column_name != "otp_counter"
    self.public_send("#{self.class.otp_counter_column_name}=", attr)
  else
    super
  end
end
otp_regenerate_backup_codes() click to toggle source
# File lib/active_model/one_time_password.rb, line 138
def otp_regenerate_backup_codes
  otp = ROTP::OTP.new(otp_column)
  backup_codes = Array.new(self.class.otp_backup_codes_count) do
    otp.generate_otp((SecureRandom.random_number(9e5) + 1e5).to_i)
  end

  public_send("#{self.class.otp_backup_codes_column_name}=", backup_codes)
end
otp_regenerate_counter() click to toggle source
# File lib/active_model/one_time_password.rb, line 70
def otp_regenerate_counter
  self.otp_counter = 1
end
otp_regenerate_secret() click to toggle source
# File lib/active_model/one_time_password.rb, line 66
def otp_regenerate_secret
  self.otp_column = self.class.otp_random_secret
end
provisioning_uri(account = nil, options = {}) click to toggle source
# File lib/active_model/one_time_password.rb, line 92
def provisioning_uri(account = nil, options = {})
  account ||= self.email if self.respond_to?(:email)
  account ||= ""

  if otp_counter_based
    ROTP::HOTP
      .new(otp_column, options)
      .provisioning_uri(account, self.otp_counter)
  else
    ROTP::TOTP
      .new(otp_column, options)
      .provisioning_uri(account)
  end
end
serializable_hash(options = nil) click to toggle source
Calls superclass method
# File lib/active_model/one_time_password.rb, line 131
def serializable_hash(options = nil)
  options ||= {}
  options[:except] = Array(options[:except])
  options[:except] << self.class.otp_column_name
  super(options)
end

Private Instance Methods

authenticate_backup_code(code) click to toggle source
# File lib/active_model/one_time_password.rb, line 197
def authenticate_backup_code(code)
  backup_codes_column_name = self.class.otp_backup_codes_column_name
  backup_codes = public_send(backup_codes_column_name)
  return false unless backup_codes.present? && backup_codes.include?(code)

  if self.class.otp_one_time_backup_codes
    backup_codes.delete(code)
    public_send("#{backup_codes_column_name}=", backup_codes)
    save if respond_to?(:changed?) && !new_record?
  end

  true
end
authenticate_hotp(code, options = {}) click to toggle source
# File lib/active_model/one_time_password.rb, line 153
def authenticate_hotp(code, options = {})
  hotp = ROTP::HOTP.new(otp_column, digits: otp_digits)
  result = hotp.verify(code, otp_counter)
  if result && options[:auto_increment]
    self.otp_counter += 1
    save if respond_to?(:changed?) && !new_record?
  end
  result
end
authenticate_totp(code, options = {}) click to toggle source
# File lib/active_model/one_time_password.rb, line 163
def authenticate_totp(code, options = {})
  totp = ROTP::TOTP.new(
    otp_column,
    digits: otp_digits,
    interval: otp_interval
  )
  if (drift = options[:drift])
    totp.verify(code, drift_behind: drift)
  else
    totp.verify(code)
  end
end
hotp_code(options = {}) click to toggle source
# File lib/active_model/one_time_password.rb, line 176
def hotp_code(options = {})
  if options[:auto_increment]
    self.otp_counter += 1
    save if respond_to?(:changed?) && !new_record?
  end
  ROTP::HOTP.new(otp_column, digits: otp_digits).at(otp_counter)
end
totp_code(options = {}) click to toggle source
# File lib/active_model/one_time_password.rb, line 184
def totp_code(options = {})
  time = if options.is_a?(Hash)
           options.fetch(:time, Time.now)
         else
           options
         end
  ROTP::TOTP.new(
    otp_column,
    digits: otp_digits,
    interval: otp_interval
  ).at(time)
end