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_atfor 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 |