User registation working. Sidebar built. Dashboard built. TOTP enable works - TOTP login works
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
class SessionsController < ApplicationController
|
class SessionsController < ApplicationController
|
||||||
allow_unauthenticated_access only: %i[ new create ]
|
allow_unauthenticated_access only: %i[ new create verify_totp ]
|
||||||
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to signin_path, alert: "Too many attempts. Try again later." }
|
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to signin_path, alert: "Too many attempts. Try again later." }
|
||||||
|
rate_limit to: 5, within: 3.minutes, only: :verify_totp, with: -> { redirect_to totp_verification_path, alert: "Too many attempts. Try again later." }
|
||||||
|
|
||||||
def new
|
def new
|
||||||
# Redirect to signup if this is first run
|
# Redirect to signup if this is first run
|
||||||
@@ -23,9 +24,9 @@ class SessionsController < ApplicationController
|
|||||||
|
|
||||||
# Check if TOTP is required
|
# Check if TOTP is required
|
||||||
if user.totp_enabled?
|
if user.totp_enabled?
|
||||||
# TODO: Implement TOTP verification flow
|
# Store user ID in session temporarily for TOTP verification
|
||||||
# For now, reject login if TOTP is enabled
|
session[:pending_totp_user_id] = user.id
|
||||||
redirect_to signin_path, alert: "Two-factor authentication is enabled but not yet implemented. Please contact an administrator."
|
redirect_to totp_verification_path
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -34,6 +35,49 @@ class SessionsController < ApplicationController
|
|||||||
redirect_to after_authentication_url, notice: "Signed in successfully."
|
redirect_to after_authentication_url, notice: "Signed in successfully."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def verify_totp
|
||||||
|
# Get the pending user from session
|
||||||
|
user_id = session[:pending_totp_user_id]
|
||||||
|
unless user_id
|
||||||
|
redirect_to signin_path, alert: "Session expired. Please sign in again."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
user = User.find_by(id: user_id)
|
||||||
|
unless user
|
||||||
|
session.delete(:pending_totp_user_id)
|
||||||
|
redirect_to signin_path, alert: "Session expired. Please sign in again."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Handle form submission
|
||||||
|
if request.post?
|
||||||
|
code = params[:code]&.strip
|
||||||
|
|
||||||
|
# Try TOTP verification first
|
||||||
|
if user.verify_totp(code)
|
||||||
|
session.delete(:pending_totp_user_id)
|
||||||
|
start_new_session_for user
|
||||||
|
redirect_to after_authentication_url, notice: "Signed in successfully."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Try backup code verification
|
||||||
|
if user.verify_backup_code(code)
|
||||||
|
session.delete(:pending_totp_user_id)
|
||||||
|
start_new_session_for user
|
||||||
|
redirect_to after_authentication_url, notice: "Signed in successfully using backup code."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Invalid code
|
||||||
|
redirect_to totp_verification_path, alert: "Invalid verification code. Please try again."
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Just render the form
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
terminate_session
|
terminate_session
|
||||||
redirect_to signin_path, status: :see_other, notice: "Signed out successfully."
|
redirect_to signin_path, status: :see_other, notice: "Signed out successfully."
|
||||||
|
|||||||
56
app/views/sessions/verify_totp.html.erb
Normal file
56
app/views/sessions/verify_totp.html.erb
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<div class="mx-auto max-w-md">
|
||||||
|
<div class="bg-white py-8 px-6 shadow rounded-lg sm:px-10">
|
||||||
|
<div class="mb-8">
|
||||||
|
<h2 class="text-2xl font-bold text-gray-900">Two-Factor Authentication</h2>
|
||||||
|
<p class="mt-2 text-sm text-gray-600">
|
||||||
|
Enter the 6-digit code from your authenticator app to complete sign in.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= form_with url: totp_verification_path, method: :post, class: "space-y-6" do |form| %>
|
||||||
|
<div>
|
||||||
|
<%= label_tag :code, "Verification Code", class: "block text-sm font-medium text-gray-700" %>
|
||||||
|
<%= text_field_tag :code,
|
||||||
|
nil,
|
||||||
|
placeholder: "000000",
|
||||||
|
maxlength: 8,
|
||||||
|
required: true,
|
||||||
|
autofocus: true,
|
||||||
|
autocomplete: "off",
|
||||||
|
class: "mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 text-center text-2xl tracking-widest font-mono sm:text-sm" %>
|
||||||
|
<p class="mt-2 text-xs text-gray-500">
|
||||||
|
Enter your 6-digit authenticator code or an 8-character backup code
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<%= form.submit "Verify",
|
||||||
|
class: "w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
<div class="relative">
|
||||||
|
<div class="absolute inset-0 flex items-center">
|
||||||
|
<div class="w-full border-t border-gray-300"></div>
|
||||||
|
</div>
|
||||||
|
<div class="relative flex justify-center text-sm">
|
||||||
|
<span class="px-2 bg-white text-gray-500">Need help?</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<p class="text-sm text-gray-600">
|
||||||
|
Lost access to your authenticator?
|
||||||
|
</p>
|
||||||
|
<p class="mt-1 text-xs text-gray-500">
|
||||||
|
Contact an administrator for assistance.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<%= link_to "Cancel and sign in again", signin_path, class: "text-sm text-blue-600 hover:text-blue-500" %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -15,6 +15,8 @@ Rails.application.routes.draw do
|
|||||||
get "/signin", to: "sessions#new", as: :signin
|
get "/signin", to: "sessions#new", as: :signin
|
||||||
post "/signin", to: "sessions#create"
|
post "/signin", to: "sessions#create"
|
||||||
delete "/signout", to: "sessions#destroy", as: :signout
|
delete "/signout", to: "sessions#destroy", as: :signout
|
||||||
|
get "/totp-verification", to: "sessions#verify_totp", as: :totp_verification
|
||||||
|
post "/totp-verification", to: "sessions#verify_totp"
|
||||||
|
|
||||||
# Authenticated routes
|
# Authenticated routes
|
||||||
root "dashboard#index"
|
root "dashboard#index"
|
||||||
|
|||||||
Reference in New Issue
Block a user