identity-vault/app/controllers/identity_totps_controller.rb
nora 87bb6d4a18
Switch mailers to SES (#72)
* add premailer

* first pass at converting existing mailers

* this EIN is not yours :-P

* remove some css that probably won't work

* that was gonna bug me

* more mailers!

* s/account/auth

* rework 2fa/security mailers

* env vars for SES creds

* add OpenSSL explicitly

* use external logo image

* nuke step_up_code
2025-12-04 16:32:32 -05:00

72 lines
2.3 KiB
Ruby

class IdentityTotpsController < ApplicationController
def index
@totp = current_identity.totp
render layout: request.headers["HX-Request"] ? "htmx" : false
end
def new
@totp = current_identity.totps.build
if @totp.save
render :show, layout: request.headers["HX-Request"] ? "htmx" : false
else
render :index, layout: request.headers["HX-Request"] ? "htmx" : false, status: :unprocessable_entity
end
end
def verify
@totp = current_identity.totps.find(params[:id])
code = params[:code]
if @totp.verify(code, drift_behind: 1, drift_ahead: 1)
@totp.mark_verified!
TwoFactorMailer.authentication_method_enabled(current_identity).deliver_later
# Generate backup codes if this is their first 2FA method
codes_generated = []
if current_identity.backup_codes.active.empty?
codes_generated = generate_backup_codes_for_identity(current_identity)
end
if codes_generated.any?
@newly_generated_codes = codes_generated
render :backup_codes, layout: request.headers["HX-Request"] ? "htmx" : false
elsif request.headers["HX-Request"]
response.headers["HX-Redirect"] = security_path
head :ok
else
redirect_to security_path, notice: "TOTP setup complete! Enable 2FA enforcement to require it on login."
end
else
flash.now[:error] = "Invalid code, please try again."
status = request.headers["HX-Request"] ? :ok : :unprocessable_entity
render :show, layout: request.headers["HX-Request"] ? "htmx" : false, status: status
end
rescue ActiveRecord::RecordNotFound
if request.headers["HX-Request"]
response.headers["HX-Redirect"] = security_path
head :ok
else
redirect_to security_path, alert: "TOTP not found"
end
end
def destroy
redirect_to new_step_up_path(action_type: "remove_totp")
end
private
def generate_backup_codes_for_identity(identity)
codes_generated = []
10.times do
backup_code = SecureRandom.alphanumeric(10).upcase
codes_generated << backup_code
identity.backup_codes.create!(code: backup_code, aasm_state: :previewed)
end
identity.backup_codes.previewed.each(&:mark_active!)
identity.create_activity :generate_backup_codes, owner: identity, recipient: identity
codes_generated
end
end