Class Account
In: app/models/account.rb
Parent: ActiveRecord::Base

Methods

Classes and Modules

Class Account::ActivationCodeNotFound
Class Account::AlreadyActivated

Attributes

password  [RW] 

Public Class methods

Authenticates a user by their login name and password. Returns the user or nil.

[Source]

    # File app/models/account.rb, line 68
68:   def self.authenticate(login, password)
69:     if a = find(:first, :conditions => ['login = ? and enabled = ? and activated_at IS NOT NULL', login, true]) # need to get the salt
70:       if a.authenticated?(password)
71:         a.last_authenticated_at, a.last_authenticated_with_yubikey = Time.now, a.authenticated_with_yubikey?
72:         a.save(false)
73:         a
74:       end
75:     end
76:   end

Encrypts some data with the salt.

[Source]

    # File app/models/account.rb, line 79
79:   def self.encrypt(password, salt)
80:     Digest::SHA1.hexdigest("--#{salt}--#{password}--")
81:   end

Finds the user with the corresponding activation code, activates their account and returns the user.

Raises:

Account::ActivationCodeNotFound
if there is no user with the corresponding activation code
Account::AlreadyActivated
if the user with the corresponding activation code has already activated their account

[Source]

    # File app/models/account.rb, line 38
38:   def self.find_and_activate!(activation_code)
39:     raise ArgumentError if activation_code.nil?
40:     user = find_by_activation_code(activation_code)
41:     raise ActivationCodeNotFound unless user
42:     raise AlreadyActivated.new(user) if user.active?
43:     user.send(:activate!)
44:     user
45:   end

Public Instance methods

The existence of an activation code means they have not activated yet

[Source]

    # File app/models/account.rb, line 52
52:   def active?
53:     activation_code.nil?
54:   end

[Source]

     # File app/models/account.rb, line 110
110:   def associate_with_yubikey(otp)
111:     if Account.verify_yubico_otp(otp)
112:       self.yubico_identity = Account.extract_yubico_identity_from_otp(otp)
113:       save(false)
114:     else
115:       false
116:     end
117:   end

[Source]

    # File app/models/account.rb, line 88
88:   def authenticated?(password)
89:     if password.length < 50
90:       encrypt(password) == crypted_password
91:     else
92:       password, yubico_otp = Account.split_password_and_yubico_otp(password)
93:       encrypt(password) == crypted_password && @authenticated_with_yubikey = yubikey_authenticated?(yubico_otp)
94:     end
95:   end

[Source]

     # File app/models/account.rb, line 106
106:   def authenticated_with_yubikey?
107:     @authenticated_with_yubikey || false
108:   end

[Source]

     # File app/models/account.rb, line 165
165:   def disable!
166:     update_attribute(:enabled, false)
167:   end

Encrypts the password with the user salt

[Source]

    # File app/models/account.rb, line 84
84:   def encrypt(password)
85:     self.class.encrypt(password, salt)
86:   end

[Source]

     # File app/models/account.rb, line 138
138:   def forget_me
139:     self.remember_token_expires_at = nil
140:     self.remember_token = nil
141:     save(false)
142:   end

[Source]

     # File app/models/account.rb, line 144
144:   def forgot_password!
145:     @forgotten_password = true
146:     self.make_password_reset_code
147:     self.save
148:   end

Does the user have the possibility to authenticate with a one time password?

[Source]

    # File app/models/account.rb, line 62
62:   def has_otp_device?
63:     !yubico_identity.nil?
64:   end

True if the user has just been activated

[Source]

    # File app/models/account.rb, line 57
57:   def pending?
58:     @activated
59:   end

[Source]

     # File app/models/account.rb, line 157
157:   def recently_forgot_password?
158:     @forgotten_password
159:   end

[Source]

     # File app/models/account.rb, line 161
161:   def recently_reset_password?
162:     @reset_password
163:   end

These create and unset the fields required for remembering users between browser closes

[Source]

     # File app/models/account.rb, line 124
124:   def remember_me
125:     remember_me_for 2.weeks
126:   end

[Source]

     # File app/models/account.rb, line 128
128:   def remember_me_for(time)
129:     remember_me_until time.from_now.utc
130:   end

[Source]

     # File app/models/account.rb, line 132
132:   def remember_me_until(time)
133:     self.remember_token_expires_at = time
134:     self.remember_token = encrypt("#{email}--#{remember_token_expires_at}")
135:     save(false)
136:   end

[Source]

     # File app/models/account.rb, line 119
119:   def remember_token?
120:     remember_token_expires_at && Time.now.utc < remember_token_expires_at 
121:   end

First update the password_reset_code before setting the reset_password flag to avoid duplicate email notifications.

[Source]

     # File app/models/account.rb, line 152
152:   def reset_password
153:     update_attribute(:password_reset_code, nil)
154:     @reset_password = true
155:   end

[Source]

    # File app/models/account.rb, line 47
47:   def to_param
48:     login
49:   end

Is the Yubico OTP valid and belongs to this account?

[Source]

     # File app/models/account.rb, line 98
 98:   def yubikey_authenticated?(otp)
 99:     if yubico_identity? && Account.verify_yubico_otp(otp)
100:       (Account.extract_yubico_identity_from_otp(otp) == yubico_identity)
101:     else
102:       false
103:     end
104:   end

Protected Instance methods

[Source]

     # File app/models/account.rb, line 171
171:   def encrypt_password
172:     return if password.blank?
173:     self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
174:     self.crypted_password = encrypt(password)
175:   end

[Source]

     # File app/models/account.rb, line 181
181:   def make_activation_code
182:     self.activation_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
183:   end

[Source]

     # File app/models/account.rb, line 185
185:   def make_password_reset_code
186:     self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
187:   end

[Source]

     # File app/models/account.rb, line 177
177:   def password_required?
178:     crypted_password.blank? || !password.blank?
179:   end

[Validate]