From b72f88f60f5f69826fc750f29c1bf9c03e123fb8 Mon Sep 17 00:00:00 2001 From: Jez Caudle Date: Tue, 21 May 2024 12:44:08 +0100 Subject: [PATCH] I do believe that OTP/MFA is now working. --- Gemfile | 1 + Gemfile.lock | 6 ++++++ app/assets/stylesheets/application.css | 6 +++--- app/controllers/mfas_controller.rb | 20 ++++++++++++++++++++ app/views/devise/passwords/edit.html.erb | 4 ++-- app/views/devise/registrations/edit.html.erb | 7 +++++++ app/views/devise/sessions/new.html.erb | 5 +++++ app/views/layouts/application.html.erb | 11 ++++++++++- app/views/mfas/new.html.erb | 9 +++++++++ config/routes.rb | 2 ++ 10 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 app/controllers/mfas_controller.rb create mode 100644 app/views/mfas/new.html.erb diff --git a/Gemfile b/Gemfile index 8eff759..60fa10e 100644 --- a/Gemfile +++ b/Gemfile @@ -8,6 +8,7 @@ gem "rails", "7.1.3.3" gem 'devise' gem 'devise-two-factor' +gem 'rqrcode' # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] gem "sprockets-rails" diff --git a/Gemfile.lock b/Gemfile.lock index 8a6aa57..bd09eb5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -93,6 +93,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) + chunky_png (1.4.0) concurrent-ruby (1.2.3) connection_pool (2.4.1) crass (1.0.6) @@ -212,6 +213,10 @@ GEM railties (>= 5.2) rexml (3.2.6) rotp (6.3.0) + rqrcode (2.2.0) + chunky_png (~> 1.0) + rqrcode_core (~> 1.0) + rqrcode_core (1.2.0) rubyzip (2.3.2) selenium-webdriver (4.20.1) base64 (~> 0.2) @@ -266,6 +271,7 @@ DEPENDENCIES mysql2 (~> 0.5) puma (~> 6.0) rails (= 7.1.3.3) + rqrcode selenium-webdriver sprockets-rails stimulus-rails diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 8053f18..eecd148 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -89,12 +89,12 @@ menu > li { flex-grow: 1; } -.domain { +.domain, .mfa { background-color: #efefef; border-radius:1rem; padding:1rem; } -.domain-header { +.domain-header, .mfa-header { background-color: #fefefe; border-radius:1rem; padding:1rem 1rem; @@ -108,7 +108,7 @@ menu > li { scale: 75%; } -.email-list, .domain-list { +.email-list, .domain-list, .mfa-list { border-radius:1rem; border:1rem black; background-color:#e7eae7; diff --git a/app/controllers/mfas_controller.rb b/app/controllers/mfas_controller.rb new file mode 100644 index 0000000..87a0c2e --- /dev/null +++ b/app/controllers/mfas_controller.rb @@ -0,0 +1,20 @@ +class MfasController < ApplicationController + def new + issuer = "Hidden Agenda Email" + label = "#{issuer}:#{current_user.email}" + current_user.otp_secret = User.generate_otp_secret + current_user.save! + + qrcode = RQRCode::QRCode.new([{ data: current_user.otp_provisioning_uri(label, issuer: issuer), mode: :byte_8bit }]) + + @svg = qrcode.as_svg(color: "000", shape_rendering: "crispEdges", module_size: 5, standalone: true, + use_path: true +) + end + + def create + current_user.otp_required_for_login = true + current_user.save! + redirect_to root_url + end +end diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb index 5fbb9ff..c45e721 100644 --- a/app/views/devise/passwords/edit.html.erb +++ b/app/views/devise/passwords/edit.html.erb @@ -21,5 +21,5 @@ <%= f.submit "Change my password" %> <% end %> - -<%= render "devise/shared/links" %> +
+<%#= render "devise/shared/links" %> diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index c5e9dd3..87415a2 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -35,5 +35,12 @@ <%= f.submit "Update" %> <% end %> +
+<% if current_user.otp_secret.to_s.size == 0 %> + <%= link_to "Enable MFA", new_mfa_path %> +<% else %> + <%= link_to "Edit MFA", new_mfa_path %> +<% end %> +| <%= link_to "Back", :back %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 811d9bf..68b4714 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -12,6 +12,11 @@ <%= f.password_field :password, autocomplete: "current-password", class: "input" %> +
+ <%= f.label :otp_attempt, class: "my-2" %> + <%= f.password_field :otp_attempt, autocomplete: "OTP Code", class: "input" %> +
+ <% if devise_mapping.rememberable? %>
<%= f.check_box :remember_me, class: "checkbox mr-3" %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 8108e38..92c96bb 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -26,12 +26,21 @@ <% if alert %>
<%= alert %>
<% end %> <%= yield %> + <% if Rails.env == "development" %>
RoR Version <%= Rails.version %> (<%=Rails.env%>) | Ruby <%= "#{RUBY_VERSION}p#{RUBY_PATCHLEVEL}" %> | OS <%= RUBY_PLATFORM %> | App Version <%= `git describe --always` %> + + <% if user_signed_in? %> +
+ <%= "User:#{current_user.email} | OTP for login:#{current_user.otp_required_for_login} | " %> + <% end %> + + <% end %>
diff --git a/app/views/mfas/new.html.erb b/app/views/mfas/new.html.erb new file mode 100644 index 0000000..5fa633c --- /dev/null +++ b/app/views/mfas/new.html.erb @@ -0,0 +1,9 @@ +
+

New MFA

+
+

Scan the code below and then click "Done".

+

You will only be able to login with your authenticator app once you have clicked "Done"

+ <%= @svg.html_safe%> +

<%= link_to "Done", mfas_path, data: { turbo_method: :post} %>

+
+
diff --git a/config/routes.rb b/config/routes.rb index 413153f..cf46274 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,6 +11,8 @@ Rails.application.routes.draw do put 'users' => 'devise/registrations#update', :as => 'user_registration' end + resources :mfas, only: [:new, :create] + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Defines the root path route ("/")