veri 0.4.0 → 1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 85a6c779bd69de4d11430630c142f8e5e12e3574d7828f740abc19f0e51d291f
4
- data.tar.gz: 0def50b534c6d728230ec7543fe6a007a518f9abe47e9c0d93aac45e7eb2f59f
3
+ metadata.gz: c4434399cb0f0e3081ff2ccb8e72df12623e74f6f2cd43f318d50ae483845be6
4
+ data.tar.gz: 194dec0866793d8f2bc906d2830f8c9a4fb37e7d8a5c7f5c58bec7d0631abc51
5
5
  SHA512:
6
- metadata.gz: 714985726d7e5d04f55dbb1b94a73110a64ed1cb2853f565ddefda540cb13393969a1c4c3ec91e7de310822224dd844031d7d6b0cf57bd3b537c36da5bb6d55b
7
- data.tar.gz: 7f2070d1f1da0260a8061b8abcff5a625245e4388f593d14a6edbdc8c8b496a3b55b5525bfda7a9abaae6bd91ffb218cb0d707d888f14114981c536d99a85e90
6
+ metadata.gz: 2e5dbe8a582d077ef157f8c16d3ec5c21ac24b501e323ed4bf11f577fe436900dffdc1a40814011c78f969962c97ca0b931cd5684253578ecb4804b994016dca
7
+ data.tar.gz: ba78fb8d71fd4dffdb527add9759f56d84ca9772535897d356f4a4a9f1302f149d3533355e8a86a518b09f179c638313dcdf2b9932c82fd7e8a427457a1b3111
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## v1.0.0
2
+
3
+ ### Breaking
4
+
5
+ - Dropped support for Rails 7.1
6
+
7
+ ### Features
8
+
9
+ - Added support for pbkdf2 password hashing algorithm
10
+
11
+ ### Bugs
12
+
13
+ - Fixed error raised on Rails console commands when the database was not yet set up
14
+
1
15
  ## v0.4.0
2
16
 
3
17
  ### Breaking
data/README.md CHANGED
@@ -1,23 +1,20 @@
1
1
  # Veri: Minimal Authentication Framework for Rails
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/veri.svg)](http://badge.fury.io/rb/veri)
4
- [![Github Actions badge](https://github.com/brownboxdev/veri/actions/workflows/ci.yml/badge.svg)](https://github.com/brownboxdev/veri/actions/workflows/ci.yml)
4
+ [![Github Actions badge](https://github.com/enjaku4/veri/actions/workflows/ci.yml/badge.svg)](https://github.com/enjaku4/veri/actions/workflows/ci.yml)
5
5
 
6
6
  Veri is a cookie-based authentication library for Ruby on Rails that provides essential authentication building blocks without imposing business logic. Unlike full-featured solutions, Veri gives you complete control over your authentication flow while handling the complex underlying mechanics of secure password storage and session management.
7
7
 
8
8
  **Key Features:**
9
9
 
10
10
  - Cookie-based authentication with database-stored sessions
11
- - Multiple password hashing algorithms (argon2, bcrypt, scrypt)
11
+ - Multiple password hashing algorithms (argon2, bcrypt, pbkdf2, scrypt)
12
12
  - Granular session management and control
13
13
  - Return path handling
14
14
  - User impersonation feature
15
15
  - Account lockout functionality
16
16
  - Multi-tenancy support
17
17
 
18
- > ⚠️ **Development Notice**<br>
19
- > Veri is functional but in early development. Breaking changes may occur in minor releases until v1.0!
20
-
21
18
  ## Table of Contents
22
19
 
23
20
  **Gem Usage:**
@@ -73,7 +70,7 @@ If customization is required, configure Veri in an initializer:
73
70
  ```rb
74
71
  # These are the default values; you can change them as needed
75
72
  Veri.configure do |config|
76
- config.hashing_algorithm = :argon2 # Password hashing algorithm (:argon2, :bcrypt, or :scrypt)
73
+ config.hashing_algorithm = :argon2 # Password hashing algorithm (:argon2, :bcrypt, :pbkdf2, or :scrypt)
77
74
  config.inactive_session_lifetime = nil # Session inactivity timeout (nil means sessions never expire due to inactivity)
78
75
  config.total_session_lifetime = 14.days # Maximum session duration regardless of activity
79
76
  config.user_model_name = "User" # Your user model name
@@ -115,6 +112,22 @@ end
115
112
  This is a simplified example of how to use Veri's authentication methods:
116
113
 
117
114
  ```rb
115
+ class RegistrationsController < ApplicationController
116
+ skip_authentication
117
+
118
+ def create
119
+ user = User.new(user_params)
120
+
121
+ if user.valid?
122
+ user.update_password(user_params[:password])
123
+ log_in(user)
124
+ redirect_to dashboard_path
125
+ else
126
+ render :new, status: :unprocessable_content
127
+ end
128
+ end
129
+ end
130
+
118
131
  class SessionsController < ApplicationController
119
132
  skip_authentication except: [:destroy]
120
133
 
@@ -126,7 +139,7 @@ class SessionsController < ApplicationController
126
139
  redirect_to return_path || dashboard_path
127
140
  else
128
141
  flash.now[:alert] = "Invalid credentials"
129
- render :new, status: :unprocessable_entity
142
+ render :new, status: :unprocessable_content
130
143
  end
131
144
  end
132
145
 
@@ -288,8 +301,14 @@ session.terminate
288
301
  # Terminate all sessions
289
302
  Veri::Session.terminate_all
290
303
 
291
- # Clean up expired/inactive sessions
304
+ # Terminate all sessions for a specific user
305
+ user.sessions.terminate_all
306
+
307
+ # Clean up expired/inactive sessions, and sessions with deleted tenant
292
308
  Veri::Session.prune
309
+
310
+ # Clean up expired/inactive sessions for a specific user
311
+ user.sessions.prune
293
312
  ```
294
313
 
295
314
  ## Account Lockout
@@ -426,13 +445,13 @@ end
426
445
  ## Getting Help and Contributing
427
446
 
428
447
  ### Getting Help
429
- Have a question or need assistance? Open a discussion in our [discussions section](https://github.com/brownboxdev/veri/discussions) for:
448
+ Have a question or need assistance? Open a discussion in our [discussions section](https://github.com/enjaku4/veri/discussions) for:
430
449
  - Usage questions
431
450
  - Implementation guidance
432
451
  - Feature suggestions
433
452
 
434
453
  ### Reporting Issues
435
- Found a bug? Please [create an issue](https://github.com/brownboxdev/veri/issues) with:
454
+ Found a bug? Please [create an issue](https://github.com/enjaku4/veri/issues) with:
436
455
  - A clear description of the problem
437
456
  - Steps to reproduce the issue
438
457
  - Your environment details (Rails version, Ruby version, etc.)
@@ -441,14 +460,14 @@ Found a bug? Please [create an issue](https://github.com/brownboxdev/veri/issues
441
460
  Ready to contribute? You can:
442
461
  - Fix bugs by submitting pull requests
443
462
  - Improve documentation
444
- - Add new features (please discuss first in our [discussions section](https://github.com/brownboxdev/veri/discussions))
463
+ - Add new features (please discuss first in our [discussions section](https://github.com/enjaku4/veri/discussions))
445
464
 
446
- Before contributing, please read the [contributing guidelines](https://github.com/brownboxdev/veri/blob/main/CONTRIBUTING.md)
465
+ Before contributing, please read the [contributing guidelines](https://github.com/enjaku4/veri/blob/main/CONTRIBUTING.md)
447
466
 
448
467
  ## License
449
468
 
450
- The gem is available as open source under the terms of the [MIT License](https://github.com/brownboxdev/veri/blob/main/LICENSE.txt).
469
+ The gem is available as open source under the terms of the [MIT License](https://github.com/enjaku4/veri/blob/main/LICENSE.txt).
451
470
 
452
471
  ## Code of Conduct
453
472
 
454
- Everyone interacting in the Veri project is expected to follow the [code of conduct](https://github.com/brownboxdev/veri/blob/main/CODE_OF_CONDUCT.md).
473
+ Everyone interacting in the Veri project is expected to follow the [code of conduct](https://github.com/enjaku4/veri/blob/main/CODE_OF_CONDUCT.md).
@@ -52,6 +52,7 @@ module Veri
52
52
  HASHERS = {
53
53
  argon2: Veri::Password::Argon2,
54
54
  bcrypt: Veri::Password::BCrypt,
55
+ pbkdf2: Veri::Password::Pbkdf2,
55
56
  scrypt: Veri::Password::SCrypt
56
57
  }.freeze
57
58
 
@@ -3,7 +3,7 @@ module Veri
3
3
  class HashingAlgorithm < Veri::Inputs::Base
4
4
  private
5
5
 
6
- def type = -> { self.class::Strict::Symbol.enum(:argon2, :bcrypt, :scrypt) }
6
+ def type = -> { self.class::Strict::Symbol.enum(:argon2, :bcrypt, :pbkdf2, :scrypt) }
7
7
  end
8
8
  end
9
9
  end
@@ -100,23 +100,15 @@ module Veri
100
100
  end
101
101
 
102
102
  def prune
103
- expired_scope = where(expires_at: ...Time.current)
103
+ expired.or(inactive).delete_all
104
104
 
105
- if Veri::Configuration.inactive_session_lifetime
106
- inactive_cutoff = Time.current - Veri::Configuration.inactive_session_lifetime
107
- expired_scope = expired_scope.or(where(last_seen_at: ...inactive_cutoff))
108
- end
109
-
110
- expired_scope.delete_all
111
-
112
- ids = where.not(tenant_id: nil).includes(:tenant).filter_map do |session|
113
- session.tenant
114
- nil
105
+ orphaned_tenant_sessions = where.not(tenant_id: nil).includes(:tenant).filter_map do |session|
106
+ !session.tenant
115
107
  rescue ActiveRecord::RecordNotFound
116
108
  session.id
117
109
  end
118
110
 
119
- where(id: ids).delete_all if ids.any?
111
+ where(id: orphaned_tenant_sessions).delete_all if orphaned_tenant_sessions.any?
120
112
  end
121
113
 
122
114
  alias terminate_all delete_all
@@ -0,0 +1,47 @@
1
+ require "openssl"
2
+ require "base64"
3
+ require "securerandom"
4
+
5
+ module Veri
6
+ module Password
7
+ module Pbkdf2
8
+ module_function
9
+
10
+ ITERATIONS = 210_000
11
+ SALT_BYTES = 64
12
+ HASH_BYTES = 64
13
+ DIGEST = "sha512"
14
+
15
+ def create(password)
16
+ salt = SecureRandom.random_bytes(SALT_BYTES)
17
+ hash = OpenSSL::KDF.pbkdf2_hmac(
18
+ password,
19
+ salt:,
20
+ iterations: ITERATIONS,
21
+ length: HASH_BYTES,
22
+ hash: DIGEST
23
+ )
24
+
25
+ "#{DIGEST}$#{ITERATIONS}$#{HASH_BYTES}$#{Base64.strict_encode64(salt)}$#{Base64.strict_encode64(hash)}"
26
+ end
27
+
28
+ def verify(password, hashed_password)
29
+ parts = hashed_password.split("$")
30
+ digest, iterations, hash_bytes, encoded_salt, encoded_hash = parts[0], parts[1], parts[2], parts[3], parts[4]
31
+
32
+ salt = Base64.strict_decode64(encoded_salt)
33
+ hash = Base64.strict_decode64(encoded_hash)
34
+
35
+ recalculated_hash = OpenSSL::KDF.pbkdf2_hmac(
36
+ password,
37
+ salt:,
38
+ iterations: iterations.to_i,
39
+ length: hash_bytes.to_i,
40
+ hash: digest
41
+ )
42
+
43
+ OpenSSL.fixed_length_secure_compare(recalculated_hash, hash)
44
+ end
45
+ end
46
+ end
47
+ end
data/lib/veri/railtie.rb CHANGED
@@ -2,9 +2,15 @@ require "rails/railtie"
2
2
 
3
3
  module Veri
4
4
  class Railtie < Rails::Railtie
5
+ def self.table_exists?
6
+ ActiveRecord::Base.connection.data_source_exists?("veri_sessions")
7
+ rescue ActiveRecord::NoDatabaseError, ActiveRecord::ConnectionNotEstablished
8
+ false
9
+ end
10
+
5
11
  initializer "veri.to_prepare" do |app|
6
12
  app.config.to_prepare do
7
- if ActiveRecord::Base.connection.data_source_exists?("veri_sessions")
13
+ if Veri::Railtie.table_exists?
8
14
  Veri::Session.where.not(tenant_id: nil).distinct.pluck(:tenant_type).each do |tenant_class|
9
15
  tenant_class.constantize
10
16
  rescue NameError => e
data/lib/veri/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Veri
2
- VERSION = "0.4.0".freeze
2
+ VERSION = "1.0.0".freeze
3
3
  end
data/lib/veri.rb CHANGED
@@ -5,6 +5,7 @@ require "active_support"
5
5
 
6
6
  require_relative "veri/password/argon2"
7
7
  require_relative "veri/password/bcrypt"
8
+ require_relative "veri/password/pbkdf2"
8
9
  require_relative "veri/password/scrypt"
9
10
 
10
11
  require_relative "veri/inputs/base"
data/veri.gemspec CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
4
4
  spec.name = "veri"
5
5
  spec.version = Veri::VERSION
6
6
  spec.authors = ["enjaku4"]
7
- spec.homepage = "https://github.com/brownboxdev/veri"
7
+ spec.homepage = "https://github.com/enjaku4/veri"
8
8
  spec.metadata["homepage_uri"] = spec.homepage
9
9
  spec.metadata["source_code_uri"] = spec.homepage
10
10
  spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_dependency "bcrypt", "~> 3.0"
24
24
  spec.add_dependency "dry-configurable", "~> 1.1"
25
25
  spec.add_dependency "dry-types", "~> 1.7"
26
- spec.add_dependency "rails", ">= 7.1", "< 8.1"
26
+ spec.add_dependency "rails", ">= 7.2", "< 8.1"
27
27
  spec.add_dependency "scrypt", "~> 3.0"
28
28
  spec.add_dependency "user_agent_parser", "~> 2.0"
29
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: veri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - enjaku4
@@ -71,7 +71,7 @@ dependencies:
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: '7.1'
74
+ version: '7.2'
75
75
  - - "<"
76
76
  - !ruby/object:Gem::Version
77
77
  version: '8.1'
@@ -81,7 +81,7 @@ dependencies:
81
81
  requirements:
82
82
  - - ">="
83
83
  - !ruby/object:Gem::Version
84
- version: '7.1'
84
+ version: '7.2'
85
85
  - - "<"
86
86
  - !ruby/object:Gem::Version
87
87
  version: '8.1'
@@ -137,17 +137,18 @@ files:
137
137
  - lib/veri/models/session.rb
138
138
  - lib/veri/password/argon2.rb
139
139
  - lib/veri/password/bcrypt.rb
140
+ - lib/veri/password/pbkdf2.rb
140
141
  - lib/veri/password/scrypt.rb
141
142
  - lib/veri/railtie.rb
142
143
  - lib/veri/version.rb
143
144
  - veri.gemspec
144
- homepage: https://github.com/brownboxdev/veri
145
+ homepage: https://github.com/enjaku4/veri
145
146
  licenses:
146
147
  - MIT
147
148
  metadata:
148
- homepage_uri: https://github.com/brownboxdev/veri
149
- source_code_uri: https://github.com/brownboxdev/veri
150
- changelog_uri: https://github.com/brownboxdev/veri/blob/main/CHANGELOG.md
149
+ homepage_uri: https://github.com/enjaku4/veri
150
+ source_code_uri: https://github.com/enjaku4/veri
151
+ changelog_uri: https://github.com/enjaku4/veri/blob/main/CHANGELOG.md
151
152
  rubygems_mfa_required: 'true'
152
153
  rdoc_options: []
153
154
  require_paths:
@@ -166,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
167
  - !ruby/object:Gem::Version
167
168
  version: '0'
168
169
  requirements: []
169
- rubygems_version: 3.6.7
170
+ rubygems_version: 3.7.1
170
171
  specification_version: 4
171
172
  summary: Minimal cookie-based authentication library for Ruby on Rails
172
173
  test_files: []