From 58d86cf3acaff5d6a3555afa952649480a35721b Mon Sep 17 00:00:00 2001 From: Emi Matchu Date: Tue, 9 Apr 2024 06:40:56 -0700 Subject: [PATCH] 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". --- app/models/auth_user.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/models/auth_user.rb b/app/models/auth_user.rb index 8a637c81..e5b47fcc 100644 --- a/app/models/auth_user.rb +++ b/app/models/auth_user.rb @@ -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