diff --git a/Gemfile b/Gemfile index bd49a0f2..dd1861b9 100644 --- a/Gemfile +++ b/Gemfile @@ -10,6 +10,7 @@ gem 'pg', '~> 1.5', '>= 1.2.3' # users gem "devise", ">= 4.7.1" gem 'devise-security' +gem 'devise-two-factor' gem "turnstile-captcha", require: "turnstile" gem 'gibbon' # mailchimp connector diff --git a/Gemfile.lock b/Gemfile.lock index 4e3b06bd..4b2d1d3c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -70,6 +70,8 @@ GEM zeitwerk (~> 2.3) addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) + attr_encrypted (4.0.0) + encryptor (~> 3.0.0) autoprefixer-rails (9.7.6) execjs awesome_print (1.9.2) @@ -143,6 +145,12 @@ GEM warden (~> 1.2.3) devise-security (0.17.0) devise (>= 4.3.0) + devise-two-factor (4.1.0) + activesupport (< 7.1) + attr_encrypted (>= 1.3, < 5, != 2) + devise (~> 4.0) + railties (< 7.1) + rotp (~> 6.0) diff-lcs (1.4.4) docile (1.3.2) domain_name (0.5.20190701) @@ -152,6 +160,7 @@ GEM htmlentities (~> 4.3.3) launchy (~> 2.1) mail (~> 2.7) + encryptor (3.0.0) erubi (1.12.0) excon (0.91.0) execjs (2.7.0) @@ -366,6 +375,7 @@ GEM reverse_markdown (2.1.1) nokogiri rinku (2.0.6) + rotp (6.3.0) rspec (3.10.0) rspec-core (~> 3.10.0) rspec-expectations (~> 3.10.0) @@ -493,6 +503,7 @@ DEPENDENCIES derailed_benchmarks devise (>= 4.7.1) devise-security + devise-two-factor email_reply_trimmer email_spec factory_bot_rails diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 19b7f147..80e3936c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -39,6 +39,7 @@ def configure_permitted_parameters devise_parameter_sanitizer.permit :sign_up, keys: added_attrs devise_parameter_sanitizer.permit :account_update, keys: [:email, :password, :password_confirmation] devise_parameter_sanitizer.permit :preferences, keys: added_attrs + [{ frequency: [] }, :way_back_past_entries, :send_past_entry, :send_time, :send_timezone, :past_filter, :current_password, hashtags_attributes: [:tag, :date]] + devise_parameter_sanitizer.for(:sign_in) << :otp_attempt end def js_action diff --git a/app/models/user.rb b/app/models/user.rb index 52ca284e..01038ebc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,10 +1,15 @@ class User < ActiveRecord::Base + devise :two_factor_authenticatable, + :otp_secret_encryption_key => ENV['OTP_ENCRYPTION_KEY'] + include RandomizedField # Include default devise modules. Others available are: # :confirmable, :timeoutable and :omniauthable, :lockable - devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :trackable, :validatable, :paranoid_verification + devise :registerable, + :recoverable, :rememberable, :trackable, :validatable, :paranoid_verification, + :two_factor_authenticatable, :two_factor_backupable, + :otp_secret_encryption_key => ENV["OTP_ENCRYPTION_KEY"] randomized_field :user_key, length: 18 do |slug_value| "u#{slug_value}" diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 87045238..5b3223e2 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,6 +1,11 @@ # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| + config.warden do |manager| + manager.default_strategies(:scope => :user).unshift :two_factor_authenticatable + manager.default_strategies(:scope => :user).unshift :two_factor_backupable + end + # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. @@ -240,7 +245,7 @@ # # config.warden do |manager| # manager.intercept_401 = false - # manager.default_strategies(scope: :user).unshift :some_external_strategy + # manager.default_strategies(:scope => :user).unshift :two_factor_backupable # end # ==> Mountable engine configurations diff --git a/db/migrate/20231004043016_add_devise_two_factor_to_users.rb b/db/migrate/20231004043016_add_devise_two_factor_to_users.rb new file mode 100644 index 00000000..de5e8646 --- /dev/null +++ b/db/migrate/20231004043016_add_devise_two_factor_to_users.rb @@ -0,0 +1,10 @@ +class AddDeviseTwoFactorToUsers < ActiveRecord::Migration[6.1] + def change + add_column :users, :encrypted_otp_secret, :string + add_column :users, :encrypted_otp_secret_iv, :string + add_column :users, :encrypted_otp_secret_salt, :string + add_column :users, :consumed_timestep, :integer + add_column :users, :otp_required_for_login, :boolean + add_column :users, :otp_backup_codes, :string, array: true + end +end