Class: OtpSecret

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user) ⇒ OtpSecret

Returns a new instance of OtpSecret.



6
7
8
9
# File 'app/models/otp_secret.rb', line 6

def initialize(user)
  @user = user
  @secret = user.otp_secret
end

Instance Attribute Details

#secretObject (readonly)

Returns the value of attribute secret.



4
5
6
# File 'app/models/otp_secret.rb', line 4

def secret
  @secret
end

#userObject (readonly)

Returns the value of attribute user.



4
5
6
# File 'app/models/otp_secret.rb', line 4

def user
  @user
end

Instance Method Details

#account_nameObject



11
12
13
# File 'app/models/otp_secret.rb', line 11

def 
  user.email
end

#disable!Object



15
16
17
18
19
20
# File 'app/models/otp_secret.rb', line 15

def disable!
  user.update(otp_enabled: false,
              otp_secret: nil,
              last_otp_at: nil,
              recovery_codes: [])
end

#enable!(recovery_codes) ⇒ Object



22
23
24
25
26
27
# File 'app/models/otp_secret.rb', line 22

def enable!(recovery_codes)
  user.update(otp_enabled: true,
              otp_secret: secret,
              last_otp_at: Time.zone.now,
              recovery_codes:)
end

#generateObject



29
30
31
# File 'app/models/otp_secret.rb', line 29

def generate
  @secret = ROTP::Base32.random
end

#generate_recovery_codesObject



33
34
35
# File 'app/models/otp_secret.rb', line 33

def generate_recovery_codes
  10.times.map { SecureRandom.alphanumeric(16) }
end

#provisioning_uriObject



37
38
39
# File 'app/models/otp_secret.rb', line 37

def provisioning_uri
  totp.provisioning_uri()
end

#regenerate_recovery_codes!Object



41
42
43
44
45
# File 'app/models/otp_secret.rb', line 41

def regenerate_recovery_codes!
  generate_recovery_codes.tap do |recovery_codes|
    user.update(recovery_codes:)
  end
end

#signed_messageObject



47
48
49
50
51
# File 'app/models/otp_secret.rb', line 47

def signed_message
  message_verifier.generate(
    { user_id: user.id, secret: }, expires_in: 1.hour
  )
end

#validate_otp!(code) ⇒ Object



53
54
55
56
57
58
# File 'app/models/otp_secret.rb', line 53

def validate_otp!(code)
  return false unless valid_otp?(code)

  user.update(last_otp_at: Time.zone.now)
  true
end

#validate_otp_or_recovery_code!(code) ⇒ Object



60
61
62
63
64
65
66
# File 'app/models/otp_secret.rb', line 60

def validate_otp_or_recovery_code!(code)
  if code =~ /^[\d]{6}$/
    validate_otp!(code)
  else
    validate_recovery_code!(code)
  end
end

#validate_recovery_code!(code) ⇒ Object



68
69
70
# File 'app/models/otp_secret.rb', line 68

def validate_recovery_code!(code)
  user.use_recovery_code!(code)
end

#verify(params) ⇒ Object



72
73
74
75
# File 'app/models/otp_secret.rb', line 72

def verify(params)
  @secret = verify_secret(params[:signed_message])
  valid_otp?(params[:otp])
end