Prevent user from removing all their login methods

Oh right, if you can remove your email, there's a way to fully lock out
your account:

1. Create account via NeoPass, so no password is set.
2. Ensure you have an email saved, then disconnect NeoPass.
3. Remove the email.
4. Now you have no NeoPass, no email, and no password!

In this change, we add a validation that requires an account to always
have at least one login method. This works well for the case described
above, and also helps offer server-side validation to the "can't
disconnect NeoPass until you have an email and password" stuff that
previously was only enforced by disabling the button.

That is, the following procedure could also lock you out before,
whereas now it raises the "Whoops, there was an error disconnecting
your NeoPass from your account, sorry." message:

1. Create account via NeoPass, so no password is set.
2. Ensure you have an email saved, so "Disconnect" button is enabled.
3. Open a new browser tab, and remove the email.
4. In the original browser tab, click "Disconnect".
This commit is contained in:
Emi Matchu 2024-04-09 06:40:56 -07:00
parent 9384fd2aa7
commit 58d86cf3ac
1 changed files with 9 additions and 0 deletions

View File

@ -9,6 +9,8 @@ class AuthUser < AuthRecord
length: {maximum: 30}
validates :uid, uniqueness: {scope: :provider, allow_nil: true}
validate :has_at_least_one_login_method
has_one :user, foreign_key: :remote_id, inverse_of: :auth_user
@ -136,6 +138,13 @@ class AuthUser < AuthRecord
end
end
def has_at_least_one_login_method
if !uses_password? && !email? && !uses_neopass?
errors.add(:base, "You must have either a password, an email, or a " +
"NeoPass. Otherwise, you can't log in!")
end
end
def self.find_by_omniauth(auth)
find_by(provider: auth.provider, uid: auth.uid)
end