diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..0165922e4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +version: 2 + +updates: + - package-ecosystem: bundler + directory: "/" + schedule: + interval: daily + open-pull-requests-limit: 5 + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + time: "02:00" + timezone: "Etc/UTC" diff --git a/.github/workflows/dynamic-security.yml b/.github/workflows/dynamic-security.yml new file mode 100644 index 000000000..f73eb7fbd --- /dev/null +++ b/.github/workflows/dynamic-security.yml @@ -0,0 +1,19 @@ +name: update-security + +on: + push: + branches: + - main + paths: + - SECURITY.md + workflow_dispatch: + +jobs: + update-security: + permissions: + contents: write + pull-requests: write + pages: write + uses: thoughtbot/templates/.github/workflows/dynamic-security.yaml@main + secrets: + token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2438b34ff..3a3cd334e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,15 @@ complete changelog, see the git history for each version via the version links. ## [Unreleased] -[Unreleased]: https://github.com/thoughtbot/clearance/compare/v2.7.2...main +[Unreleased]: https://github.com/thoughtbot/clearance/compare/v2.8.0...main + +## [2.8.0] - August 9, 2024 +- Feature: Added allow_password_resets config option (#1019) Jos O'shea +- Added dependabot (#1028) Karine Vieira +- Fixed some deprecation warnings (#1018) +- Added a dynamic workflow to update SECURITY.md + +[2.8.0]: https://github.com/thoughtbot/clearance/compare/v2.7.2...v2.8.0 ## [2.7.2] - June 28, 2024 - Fix method redefinition and circular require issues (#1027) diff --git a/Gemfile.lock b/Gemfile.lock index 44f2869ad..f8833fc22 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - clearance (2.7.2) + clearance (2.8.0) actionmailer (>= 5.0) activemodel (>= 5.0) activerecord (>= 5.0) @@ -107,7 +107,7 @@ GEM factory_bot_rails (6.2.0) factory_bot (~> 6.2.0) railties (>= 5.0.0) - ffi (1.16.3) + ffi (1.17.0) ffi-compiler (1.3.2) ffi (>= 1.15.5) rake @@ -130,7 +130,7 @@ GEM mini_mime (1.1.2) mini_portile2 (2.8.6) minitest (5.22.3) - net-imap (0.4.11) + net-imap (0.4.14) date net-protocol net-pop (0.1.2) diff --git a/README.md b/README.md index 9698f393e..8fe714858 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Override any of these defaults in `config/initializers/clearance.rb`: ```ruby Clearance.configure do |config| config.allow_sign_up = true + config.allow_password_reset = true config.cookie_domain = ".example.com" config.cookie_expiration = lambda { |cookies| 1.year.from_now.utc } config.cookie_name = "remember_token" diff --git a/SECURITY.md b/SECURITY.md index 8847f77de..af661807e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,16 +1,20 @@ + # Security Policy ## Supported Versions -We will provide security updates for the latest 3 versions. +Only the the latest version of this project is supported at a given time. If +you find a security issue with an older version, please try updating to the +latest version first. -| Version | Security updates | -| - | - | -| 2.7.x | ✅ | -| 2.6.x | ✅ | -| 2.5.x | ✅ | -| < 2.5.0 | :x: | +If for some reason you can't update to the latest version, please let us know +your reasons so that we can have a better understanding of your situation. ## Reporting a Vulnerability -You can contact . See for more information about our security policy. +For security inquiries or vulnerability reports, visit +. + +If you have any suggestions to improve this policy, visit . + + diff --git a/app/views/sessions/_form.html.erb b/app/views/sessions/_form.html.erb index 31dc415ac..8fb2e9abe 100644 --- a/app/views/sessions/_form.html.erb +++ b/app/views/sessions/_form.html.erb @@ -17,6 +17,8 @@ <% if Clearance.configuration.allow_sign_up? %> <%= link_to t(".sign_up"), sign_up_path %> <% end %> - <%= link_to t(".forgot_password"), new_password_path %> + <% if Clearance.configuration.allow_password_reset? %> + <%= link_to t(".forgot_password"), new_password_path %> + <% end %> <% end %> diff --git a/clearance.gemspec b/clearance.gemspec index 3607fc348..e91d8c12e 100644 --- a/clearance.gemspec +++ b/clearance.gemspec @@ -28,7 +28,8 @@ Gem::Specification.new do |s| 'Jason Morrison', 'Galen Frechette', 'Josh Steiner', - 'Dorian Marié' + 'Dorian Marié', + 'Sara Jackson' ] s.description = <<-DESCRIPTION Clearance is built to support authentication and authorization via an diff --git a/config/routes.rb b/config/routes.rb index 700f7b3e0..08de03e34 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,9 +11,11 @@ resources :users, controller: 'clearance/users', only: Clearance.configuration.user_actions do - resource :password, - controller: 'clearance/passwords', - only: [:edit, :update] + if Clearance.configuration.allow_password_reset? + resource :password, + controller: 'clearance/passwords', + only: [:edit, :update] + end end get '/sign_in' => 'clearance/sessions#new', as: 'sign_in' diff --git a/lib/clearance/configuration.rb b/lib/clearance/configuration.rb index 8a2c70280..75e564f06 100644 --- a/lib/clearance/configuration.rb +++ b/lib/clearance/configuration.rb @@ -7,6 +7,13 @@ class Configuration # @return [Boolean] attr_writer :allow_sign_up + # Controls whether the password reset routes are enabled + # Defaults to `true`. Set to False to disable password reset routes + # The setting is ignored if routes are disabled. + # @param [Boolean] value + # @return [Boolean] + attr_writer :allow_password_reset + # The domain to use for the clearance remember token cookie. # Defaults to `nil`, which causes the cookie domain to default to the # domain of the request. For more, see @@ -145,6 +152,7 @@ class Configuration def initialize @allow_sign_up = true + @allow_password_reset = true @allowed_backdoor_environments = ["test", "ci", "development"] @cookie_domain = nil @cookie_expiration = ->(cookies) { 1.year.from_now.utc } @@ -195,6 +203,12 @@ def allow_sign_up? @allow_sign_up end + # Are the password reset routes enabled? + # @return [Boolean] + def allow_password_reset? + @allow_password_reset + end + # Specifies which controller actions are allowed for user resources. # This will be `[:create]` is `allow_sign_up` is true (the default), and # empty otherwise. diff --git a/lib/clearance/version.rb b/lib/clearance/version.rb index e77ce3ee7..7ab907b57 100644 --- a/lib/clearance/version.rb +++ b/lib/clearance/version.rb @@ -1,3 +1,3 @@ module Clearance - VERSION = "2.7.2".freeze + VERSION = "2.8.0".freeze end diff --git a/spec/configuration_spec.rb b/spec/configuration_spec.rb index 446365023..c6436ece7 100644 --- a/spec/configuration_spec.rb +++ b/spec/configuration_spec.rb @@ -179,6 +179,21 @@ end end + describe "#allow_password_reset?" do + context "when allow_password_reset is configured to false" do + it "returns false" do + Clearance.configure { |config| config.allow_password_reset = false } + expect(Clearance.configuration.allow_password_reset?).to eq false + end + end + + context "when allow_sign_up has not been configured" do + it "returns true" do + expect(Clearance.configuration.allow_password_reset?).to eq true + end + end + end + describe "#user_actions" do context "when allow_sign_up is configured to false" do it "returns empty array" do diff --git a/spec/dummy/application.rb b/spec/dummy/application.rb index 03e56572b..884e27bc5 100644 --- a/spec/dummy/application.rb +++ b/spec/dummy/application.rb @@ -9,6 +9,9 @@ class Application < Rails::Application config.action_controller.perform_caching = false config.action_mailer.default_url_options = { host: "dummy.example.com" } config.action_mailer.delivery_method = :test + if Rails.version.match?(/(6.1|7.0)/) + config.active_record.legacy_connection_handling = false + end config.active_support.deprecation = :stderr config.eager_load = false diff --git a/spec/generators/clearance/install/install_generator_spec.rb b/spec/generators/clearance/install/install_generator_spec.rb index 83ec4b6a9..8c50a8941 100644 --- a/spec/generators/clearance/install/install_generator_spec.rb +++ b/spec/generators/clearance/install/install_generator_spec.rb @@ -2,6 +2,10 @@ require "generators/clearance/install/install_generator" describe Clearance::Generators::InstallGenerator, :generator do + def get_migration(path) + Pathname.new(migration_file(path)) + end + describe "initializer" do it "is copied to the application" do provide_existing_application_controller @@ -66,7 +70,7 @@ table_does_not_exist(:users) run_generator - migration = migration_file("db/migrate/create_users.rb") + migration = get_migration("db/migrate/create_users.rb") expect(migration).to exist expect(migration).to have_correct_syntax @@ -88,7 +92,7 @@ table_does_not_exist(:users) run_generator - migration = migration_file("db/migrate/create_users.rb") + migration = get_migration("db/migrate/create_users.rb") expect(migration).to exist expect(migration).to have_correct_syntax @@ -102,8 +106,8 @@ provide_existing_application_controller run_generator - create_migration = migration_file("db/migrate/create_users.rb") - add_migration = migration_file("db/migrate/add_clearance_to_users.rb") + create_migration = get_migration("db/migrate/create_users.rb") + add_migration = get_migration("db/migrate/add_clearance_to_users.rb") expect(create_migration).not_to exist expect(add_migration).not_to exist @@ -126,7 +130,7 @@ and_return(existing_indexes) run_generator - migration = migration_file("db/migrate/add_clearance_to_users.rb") + migration = get_migration("db/migrate/add_clearance_to_users.rb") expect(migration).to exist expect(migration).to have_correct_syntax diff --git a/spec/routing/clearance_routes_spec.rb b/spec/routing/clearance_routes_spec.rb index 960c1ba90..633824b95 100644 --- a/spec/routing/clearance_routes_spec.rb +++ b/spec/routing/clearance_routes_spec.rb @@ -62,4 +62,36 @@ expect(post: 'users').to be_routable end end + + context 'password reset disabled' do + around do |example| + Clearance.configure { |config| config.allow_password_reset = false } + Rails.application.reload_routes! + example.run + Clearance.configuration = Clearance::Configuration.new + Rails.application.reload_routes! + end + + it 'does not route password edit' do + user = create(:user) + expect(get: "users/#{user.id}/password/edit").not_to be_routable + end + + it 'does not route to clearance/passwords#update' do + user = create(:user) + expect(patch: "/users/#{user.id}/password").not_to be_routable + end + end + + context 'reset enabled' do + it 'does route password edit' do + user = create(:user) + expect(get: "users/#{user.id}/password/edit").to be_routable + end + + it 'does route to clearance/passwords#update' do + user = create(:user) + expect(patch: "/users/#{user.id}/password").to be_routable + end + end end