devise-argon2 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +47 -0
  3. data/.gitignore +3 -0
  4. data/CHANGELOG.md +20 -0
  5. data/Gemfile +7 -4
  6. data/README.md +119 -32
  7. data/devise-argon2.gemspec +15 -12
  8. data/lib/devise-argon2/model.rb +89 -0
  9. data/lib/devise-argon2/version.rb +5 -0
  10. data/lib/devise-argon2.rb +8 -3
  11. data/spec/devise-argon2_spec.rb +224 -27
  12. data/spec/orm/active_record.rb +1 -0
  13. data/spec/orm/mongoid.rb +5 -0
  14. data/spec/rails_app/Rakefile +6 -0
  15. data/spec/rails_app/app/active_record/old_user.rb +3 -0
  16. data/spec/rails_app/app/active_record/user.rb +3 -0
  17. data/spec/rails_app/app/controllers/application_controller.rb +3 -0
  18. data/spec/rails_app/app/mongoid/old_user.rb +12 -0
  19. data/spec/rails_app/app/mongoid/user.rb +10 -0
  20. data/spec/rails_app/bin/bundle +109 -0
  21. data/spec/rails_app/bin/rails +4 -0
  22. data/spec/rails_app/bin/rake +4 -0
  23. data/spec/rails_app/bin/setup +33 -0
  24. data/spec/rails_app/config/application.rb +24 -0
  25. data/spec/rails_app/config/boot.rb +5 -0
  26. data/spec/rails_app/config/database.yml +14 -0
  27. data/spec/rails_app/config/environment.rb +7 -0
  28. data/spec/rails_app/config/initializers/devise.rb +6 -0
  29. data/spec/rails_app/config/mongoid.yml +10 -0
  30. data/spec/rails_app/config.ru +6 -0
  31. data/spec/rails_app/db/migrate/20230617201921_devise_create_users.rb +15 -0
  32. data/spec/rails_app/db/migrate/20231004084147_devise_create_old_users.rb +17 -0
  33. data/spec/rails_app/db/schema.rb +31 -0
  34. data/spec/spec_helper.rb +7 -3
  35. metadata +57 -25
  36. data/.travis.yml +0 -13
  37. data/lib/devise/encryptable/encryptors/argon2/version.rb +0 -7
  38. data/lib/devise/encryptable/encryptors/argon2.rb +0 -17
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6710d39a7495e895f798cb907b4d4e4d67fa0f39fd3141d2a4d76d6da0c0b7a4
4
- data.tar.gz: 48086d611acd10f4d91b2ccfa229bac0abe6f587abdae1a3b3df154c6d2d6408
3
+ metadata.gz: 6d20fef20b04b01fd33fd4e8b7104f50ef57ce75e6a4406df46a3ea10fe693a1
4
+ data.tar.gz: 7b66c6a1e646eea75a16c43ae37a95b557e6342488885a73ab60a80d3d5903a5
5
5
  SHA512:
6
- metadata.gz: 9e1be2f0b26ca41bb61ea3f42d1bfae79e59b1a670fe23574d1453138173caa8e4267266a169d9bfcc15bead58be9fb8009d70d183bf18a22967682ba58c095a
7
- data.tar.gz: 22671a23d33b2de4c6c5ee5e50d1e5eb6a46009c338612256138b8ad72ff05cef442854c9f6ceab4f7a42934fbbafad0d213ce898c9c6ce6916c58625bed0335
6
+ metadata.gz: 668de52215782a24691ec1d44ced5c85376d99099da8352c583a3452fb78d60e928fef311efe5bdfadffc5dfac130b1affabf9ce26b0197ea807d5602ed257d8
7
+ data.tar.gz: 12669cb6bbd94d3cc6e0427a6bf805152417f47858145daf6fba20907d32c10f9c8bedf4535a7ede8af0c572723886537ee782967e7b9b7e5566ec01c6f6ec27
@@ -0,0 +1,47 @@
1
+ name: Test suite
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ matrix:
10
+ ruby-version: ['2.7', '3.0', '3.1', '3.2', 'ruby-head']
11
+ rails-version: ['~> 7.0', '~> 6.1']
12
+ orm:
13
+ - adapter: active_record
14
+ - adapter: mongoid
15
+ mongoid-version: 8.1.2
16
+ - adapter: mongoid
17
+ mongoid-version: 8.0.6
18
+ - adapter: mongoid
19
+ mongoid-version: 7.5.4
20
+ include:
21
+ - rails-version: '~> 7.1'
22
+ ruby-version: '3.1'
23
+ orm:
24
+ adapter: active_record
25
+ - rails-version: '~> 7.1'
26
+ ruby-version: '3.2'
27
+ orm:
28
+ adapter: active_record
29
+ env:
30
+ RAILS_VERSION: ${{ matrix.rails-version || '~> 7.0'}}
31
+ MONGOID_VERSION: ${{ matrix.orm.mongoid-version || '8.1.2'}}
32
+ ORM: ${{ matrix.orm.adapter }}
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - name: Set up Ruby ${{ matrix.ruby-version }}
36
+ uses: ruby/setup-ruby@v1
37
+ with:
38
+ ruby-version: ${{ matrix.ruby-version }}
39
+ bundler-cache: true
40
+ - uses: supercharge/mongodb-github-action@1.10.0
41
+ if: ${{ matrix.orm.adapter == 'mongoid' }}
42
+ - name: Setup rails test environment
43
+ run: |
44
+ cd spec/rails_app
45
+ RAILS_ENV=test bin/rails db:setup
46
+ - name: Run tests
47
+ run: bundle exec rspec
data/.gitignore CHANGED
@@ -12,6 +12,9 @@ lib/bundler/man
12
12
  pkg
13
13
  rdoc
14
14
  spec/reports
15
+ spec/rails_app/log/*
16
+ spec/rails_app/tmp/*
17
+ spec/rails_app/db/test.sqlite3
15
18
  test/tmp
16
19
  test/version_tmp
17
20
  tmp
data/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ### Added
6
+ - Expose Argon2 options for configuring hashing work factors
7
+ - Add support for migration v1 hashes
8
+ - Add support for migrating bcrypt hashes
9
+ - Add tests for Mongoid
10
+ - Add Changelog :)
11
+
12
+ ### Changed
13
+ - Change salting / peppering mechanism
14
+ - Change CI from Travis to GitHub Actions
15
+
16
+ ### Removed
17
+ - Remove `devise-encryptable` dependency
18
+ - Remove superflous dependency on devise `password_salt` column
19
+
20
+
data/Gemfile CHANGED
@@ -1,10 +1,13 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in gvoe_auth-client.gemspec
4
3
  gemspec
5
4
 
6
5
  gem 'rspec'
7
6
  gem 'simplecov'
8
- gem 'activesupport'
9
- gem 'activemodel'
10
- gem 'pry'
7
+ gem 'activerecord'
8
+ gem 'sqlite3'
9
+ gem 'rails', ENV['RAILS_VERSION'] || '~> 7.0'
10
+
11
+ if ENV['ORM'] == 'mongoid'
12
+ gem 'mongoid', ENV['MONGOID_VERSION'] || '~> 7.5'
13
+ end
data/README.md CHANGED
@@ -1,41 +1,124 @@
1
- devise-argon2 [![Build Status](https://secure.travis-ci.org/erdostom/devise-argon2.png)][Continuous Integration] [![Gem Version](https://badge.fury.io/rb/devise-argon2.svg)](https://badge.fury.io/rb/devise-argon2)
2
- =============
1
+ # devise-argon2
2
+ [![Gem Version](https://badge.fury.io/rb/devise-argon2.svg)](https://badge.fury.io/rb/devise-argon2)
3
3
 
4
- **A [devise-encryptable] password encryptor that uses [argon2]**
4
+ A ruby gem that gives Devise models which use `database_authenticatable` the ability to hash
5
+ passwords with Argon2id.
5
6
 
6
- * [Continuous Integration]
7
+ ## Installation
7
8
 
8
- [Continuous Integration]: http://travis-ci.org/erdostom/devise-argon2 "Continuous integration @ travis-ci.org"
9
-
10
- [argon2]: https://github.com/technion/ruby-argon2
11
- [devise]: https://github.com/plataformatec/devise
12
- [devise-encryptable]: https://github.com/plataformatec/devise-encryptable
13
-
14
- ## Why use Argon2?
15
-
16
- Argon2 won Password Hashing Competition and offers additional security compared to the default `bcrypt` by adding a memory cost. More info:
17
-
18
- - https://github.com/P-H-C/phc-winner-argon2
19
- - https://hynek.me/articles/storing-passwords/
9
+ ```
10
+ bundle add devise-argon2
11
+ ```
20
12
 
21
13
  ## Usage
22
14
 
23
- Assuming you have [devise] (>= 2.1) and the [devise-encryptable] plugin
24
- set up in your application, add `devise-argon2` to your `Gemfile` and `bundle`:
25
-
26
- gem 'devise-argon2'
15
+ Add `devise :argon2` to your Devise model. For example:
16
+
17
+ ```
18
+ class User < ApplicationRecord
19
+ devise :database_authenticatable, :argon2
20
+ end
21
+ ```
22
+
23
+ Now the password of a newly created user will be hashed with Argon2id. Existing BCrypt hashes will
24
+ continue to work; if the password of a user is hashed with BCrypt, the Argon2id hash will replace
25
+ the existing hash as soon as a user signs in (more specifically: as soon as `valid_password?`
26
+ is called with a valid password).
27
+
28
+ ## Configuration
29
+
30
+ ### Argon2 options
31
+
32
+ For Argon2 hashing the gem [ruby-argon2](https://github.com/technion/ruby-argon2) is used, which
33
+ provides FFI bindings to the
34
+ [Argon 2 reference implementation](https://github.com/P-H-C/phc-winner-argon2).
35
+ `ruby-argon2` can be configured by passing parameters like `profile`, `t_cost`, `m_cost`, `p_cost`,
36
+ or `secret` to `Argon2::Password.new`. These parameters can be set like this:
37
+
38
+ ```
39
+ class User < ApplicationRecord
40
+ devise :database_authenticatable,
41
+ :argon2,
42
+ argon2_options: { t_cost: 3, p_cost: 2 }
43
+ end
44
+ ```
45
+
46
+ If the the configured work factors differ from the work factors of the hash in the database, the
47
+ password will be re-hashed as soon as `valid_password?` is called with a valid password.
48
+
49
+ ### Pepper/secret key
50
+
51
+ The [Argon 2 reference implementation](https://github.com/P-H-C/phc-winner-argon2#library) has a
52
+ built-in pepper which is called `secret`. This Argon2 secret key can be set like this:
53
+
54
+ ```
55
+ class User < ApplicationRecord
56
+ devise :database_authenticatable,
57
+ :argon2,
58
+ argon2_options: { secret: ENV['ARGON2_SECRET_KEY'] }
59
+ end
60
+ ```
61
+
62
+ Traditionally, peppers in Devise are configured by setting `config.pepper` in `devise.rb`. This
63
+ option in honored but `argon2_options[:secret]` takes precedence over `config.pepper`. Specifically:
64
+ - `config.pepper` is used as secret key for new hashes if and only if `argon2_options[:secret]` is
65
+ not set.
66
+ - The verification of existing BCrypt hashes is not touched, so it continues to use `config.pepper`
67
+ as pepper.
68
+
69
+ ## Updating from version 1
70
+
71
+ With version 2 come two major changes: First, `devise-encryptable` is no longer needed. Second, the mechanism for salting
72
+ and peppering has changed: Salts are now managed by Argon2 and the pepper is passed as secret key
73
+ parameter. If you have existing hashes in your database that have been generated by
74
+ devise-argon2 v1, you'll need to set `:migrate_from_devise_argon2_v1` in `argon2_options`.
75
+
76
+ With this option your existing hashes will continue to work as the old mechanism for salting and
77
+ peppering is used if and only if `password_salt` is truthy. The first time you pass a valid
78
+ password to `valid_password?`, the hash will be updated and `password_salt` will be set to `nil`.
79
+ The next time you call `valid_password?` the new salting and peppering mechanism will be used
80
+ because `password_salt` is not truthy anymore.
81
+
82
+ As soon as all `password_salt` fields are set to `nil`, you can delete the column from the database
83
+ and remove `:migrate_from_devise_argon2_v1` from `argon2_options`.
84
+
85
+ Please note that this works only if your database table has a field `password_salt`.
86
+
87
+ ### Upgrade Steps
88
+
89
+ 1. Update your `Gemfile` to use `devise-argon2` version 2: `gem 'devise-argon2', '~> 2.0'`
90
+ 1. Remove `devise-encryptable` from your `Gemfile`
91
+ 1. Run `bundle install`
92
+ 1. Remove the line `config.encryptor = :argon2` from `config/initializers/devise.rb`
93
+ 1. Change your Devise model by removing `:encryptable` and adding `:argon2, argon2_options: { migrate_from_devise_argon2_v1: true }`
94
+ 1. It should now look something like this
95
+
96
+ ```
97
+ class User < ApplicationRecord
98
+ devise :database_authenticatable,
99
+ :argon2,
100
+ argon2_options: { migrate_from_devise_argon2_v1: true }
101
+ end
102
+ ```
103
+
104
+ That's it, you're done! Your users will now be able to log in with their existing passwords and their passwords will be migrated to the V2 format the next time they log in.
105
+
106
+ ---
107
+
108
+ Once all of your users' passwords are migrated to the V2 format:
109
+ 1. Remove the `argon2_options { migrated_from_devise_argon2_v1: true }` line from your Devise model
110
+ 1. Delete the `password_salt` column from your database using a migration like this:
111
+ ```
112
+ class RemovePasswordSaltFromUsers < ActiveRecord::Migration[7.1]
113
+ def change
114
+ remove_column :users, :password_salt, :string
115
+ end
116
+ end
117
+ ```
118
+
119
+ Note: If you do this before all of your users' passwords are migrated to the V2 format, they will be unable to log
120
+ in with their current passwords.
27
121
 
28
- Then open up your [devise] configuration,`config/initializers/devise.rb` and configure your encryptor to be `argon2`:
29
-
30
- # config/initializers/devise.rb
31
- Devise.setup do |config|
32
- # ..
33
- config.encryptor = :argon2
34
- # ...
35
- end
36
-
37
- It is also recommended to uncomment (or add) `config.pepper` with a random
38
- string that will be used in addition to the per-user `password_salt` when hashing.
39
122
 
40
123
  ## Contributing
41
124
 
@@ -45,6 +128,10 @@ string that will be used in addition to the per-user `password_salt` when hashin
45
128
  4. Push to the branch (`git push origin my-new-feature`)
46
129
  5. Create new Pull Request
47
130
 
48
- ## Copyright
131
+ ## Contributors
132
+
133
+ Please see here for full list of contributors: https://github.com/erdostom/devise-argon2/graphs/contributors
134
+
135
+ ## License
49
136
 
50
137
  Released under MIT License.
@@ -1,23 +1,26 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "devise/encryptable/encryptors/argon2/version"
4
+ require "devise-argon2/version"
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "devise-argon2"
8
- gem.version = Devise::Encryptable::Encryptors::ARGON2_VERSION
9
- gem.authors = ["Tamas Erdos"]
10
- gem.email = ["tamas at tamaserdos com"]
11
- gem.description = %q{A devise-encryptable password encryptor that uses Argon2}
12
- gem.summary = %q{A devise-encryptable password encryptor that uses Argon2}
13
- gem.homepage = "https://github.com/erdostom/devise-argon2"
7
+ gem.name = "devise-argon2"
8
+ gem.version = Devise::Argon2::ARGON2_VERSION
9
+ gem.authors = ["Tamas Erdos"]
10
+ gem.email = ["tamas at tamaserdos com"]
11
+ gem.description = %q{Enables Devise to hash passwords with Argon2id}
12
+ gem.summary = %q{Enables Devise to hash passwords with Argon2id}
13
+ gem.license = 'MIT'
14
+ gem.homepage = "https://github.com/erdostom/devise-argon2"
14
15
 
15
- gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.files = `git ls-files`.split($/)
17
+ gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
19
  gem.require_paths = ["lib"]
19
20
 
20
21
  gem.add_dependency 'devise', '>= 2.1.0'
21
- gem.add_dependency 'devise-encryptable', '>= 0.2.0'
22
22
  gem.add_dependency 'argon2', '~> 2.0'
23
+
24
+
25
+ gem.post_install_message = "Version 2 of devise-argon2 introduces breaking changes, please see README.md for details."
23
26
  end
@@ -0,0 +1,89 @@
1
+ require 'argon2'
2
+
3
+ module Devise
4
+ module Models
5
+ module Argon2
6
+ def valid_password?(password)
7
+ is_valid = hash_needs_update = false
8
+
9
+ if ::Argon2::Password.valid_hash?(encrypted_password)
10
+ if migrate_hash_from_devise_argon2_v1?
11
+ is_valid = ::Argon2::Password.verify_password(
12
+ "#{password}#{password_salt}#{self.class.pepper}",
13
+ encrypted_password
14
+ )
15
+ hash_needs_update = true
16
+ else
17
+ argon2_secret = (self.class.argon2_options[:secret] || self.class.pepper)
18
+ is_valid = ::Argon2::Password.verify_password(
19
+ password,
20
+ encrypted_password,
21
+ argon2_secret
22
+ )
23
+ hash_needs_update = outdated_work_factors?
24
+ end
25
+ else
26
+ # Devise models are included in a fixed order, see
27
+ # https://github.com/heartcombo/devise/blob/f6e73e5b5c8f519f4be29ac9069c6ed8a2343ce4/lib/devise/models.rb#L79.
28
+ # Since we don't specify where this model should be inserted when we call add_module,
29
+ # it will be inserted at the end, i.e. after DatabaseAuthenticatable (see
30
+ # https://github.com/heartcombo/devise/blob/f6e73e5b5c8f519f4be29ac9069c6ed8a2343ce4/lib/devise.rb#L393).
31
+ # So we can call DatabaseAuthenticable's valid_password? with super.
32
+ is_valid = super
33
+ hash_needs_update = true
34
+ end
35
+
36
+ update_hash(password) if is_valid && hash_needs_update
37
+
38
+ is_valid
39
+ end
40
+
41
+ protected
42
+
43
+ def password_digest(password)
44
+ hasher_options = self.class.argon2_options.except(:migrate_from_devise_argon2_v1)
45
+ hasher_options[:secret] ||= self.class.pepper
46
+ hasher = ::Argon2::Password.new(hasher_options)
47
+ hasher.create(password)
48
+ end
49
+
50
+ private
51
+
52
+ def update_hash(password)
53
+ attributes = { encrypted_password: password_digest(password) }
54
+ attributes[:password_salt] = nil if migrate_hash_from_devise_argon2_v1?
55
+
56
+ self.assign_attributes(attributes)
57
+ self.save if self.persisted?
58
+ end
59
+
60
+ def outdated_work_factors?
61
+ # Since version 2.3.0 the argon2 gem exposes the default work factors via constants, see
62
+ # https://github.com/technion/ruby-argon2/commit/d62ecf8b4ec6b8c1651fade5a5ebdc856e8aef42
63
+ default_t_cost = defined?(::Argon2::Password::DEFAULT_T_COST) ? ::Argon2::Password::DEFAULT_T_COST : 2
64
+ default_m_cost = defined?(::Argon2::Password::DEFAULT_M_COST) ? ::Argon2::Password::DEFAULT_M_COST : 16
65
+ default_p_cost = defined?(::Argon2::Password::DEFAULT_P_COST) ? ::Argon2::Password::DEFAULT_P_COST : 1
66
+
67
+ current_t_cost = self.class.argon2_options[:t_cost] || default_t_cost
68
+ current_m_cost = self.class.argon2_options[:m_cost] || default_m_cost
69
+ current_p_cost = self.class.argon2_options[:p_cost] || default_p_cost
70
+
71
+ hash_format = ::Argon2::HashFormat.new(encrypted_password)
72
+
73
+ hash_format.t_cost != current_t_cost ||
74
+ hash_format.m_cost != (1 << current_m_cost) ||
75
+ hash_format.p_cost != current_p_cost
76
+ end
77
+
78
+ def migrate_hash_from_devise_argon2_v1?
79
+ self.class.argon2_options[:migrate_from_devise_argon2_v1] &&
80
+ defined?(password_salt) &&
81
+ password_salt
82
+ end
83
+
84
+ module ClassMethods
85
+ Devise::Models.config(self, :argon2_options)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,5 @@
1
+ module Devise
2
+ module Argon2
3
+ ARGON2_VERSION = '2.0.0'
4
+ end
5
+ end
data/lib/devise-argon2.rb CHANGED
@@ -1,4 +1,9 @@
1
1
  require 'devise'
2
- require 'devise-encryptable'
3
- require "devise/encryptable/encryptors/argon2/version"
4
- require "devise/encryptable/encryptors/argon2"
2
+ require 'devise-argon2/version'
3
+
4
+ module Devise
5
+ add_module(:argon2, :model => 'devise-argon2/model')
6
+
7
+ mattr_accessor :argon2_options
8
+ @@argon2_options = {}
9
+ end
@@ -1,50 +1,247 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
+ require 'bcrypt'
3
4
 
4
- describe Devise::Encryptable::Encryptors::Argon2 do
5
- let(:argon2) { Devise::Encryptable::Encryptors::Argon2 }
6
- let(:password) { 'Tr0ub4dor&3' }
7
- let(:stretches) { 10 }
5
+ describe Devise::Models::Argon2 do
6
+ CORRECT_PASSWORD = 'Tr0ub4dor&3'
7
+ INCORRECT_PASSWORD = 'wrong'
8
+ DEFAULT_M_COST = 3
9
+ DEFAULT_T_COST = 1
10
+ DEFAULT_P_COST = 1
8
11
 
9
- describe "used with salt + pepper" do
10
- let(:salt) { "You say you love me like salt! The simplest spice in my kingdom!" }
11
- let(:pepper) { "I don't really want to stop the show But I thought that you might like to know That the singer's going to sing a song And he wants you all to sing along" }
12
+ let(:user) { User.new(password: CORRECT_PASSWORD) }
12
13
 
13
- describe ".compare" do
14
- let(:encrypted) { Argon2::Password.create("#{password}#{salt}#{pepper}").to_s }
14
+ before do
15
+ Devise.pepper = nil
16
+ Devise.argon2_options = {
17
+ m_cost: DEFAULT_M_COST,
18
+ t_cost: DEFAULT_T_COST,
19
+ p_cost: DEFAULT_P_COST
20
+ }
21
+ User.destroy_all
22
+ end
23
+
24
+ def work_factors(hash)
25
+ hash_format = Argon2::HashFormat.new(hash)
26
+ {
27
+ m_cost: hash_format.m_cost,
28
+ t_cost: hash_format.t_cost,
29
+ p_cost: hash_format.p_cost
30
+ }
31
+ end
15
32
 
16
- it "is true when the encrypted password contains the argon2id format" do
17
- expect(encrypted).to match /argon2id/
18
- end
33
+ describe 'valid_password?' do
34
+ shared_examples 'a password is validated if and only if it is correct' do
35
+ it 'validates the correct password' do
36
+ expect(user.valid_password?(CORRECT_PASSWORD)).to be true
37
+ end
19
38
 
20
- it "is true when comparing an encrypted password against given plaintext" do
21
- expect(argon2.compare(encrypted, password, stretches, salt, pepper)).to be true
39
+ it 'does not validate an incorrect password' do
40
+ expect(user.valid_password?(INCORRECT_PASSWORD)).to be false
22
41
  end
42
+ end
43
+
44
+ context 'no pepper' do
45
+ include_examples 'a password is validated if and only if it is correct'
46
+ end
47
+
48
+ context 'Devise.pepper is set' do
49
+ before do
50
+ Devise.pepper = 'pepper'
51
+ end
52
+
53
+ include_examples 'a password is validated if and only if it is correct'
54
+ end
55
+
56
+ context 'argon2_options[:secret] is set' do
57
+ before do
58
+ Devise.argon2_options[:secret] = 'pepper'
59
+ end
60
+
61
+ include_examples 'a password is validated if and only if it is correct'
62
+ end
23
63
 
24
- it "is false when comparing with wrong password" do
25
- expect(argon2.compare(encrypted, 'hunter2', stretches, salt, pepper)).to be false
64
+ context 'encrypted_password is a BCrypt hash' do
65
+ before do
66
+ Devise.pepper = 'devise pepper'
67
+ Devise.argon2_options.merge!({ secret: 'argon2 secret' })
68
+
69
+ # Devise peppers by concatenating password and pepper:
70
+ # https://github.com/heartcombo/devise/blob/main/lib/devise/encryptor.rb
71
+ bcrypt_hash = BCrypt::Password.create("#{CORRECT_PASSWORD}#{Devise.pepper}", cost: 4)
72
+
73
+ user.encrypted_password = bcrypt_hash
26
74
  end
27
75
 
28
- it "is false when comparing with correct password but wrong salt" do
29
- expect(argon2.compare(encrypted, password, stretches, 'nacl', pepper)).to be false
76
+ include_examples 'a password is validated if and only if it is correct'
77
+
78
+ it 'updates hash if valid password is given' do
79
+ expect{ user.valid_password?(CORRECT_PASSWORD) }.to(change(user, :encrypted_password))
80
+ expect(
81
+ ::Argon2::Password.verify_password(
82
+ CORRECT_PASSWORD,
83
+ user.encrypted_password,
84
+ 'argon2 secret'
85
+ )
86
+ ).to be true
30
87
  end
31
88
 
32
- it "is false when comparing with correct password but wrong pepper" do
33
- expect(argon2.compare(encrypted, password, stretches, salt, 'beatles')).to be false
89
+ it 'does not update the hash if an invalid password is given' do
90
+ expect{ user.valid_password?(INCORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
34
91
  end
35
92
  end
36
93
 
37
- describe "without any salt or pepper" do
38
- let(:encrypted) { Argon2::Password.create(password).to_s }
39
- let(:salt) { nil }
40
- let(:pepper) { nil }
41
- let(:encrypted) { Argon2::Password.create(password).to_s }
94
+ context 'encrypted_password is hashed with version 1 of devise-argon2' do
95
+ let(:user) { OldUser.new(password: CORRECT_PASSWORD) }
96
+
97
+ before do
98
+ Devise.pepper = 'devise pepper'
99
+ Devise.argon2_options.merge!({
100
+ secret: 'argon2 secret',
101
+ migrate_from_devise_argon2_v1: true
102
+ })
42
103
 
43
- it "is still works" do
44
- expect(argon2.compare(encrypted, password, stretches, salt, pepper)).to be true
104
+ user.password_salt = 'devise-argon2 v1 salt'
105
+ user.encrypted_password = ::Argon2::Password.create(
106
+ "#{CORRECT_PASSWORD}#{user.password_salt}#{Devise.pepper}"
107
+ )
108
+ end
109
+
110
+ include_examples 'a password is validated if and only if it is correct'
111
+
112
+ it 'updates hash once if valid password is given' do
113
+ expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
114
+ change(user, :encrypted_password)
115
+ .and(change(user, :password_salt).to(nil))
116
+ )
117
+ expect(
118
+ ::Argon2::Password.verify_password(
119
+ CORRECT_PASSWORD,
120
+ user.encrypted_password,
121
+ 'argon2 secret'
122
+ )
123
+ ).to be true
124
+ expect{ user.valid_password?(CORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
125
+ end
126
+
127
+ it 'does not update the hash if an invalid password is given' do
128
+ expect{ user.valid_password?(INCORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
45
129
  end
46
130
  end
47
131
 
132
+ describe 'updating outdated work factors' do
133
+ it 'updates work factors if a valid password is given' do
134
+ user # build user
135
+
136
+ Devise.argon2_options.merge!({
137
+ m_cost: 4,
138
+ t_cost: 3,
139
+ p_cost: 2
140
+ })
141
+
142
+ expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
143
+ change{ work_factors(user.encrypted_password) }
144
+ .from({ m_cost: 1 << DEFAULT_M_COST, t_cost: DEFAULT_T_COST, p_cost: DEFAULT_P_COST})
145
+ .to({ m_cost: 1 << 4, t_cost: 3, p_cost: 2 })
146
+ )
147
+ end
148
+
149
+ it 'does not update work factors if an invalid password is given' do
150
+ user # build user
151
+
152
+ Devise.argon2_options.merge!({
153
+ m_cost: 4,
154
+ t_cost: 3,
155
+ p_cost: 2
156
+ })
157
+
158
+ expect{ user.valid_password?(INCORRECT_PASSWORD) }
159
+ .not_to change{ work_factors(user.encrypted_password) }
160
+ end
161
+
162
+ it 'updates work factors for a persisted user' do
163
+ user.save!
164
+
165
+ Devise.argon2_options.merge!({
166
+ m_cost: 4,
167
+ t_cost: 3,
168
+ p_cost: 2
169
+ })
170
+
171
+ expect{ user.valid_password?(CORRECT_PASSWORD) }.to(
172
+ change{ work_factors(user.encrypted_password) }
173
+ .from({ m_cost: 1 << DEFAULT_M_COST, t_cost: DEFAULT_T_COST, p_cost: DEFAULT_P_COST})
174
+ .to({ m_cost: 1 << 4, t_cost: 3, p_cost: 2 })
175
+ )
176
+ end
177
+ end
178
+
179
+ it 'ignores migrate_from_devise_argon2_v1 if password_salt is not present' do
180
+ Devise.argon2_options.merge!({ migrate_from_devise_argon2_v1: true })
181
+ expect{ user.valid_password?(CORRECT_PASSWORD) }.not_to(change(user, :encrypted_password))
182
+ end
48
183
  end
49
184
 
185
+ describe 'password_digest' do
186
+ context 'no pepper' do
187
+ it 'hashes the given password with Argon2' do
188
+ expect(
189
+ Argon2::Password.verify_password(CORRECT_PASSWORD, user.encrypted_password)
190
+ ).to be true
191
+ end
192
+ end
193
+
194
+ context 'Devise.pepper is set' do
195
+ before do
196
+ Devise.pepper = 'pepper'
197
+ end
198
+
199
+ it 'uses Devise.pepper as secret key for Argon2' do
200
+ expect(
201
+ Argon2::Password.verify_password(CORRECT_PASSWORD, user.encrypted_password, 'pepper')
202
+ ).to be true
203
+ end
204
+ end
205
+
206
+ context 'argon2_options[:secret] is set' do
207
+ before do
208
+ Devise.argon2_options[:secret] = 'pepper'
209
+ end
210
+
211
+ it 'uses argon2_options[:secret] as secret key for Argon2' do
212
+ expect(
213
+ Argon2::Password.verify_password(CORRECT_PASSWORD, user.encrypted_password, 'pepper')
214
+ ).to be true
215
+ end
216
+ end
217
+
218
+ context 'both Devise.pepper and argon2_options[:secret] are set' do
219
+ before do
220
+ Devise.pepper = 'devise pepper'
221
+ Devise.argon2_options[:secret] = 'argon2_options pepper'
222
+ end
223
+
224
+ it 'uses argon2_options[:secret] as secret key for Argon2' do
225
+ expect(
226
+ Argon2::Password.verify_password(
227
+ CORRECT_PASSWORD,
228
+ user.encrypted_password,
229
+ 'argon2_options pepper'
230
+ )
231
+ ).to be true
232
+ end
233
+ end
234
+
235
+ it 'uses work factors given in argon2_options' do
236
+ Devise.argon2_options.merge!({
237
+ m_cost: 4,
238
+ t_cost: 3,
239
+ p_cost: 2
240
+ })
241
+
242
+ expect(work_factors(user.encrypted_password)).to eq(
243
+ { m_cost: 1 << 4, t_cost: 3, p_cost: 2 }
244
+ )
245
+ end
246
+ end
50
247
  end
@@ -0,0 +1 @@
1
+ ActiveRecord::Base.logger = Logger.new(nil)
@@ -0,0 +1,5 @@
1
+ require 'mongoid/version'
2
+
3
+ Mongoid.configure do |config|
4
+ config.load!('spec/rails_app/config/mongoid.yml')
5
+ end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative "config/application"
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,3 @@
1
+ class OldUser < ActiveRecord::Base
2
+ devise :database_authenticatable, :argon2
3
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ devise :database_authenticatable, :argon2
3
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationController < ActionController::Base
2
+
3
+ end
@@ -0,0 +1,12 @@
1
+ class OldUser
2
+ include Mongoid::Document
3
+
4
+ devise :database_authenticatable, :argon2
5
+
6
+ field :email, type: String, default: ""
7
+ field :encrypted_password, type: String, default: ""
8
+
9
+ field :password_salt, type: String, default: ""
10
+
11
+ include Mongoid::Timestamps
12
+ end
@@ -0,0 +1,10 @@
1
+ class User
2
+ include Mongoid::Document
3
+
4
+ devise :database_authenticatable, :argon2
5
+
6
+ field :email, type: String, default: ""
7
+ field :encrypted_password, type: String, default: ""
8
+
9
+ include Mongoid::Timestamps
10
+ end
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../Gemfile", __dir__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_requirement
64
+ @bundler_requirement ||=
65
+ env_var_version ||
66
+ cli_arg_version ||
67
+ bundler_requirement_for(lockfile_version)
68
+ end
69
+
70
+ def bundler_requirement_for(version)
71
+ return "#{Gem::Requirement.default}.a" unless version
72
+
73
+ bundler_gem_version = Gem::Version.new(version)
74
+
75
+ bundler_gem_version.approximate_recommendation
76
+ end
77
+
78
+ def load_bundler!
79
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
80
+
81
+ activate_bundler
82
+ end
83
+
84
+ def activate_bundler
85
+ gem_error = activation_error_handling do
86
+ gem "bundler", bundler_requirement
87
+ end
88
+ return if gem_error.nil?
89
+ require_error = activation_error_handling do
90
+ require "bundler/version"
91
+ end
92
+ return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
93
+ warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
94
+ exit 42
95
+ end
96
+
97
+ def activation_error_handling
98
+ yield
99
+ nil
100
+ rescue StandardError, LoadError => e
101
+ e
102
+ end
103
+ end
104
+
105
+ m.load_bundler!
106
+
107
+ if m.invoked_as_script?
108
+ load Gem.bin_path("bundler", "bundle")
109
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path("../config/application", __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../config/boot"
3
+ require "rake"
4
+ Rake.application.run
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ require "fileutils"
3
+
4
+ # path to your application root.
5
+ APP_ROOT = File.expand_path("..", __dir__)
6
+
7
+ def system!(*args)
8
+ system(*args) || abort("\n== Command #{args} failed ==")
9
+ end
10
+
11
+ FileUtils.chdir APP_ROOT do
12
+ # This script is a way to set up or update your development environment automatically.
13
+ # This script is idempotent, so that you can run it at any time and get an expectable outcome.
14
+ # Add necessary setup steps to this file.
15
+
16
+ puts "== Installing dependencies =="
17
+ system! "gem install bundler --conservative"
18
+ system("bundle check") || system!("bundle install")
19
+
20
+ # puts "\n== Copying sample files =="
21
+ # unless File.exist?("config/database.yml")
22
+ # FileUtils.cp "config/database.yml.sample", "config/database.yml"
23
+ # end
24
+
25
+ puts "\n== Preparing database =="
26
+ system! "bin/rails db:prepare"
27
+
28
+ puts "\n== Removing old logs and tempfiles =="
29
+ system! "bin/rails log:clear tmp:clear"
30
+
31
+ puts "\n== Restarting application server =="
32
+ system! "bin/rails restart"
33
+ end
@@ -0,0 +1,24 @@
1
+ ORM = (ENV['ORM'] || 'active_record')
2
+
3
+ require "rails"
4
+
5
+ Bundler.require :default, ORM
6
+
7
+ require "action_controller/railtie"
8
+
9
+ require "#{ORM}/railtie"
10
+ require "action_mailer/railtie"
11
+ require 'devise-argon2'
12
+
13
+ # Require the gems listed in Gemfile, including any gems
14
+ # you've limited to :test, :development, or :production.
15
+ Bundler.require(*Rails.groups)
16
+
17
+ module DummyRailsApp
18
+ class Application < Rails::Application
19
+ config.load_defaults Rails.version.match(/^\d.\d/)[0]
20
+ config.eager_load = false
21
+ config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers mailers views).include?($1) }
22
+ config.autoload_paths += ["#{config.root}/app/#{ORM}"]
23
+ end
24
+ end
@@ -0,0 +1,5 @@
1
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile", __dir__)
2
+
3
+ require "bundler/setup" # Set up gems listed in the Gemfile.
4
+
5
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -0,0 +1,14 @@
1
+ # SQLite. Versions 3.8.0 and up are supported.
2
+ # gem install sqlite3
3
+ #
4
+ # Ensure the SQLite 3 gem is defined in your Gemfile
5
+ # gem "sqlite3"
6
+ #
7
+ default: &default
8
+ adapter: sqlite3
9
+ pool: 5
10
+ timeout: 5000
11
+
12
+ test:
13
+ <<: *default
14
+ database: db/test.sqlite3
@@ -0,0 +1,7 @@
1
+ ENV['RAILS_ENV'] = 'test'
2
+
3
+ # Load the Rails application.
4
+ require_relative "application"
5
+
6
+ # Initialize the Rails application.
7
+ Rails.application.initialize!
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ Devise.setup do |config|
4
+ require "devise/orm/#{ENV['ORM'] || 'active_record'}"
5
+ config.stretches = 1
6
+ end
@@ -0,0 +1,10 @@
1
+ test:
2
+ clients:
3
+ default:
4
+ database: dummy_rails_app_test
5
+ hosts:
6
+ - localhost:27017
7
+ options:
8
+ read:
9
+ mode: :primary
10
+ max_pool_size: 1
@@ -0,0 +1,6 @@
1
+ # This file is used by Rack-based servers to start the application.
2
+
3
+ require_relative "config/environment"
4
+
5
+ run Rails.application
6
+ Rails.application.load_server
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DeviseCreateUsers < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :users do |t|
6
+ ## Database authenticatable
7
+ t.string :email, null: false, default: ""
8
+ t.string :encrypted_password, null: false, default: ""
9
+
10
+ t.timestamps null: false
11
+ end
12
+
13
+ add_index :users, :email, unique: true
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DeviseCreateOldUsers < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table :old_users do |t|
6
+ ## Database authenticatable
7
+ t.string :email, null: false, default: ""
8
+ t.string :encrypted_password, null: false, default: ""
9
+
10
+ t.string :password_salt
11
+
12
+ t.timestamps null: false
13
+ end
14
+
15
+ add_index :old_users, :email, unique: true
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # This file is the source Rails uses to define your schema when running `bin/rails
6
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7
+ # be faster and is potentially less error prone than running all of your
8
+ # migrations from scratch. Old migrations may fail to apply correctly if those
9
+ # migrations use external dependencies or application code.
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
12
+
13
+ ActiveRecord::Schema.define(version: 2023_10_04_084147) do
14
+ create_table "old_users", force: :cascade do |t|
15
+ t.string "email", default: "", null: false
16
+ t.string "encrypted_password", default: "", null: false
17
+ t.string "password_salt"
18
+ t.datetime "created_at", null: false
19
+ t.datetime "updated_at", null: false
20
+ t.index ["email"], name: "index_old_users_on_email", unique: true
21
+ end
22
+
23
+ create_table "users", force: :cascade do |t|
24
+ t.string "email", default: "", null: false
25
+ t.string "encrypted_password", default: "", null: false
26
+ t.datetime "created_at", null: false
27
+ t.datetime "updated_at", null: false
28
+ t.index ["email"], name: "index_users_on_email", unique: true
29
+ end
30
+
31
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,13 @@
1
1
  require 'rubygems'
2
2
  require 'simplecov'
3
3
  SimpleCov.start
4
- require 'pry'
5
4
  require 'bundler/setup'
6
- require 'devise-argon2'
5
+
6
+ require 'rails_app/config/environment'
7
+ ORM = (ENV['ORM'] || 'active_record')
8
+ require "orm/#{ORM}"
9
+
10
+
7
11
 
8
12
  RSpec.configure do |config|
9
- end
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise-argon2
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tamas Erdos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-11-30 00:00:00.000000000 Z
11
+ date: 2023-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: devise
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 2.1.0
27
- - !ruby/object:Gem::Dependency
28
- name: devise-encryptable
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 0.2.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 0.2.0
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: argon2
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,30 +38,55 @@ dependencies:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
40
  version: '2.0'
55
- description: A devise-encryptable password encryptor that uses Argon2
41
+ description: Enables Devise to hash passwords with Argon2id
56
42
  email:
57
43
  - tamas at tamaserdos com
58
44
  executables: []
59
45
  extensions: []
60
46
  extra_rdoc_files: []
61
47
  files:
48
+ - ".github/workflows/test.yml"
62
49
  - ".gitignore"
63
50
  - ".rspec"
64
- - ".travis.yml"
51
+ - CHANGELOG.md
65
52
  - Gemfile
66
53
  - LICENSE.txt
67
54
  - README.md
68
55
  - Rakefile
69
56
  - devise-argon2.gemspec
70
57
  - lib/devise-argon2.rb
71
- - lib/devise/encryptable/encryptors/argon2.rb
72
- - lib/devise/encryptable/encryptors/argon2/version.rb
58
+ - lib/devise-argon2/model.rb
59
+ - lib/devise-argon2/version.rb
73
60
  - spec/devise-argon2_spec.rb
61
+ - spec/orm/active_record.rb
62
+ - spec/orm/mongoid.rb
63
+ - spec/rails_app/Rakefile
64
+ - spec/rails_app/app/active_record/old_user.rb
65
+ - spec/rails_app/app/active_record/user.rb
66
+ - spec/rails_app/app/controllers/application_controller.rb
67
+ - spec/rails_app/app/mongoid/old_user.rb
68
+ - spec/rails_app/app/mongoid/user.rb
69
+ - spec/rails_app/bin/bundle
70
+ - spec/rails_app/bin/rails
71
+ - spec/rails_app/bin/rake
72
+ - spec/rails_app/bin/setup
73
+ - spec/rails_app/config.ru
74
+ - spec/rails_app/config/application.rb
75
+ - spec/rails_app/config/boot.rb
76
+ - spec/rails_app/config/database.yml
77
+ - spec/rails_app/config/environment.rb
78
+ - spec/rails_app/config/initializers/devise.rb
79
+ - spec/rails_app/config/mongoid.yml
80
+ - spec/rails_app/db/migrate/20230617201921_devise_create_users.rb
81
+ - spec/rails_app/db/migrate/20231004084147_devise_create_old_users.rb
82
+ - spec/rails_app/db/schema.rb
74
83
  - spec/spec_helper.rb
75
84
  homepage: https://github.com/erdostom/devise-argon2
76
- licenses: []
85
+ licenses:
86
+ - MIT
77
87
  metadata: {}
78
- post_install_message:
88
+ post_install_message: Version 2 of devise-argon2 introduces breaking changes, please
89
+ see README.md for details.
79
90
  rdoc_options: []
80
91
  require_paths:
81
92
  - lib
@@ -90,11 +101,32 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
101
  - !ruby/object:Gem::Version
91
102
  version: '0'
92
103
  requirements: []
93
- rubyforge_project:
94
- rubygems_version: 2.7.8
104
+ rubygems_version: 3.3.3
95
105
  signing_key:
96
106
  specification_version: 4
97
- summary: A devise-encryptable password encryptor that uses Argon2
107
+ summary: Enables Devise to hash passwords with Argon2id
98
108
  test_files:
99
109
  - spec/devise-argon2_spec.rb
110
+ - spec/orm/active_record.rb
111
+ - spec/orm/mongoid.rb
112
+ - spec/rails_app/Rakefile
113
+ - spec/rails_app/app/active_record/old_user.rb
114
+ - spec/rails_app/app/active_record/user.rb
115
+ - spec/rails_app/app/controllers/application_controller.rb
116
+ - spec/rails_app/app/mongoid/old_user.rb
117
+ - spec/rails_app/app/mongoid/user.rb
118
+ - spec/rails_app/bin/bundle
119
+ - spec/rails_app/bin/rails
120
+ - spec/rails_app/bin/rake
121
+ - spec/rails_app/bin/setup
122
+ - spec/rails_app/config.ru
123
+ - spec/rails_app/config/application.rb
124
+ - spec/rails_app/config/boot.rb
125
+ - spec/rails_app/config/database.yml
126
+ - spec/rails_app/config/environment.rb
127
+ - spec/rails_app/config/initializers/devise.rb
128
+ - spec/rails_app/config/mongoid.yml
129
+ - spec/rails_app/db/migrate/20230617201921_devise_create_users.rb
130
+ - spec/rails_app/db/migrate/20231004084147_devise_create_old_users.rb
131
+ - spec/rails_app/db/schema.rb
100
132
  - spec/spec_helper.rb
data/.travis.yml DELETED
@@ -1,13 +0,0 @@
1
- script:
2
- - bundle
3
- - bundle exec rspec
4
- rvm:
5
- - 1.9.3
6
- - 2.2.3
7
- - ruby-head
8
- - rbx-18mode
9
- - rbx-19mode
10
- notifications:
11
- email:
12
- on_success: always
13
- on_failure: always
@@ -1,7 +0,0 @@
1
- module Devise
2
- module Encryptable
3
- module Encryptors
4
- ARGON2_VERSION = '1.1.0'
5
- end
6
- end
7
- end
@@ -1,17 +0,0 @@
1
- require 'argon2'
2
-
3
- module Devise
4
- module Encryptable
5
- module Encryptors
6
- class Argon2 < Base
7
- def self.digest(password, stretches, salt, pepper)
8
- ::Argon2::Password.create("#{password}#{salt}#{pepper}")
9
- end
10
-
11
- def self.compare(encrypted_password, password, stretches, salt, pepper)
12
- ::Argon2::Password.verify_password("#{password}#{salt}#{pepper}", encrypted_password)
13
- end
14
- end
15
- end
16
- end
17
- end