Class: Administrator
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Administrator
- Defined in:
- app/models/administrator.rb
Instance Method Summary collapse
-
#accrue_strike! ⇒ Object
Add one strike to the account.
-
#authenticate!(passcode) ⇒ Object
Attempt to authenticate the account with the given plaintext
passcode
. -
#consume_passcode! ⇒ Object
Immediately expire the current passcode and reset lockout strikes.
-
#initialize_authentication! ⇒ Object
Initialize
passcode
,passcode_expires_at
,auth_token
, andaccount_unlocks_at
for a new admin. -
#lock_account! ⇒ Object
Lock this account immediately and reset lockout strikes.
-
#locked? ⇒ Boolean
True if the account is currently inside a lockout window.
-
#normalize_email! ⇒ Object
Downcase and strip whitespace from the current email.
-
#send_passcode_email! ⇒ Object
Send a passcode challenge email to the admin.
-
#set_passcode! ⇒ Object
Generate a new passcode challenge.
-
#unlock_account! ⇒ Object
Unlock the user’s account.
Instance Method Details
#accrue_strike! ⇒ Object
Add one strike to the account. An admin is given a strike for requesting a code or flunking a challenge. Will lock the account if they’ve hit the threshold.
102 103 104 105 106 107 108 109 110 |
# File 'app/models/administrator.rb', line 102 def accrue_strike! self.update!( lockout_strikes: self.lockout_strikes + 1, total_strikes: self.total_strikes + 1, ) if self.lockout_strikes >= Tolaria.config.lockout_threshold self.lock_account! end end |
#authenticate!(passcode) ⇒ Object
Attempt to authenticate the account with the given plaintext passcode
.
Returns true if the passcode was valid, false otherwise.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'app/models/administrator.rb', line 71 def authenticate!(passcode) # Always run bcrypt first so that we incur the time penalty bcrypt_valid = BCrypt::Password.new(self.passcode) == passcode # Reject if currently locked return false if self.locked? # Clear strikes and consume the passcode if the passcode was valid. # Reject and incur a strike if the challenge was failed. if bcrypt_valid && Time.current < self.passcode_expires_at self.consume_passcode! return true else self.accrue_strike! return false end end |
#consume_passcode! ⇒ Object
Immediately expire the current passcode and reset lockout strikes.
92 93 94 95 96 97 |
# File 'app/models/administrator.rb', line 92 def consume_passcode! self.update!( passcode_expires_at: Time.current, lockout_strikes: 0, ) end |
#initialize_authentication! ⇒ Object
Initialize passcode
, passcode_expires_at
,
auth_token
, and account_unlocks_at
for a new admin.
To prevent passcode system fields from being null,
we fill them with an immediately expired passcode.
44 45 46 47 48 49 |
# File 'app/models/administrator.rb', line 44 def initialize_authentication! self.passcode ||= BCrypt::Password.create(Tolaria::RandomTokens.passcode, cost:Tolaria.config.bcrypt_cost) self.passcode_expires_at ||= Time.current self.auth_token ||= Tolaria::RandomTokens.auth_token self.account_unlocks_at ||= Time.current end |
#lock_account! ⇒ Object
Lock this account immediately and reset lockout strikes.
113 114 115 116 117 118 |
# File 'app/models/administrator.rb', line 113 def lock_account! self.update!( account_unlocks_at: Time.current + Tolaria.config.lockout_duration, lockout_strikes: 0, ) end |
#locked? ⇒ Boolean
True if the account is currently inside a lockout window
130 131 132 |
# File 'app/models/administrator.rb', line 130 def locked? return Time.current < self.account_unlocks_at end |
#normalize_email! ⇒ Object
Downcase and strip whitespace from the current email
29 30 31 |
# File 'app/models/administrator.rb', line 29 def normalize_email! self.email = self.email.to_s.downcase.squish end |
#send_passcode_email! ⇒ Object
Send a passcode challenge email to the admin
52 53 54 55 |
# File 'app/models/administrator.rb', line 52 def send_passcode_email! plaintext_passcode = self.set_passcode! PasscodeMailer.passcode(self, plaintext_passcode).deliver_now end |
#set_passcode! ⇒ Object
Generate a new passcode challenge. Create a passcode, save it, and set an expiration window. Returns the plaintext passcode to send to the user.
60 61 62 63 64 65 66 67 |
# File 'app/models/administrator.rb', line 60 def set_passcode! plaintext_passcode = Tolaria::RandomTokens.passcode self.update!( passcode: BCrypt::Password.create(plaintext_passcode, cost:Tolaria.config.bcrypt_cost), passcode_expires_at: Time.current + Tolaria.config.passcode_lifespan, ) return plaintext_passcode end |
#unlock_account! ⇒ Object
Unlock the user’s account. Currently only usable by someone with Rails console access.
122 123 124 125 126 127 |
# File 'app/models/administrator.rb', line 122 def unlock_account! self.update!( account_unlocks_at: Time.current, lockout_strikes: 0, ) end |