Class: Administrator

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/administrator.rb

Instance Method Summary collapse

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. ||= 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

Returns:

  • (Boolean)


130
131
132
# File 'app/models/administrator.rb', line 130

def locked?
  return Time.current < self.
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