about summary refs log tree commit diff
path: root/app/controllers/concerns/two_factor_authentication_concern.rb
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2020-08-30 16:13:08 +0200
committerThibaut Girka <thib@sitedethib.com>2020-08-30 16:13:08 +0200
commit8c3c27bf063d648823da39a206be3efd285611ad (patch)
treec78c0bed2bab5ed64a7dfd546b91b21600947112 /app/controllers/concerns/two_factor_authentication_concern.rb
parent30632adf9eda6d83a9b4269f23f11ced5e09cd93 (diff)
parent52157fdcba0837c782edbfd240be07cabc551de9 (diff)
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts:
- `app/controllers/accounts_controller.rb`:
  Upstream change too close to a glitch-soc change related to
  instance-local toots. Merged upstream changes.
- `app/services/fan_out_on_write_service.rb`:
  Minor conflict due to glitch-soc's handling of Direct Messages,
  merged upstream changes.
- `yarn.lock`:
  Not really a conflict, caused by glitch-soc-only dependencies
  being textually too close to updated upstream dependencies.
  Merged upstream changes.
Diffstat (limited to 'app/controllers/concerns/two_factor_authentication_concern.rb')
-rw-r--r--app/controllers/concerns/two_factor_authentication_concern.rb45
1 files changed, 41 insertions, 4 deletions
diff --git a/app/controllers/concerns/two_factor_authentication_concern.rb b/app/controllers/concerns/two_factor_authentication_concern.rb
index 35c0c27cf..6b043a804 100644
--- a/app/controllers/concerns/two_factor_authentication_concern.rb
+++ b/app/controllers/concerns/two_factor_authentication_concern.rb
@@ -8,7 +8,23 @@ module TwoFactorAuthenticationConcern
   end
 
   def two_factor_enabled?
-    find_user&.otp_required_for_login?
+    find_user&.two_factor_enabled?
+  end
+
+  def valid_webauthn_credential?(user, webauthn_credential)
+    user_credential = user.webauthn_credentials.find_by!(external_id: webauthn_credential.id)
+
+    begin
+      webauthn_credential.verify(
+        session[:webauthn_challenge],
+        public_key: user_credential.public_key,
+        sign_count: user_credential.sign_count
+      )
+
+      user_credential.update!(sign_count: webauthn_credential.sign_count)
+    rescue WebAuthn::Error
+      false
+    end
   end
 
   def valid_otp_attempt?(user)
@@ -21,14 +37,29 @@ module TwoFactorAuthenticationConcern
   def authenticate_with_two_factor
     user = self.resource = find_user
 
-    if user_params[:otp_attempt].present? && session[:attempt_user_id]
-      authenticate_with_two_factor_attempt(user)
+    if user.webauthn_enabled? && user_params[:credential].present? && session[:attempt_user_id]
+      authenticate_with_two_factor_via_webauthn(user)
+    elsif user_params[:otp_attempt].present? && session[:attempt_user_id]
+      authenticate_with_two_factor_via_otp(user)
     elsif user.present? && user.external_or_valid_password?(user_params[:password])
       prompt_for_two_factor(user)
     end
   end
 
-  def authenticate_with_two_factor_attempt(user)
+  def authenticate_with_two_factor_via_webauthn(user)
+    webauthn_credential = WebAuthn::Credential.from_get(user_params[:credential])
+
+    if valid_webauthn_credential?(user, webauthn_credential)
+      session.delete(:attempt_user_id)
+      remember_me(user)
+      sign_in(user)
+      render json: { redirect_path: root_path }, status: :ok
+    else
+      render json: { error: t('webauthn_credentials.invalid_credential') }, status: :unprocessable_entity
+    end
+  end
+
+  def authenticate_with_two_factor_via_otp(user)
     if valid_otp_attempt?(user)
       session.delete(:attempt_user_id)
       remember_me(user)
@@ -44,6 +75,12 @@ module TwoFactorAuthenticationConcern
       session[:attempt_user_id] = user.id
       use_pack 'auth'
       @body_classes = 'lighter'
+      @webauthn_enabled = user.webauthn_enabled?
+      @scheme_type = if user.webauthn_enabled? && user_params[:otp_attempt].blank?
+                       'webauthn'
+                     else
+                       'totp'
+                     end
       render :two_factor
     end
   end