veri 0.1.0 → 0.2.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: ac32f0c6d36a07d566aec8905648f0e27811876d52929ab1753f3109af5648b7
4
- data.tar.gz: eaaec22fa0215df1896cf3baadf7b8ce5e7ff4ebcb61094443a020e54c63023c
3
+ metadata.gz: '0782d4bd585ca9ca0aaa91cb51fe4b240d9e97ccf829c69890bc2079b38dda18'
4
+ data.tar.gz: 56cd6f6147a7b23ea2a5cc0b12dd9d573fcae55dcbf49462f93a4db59d5ef724
5
5
  SHA512:
6
- metadata.gz: d75c20d2484660914c53ead2394f376bc915c45833bfe8b643b7e4964dc104c94d64747ce8be312bae24930e27216296060f1971a8356c9ec4c347372106c080
7
- data.tar.gz: 4166c688264ac0cfa34866487a2ac572deb70972656c59fd724608841ea50d8b5436e64d70c7a45990302e4a8111cf0e47b103aff78075f0d792d05953c5a2b7
6
+ metadata.gz: 29763c6104a41dd4987ff30d4c75089d8390d5c36afb7d9f9f297fe627380f0b674d46d4c52aedb27865776d6915bd38ca4acacc2adda7894fe66d9e457bfeec
7
+ data.tar.gz: '038ae16e36b31d87b4b83f7d51f51bb4c9d9318e6c161c9249f6eeff0a6a970343a2b1acbcb256edb4622bd03e01d1b6dda5c90c441274ef3b841f792dbc8ba6'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## v0.2.0
2
+
3
+ ### Breaking
4
+
5
+ - Added `password_updated_at` timestamp tracking for authenticatable models
6
+ - Added shapeshifter functionality for impersonation/session switching
7
+
8
+ ### Features
9
+
10
+ - Added `Session#identity` method
11
+ - Added `current_session` helper method for views
12
+
1
13
  ## v0.1.0
2
14
 
3
15
  - Initial release
data/README.md CHANGED
@@ -10,9 +10,8 @@ Veri is a cookie-based authentication library for Ruby on Rails that provides es
10
10
  - Cookie-based authentication with database-stored sessions
11
11
  - Supports multiple password hashing algorithms (argon2, bcrypt, scrypt)
12
12
  - Granular session management and control
13
- - Flexible authentication callbacks
14
- - No pre-defined business logic, no views, controllers, or mailers — just the essential methods
15
13
  - Built-in return path handling
14
+ - User impersonation feature
16
15
 
17
16
  > ⚠️ **Development Notice**<br>
18
17
  > Veri is functional but in early development. Breaking changes may occur in minor releases until v1.0!
@@ -99,11 +98,11 @@ Include the authentication module and configure protection:
99
98
  class ApplicationController < ActionController::Base
100
99
  include Veri::Authentication
101
100
 
102
- with_authentication # Require authentication by default
101
+ with_authentication # Require authentication by default
103
102
  end
104
103
 
105
104
  class PicturesController < ApplicationController
106
- skip_authentication only: [:index, :show] # Allow public access to index and show actions
105
+ skip_authentication only: [:index, :show] # Allow public access to index and show actions
107
106
  end
108
107
  ```
109
108
 
@@ -136,16 +135,49 @@ end
136
135
 
137
136
  Available methods:
138
137
 
139
- - `current_user` - returns the authenticated user or `nil`
140
- - `logged_in?` - returns `true` if user is authenticated
141
- - `log_in(user)` - authenticates the user and creates a session
142
- - `log_out` - terminates the current session
143
- - `return_path` - returns the path the user was trying to access before authentication
144
- - `current_session` - returns the current authentication session
138
+ - `current_user` - Returns authenticated user or `nil`
139
+ - `logged_in?` - Returns `true` if user is authenticated
140
+ - `log_in(user)` - Authenticates user and creates session
141
+ - `log_out` - Terminates current session
142
+ - `return_path` - Returns path user was accessing before authentication
143
+ - `current_session` - Returns current authentication session
145
144
 
146
- ### Authentication Callbacks
145
+ ### User Impersonation (Shapeshifting)
147
146
 
148
- Override these private methods to customize authentication behavior:
147
+ Veri provides user impersonation functionality that allows, for example, administrators to temporarily assume another user's identity:
148
+
149
+ ```rb
150
+ module Admin
151
+ class ImpersonationController < ApplicationController
152
+ def create
153
+ user = User.find(params[:user_id])
154
+ current_session.shapeshift(user)
155
+ redirect_to root_path, notice: "Now viewing as #{user.name}"
156
+ end
157
+
158
+ def destroy
159
+ original_user = current_session.true_identity
160
+ current_session.revert_to_true_identity
161
+ redirect_to admin_dashboard_path, notice: "Returned to #{original_user.name}"
162
+ end
163
+ end
164
+ end
165
+ ```
166
+
167
+ Available session methods:
168
+
169
+ - `shapeshift(user)` - Assume another user's identity (maintains original identity)
170
+ - `revert_to_true_identity` - Return to original identity
171
+ - `shapeshifted?` - Returns true if currently shapeshifted
172
+ - `true_identity` - Returns original user when shapeshifted, otherwise current user
173
+
174
+ Controller helper:
175
+
176
+ - `shapeshifter?` - Returns true if the current session is shapeshifted
177
+
178
+ ### When unauthenticated
179
+
180
+ Override this private method to customize authentication behavior:
149
181
 
150
182
  ```rb
151
183
  class ApplicationController < ActionController::Base
@@ -157,18 +189,6 @@ class ApplicationController < ActionController::Base
157
189
 
158
190
  private
159
191
 
160
- # Called after successful login
161
- def after_login(user)
162
- Rails.logger.info "User #{user.id} logged in"
163
- # Custom redirect logic, analytics, etc.
164
- end
165
-
166
- # Called after logout
167
- def after_logout
168
- Rails.logger.info "User logged out"
169
- # Cleanup, analytics, etc.
170
- end
171
-
172
192
  # Customize unauthenticated user handling
173
193
  def when_unauthenticated
174
194
  # By default redirects back with a fallback to the root path if the request format is HTML,
@@ -180,7 +200,7 @@ end
180
200
 
181
201
  ## Authentication Sessions
182
202
 
183
- Veri stores authentication sessions in the database, enabling powerful session management:
203
+ Veri stores authentication sessions in the database, providing session management capabilities:
184
204
 
185
205
  ### Session Access
186
206
 
@@ -195,13 +215,15 @@ current_session
195
215
  ### Session Information
196
216
 
197
217
  ```rb
218
+ session.identity
219
+ # => authenticated user
198
220
  session.info
199
221
  # => {
200
222
  # device: "Desktop",
201
223
  # os: "macOS",
202
224
  # browser: "Chrome",
203
225
  # ip_address: "1.2.3.4",
204
- # last_activity: "2023-10-01 12:00:00"
226
+ # last_seen_at: "2023-10-01 12:00:00"
205
227
  # }
206
228
  ```
207
229
 
@@ -234,6 +256,10 @@ Access authentication state in your views:
234
256
  ```erb
235
257
  <% if logged_in? %>
236
258
  <p>Welcome, <%= current_user.name %>!</p>
259
+ <% if shapeshifter? %>
260
+ <p><em>Currently viewing as <%= current_user.name %> (Original: <%= current_session.true_identity.name %>)</em></p>
261
+ <%= link_to "Return to Original Identity", revert_path, method: :patch %>
262
+ <% end %>
237
263
  <%= link_to "Logout", logout_path, method: :delete %>
238
264
  <% else %>
239
265
  <%= link_to "Login", login_path %>
@@ -1,11 +1,14 @@
1
1
  class AddVeriAuthentication < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version.to_s %>]
2
2
  def change
3
3
  add_column <%= table_name.to_sym.inspect %>, :hashed_password, :text
4
+ add_column <%= table_name.to_sym.inspect %>, :password_updated_at, :datetime
4
5
 
5
6
  create_table :veri_sessions<%= ", id: :uuid" if options[:uuid] %> do |t|
6
7
  t.string :hashed_token, null: false, index: { unique: true }
7
8
  t.datetime :expires_at, null: false
8
9
  t.belongs_to :authenticatable, null: false, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }, index: true<%= ", type: :uuid" if options[:uuid] %>
10
+ t.belongs_to :original_authenticatable, foreign_key: { to_table: <%= table_name.to_sym.inspect %> }, index: true<%= ", type: :uuid" if options[:uuid] %>
11
+ t.datetime :shapeshifted_at
9
12
  t.datetime :last_seen_at, null: false
10
13
  t.string :ip_address
11
14
  t.string :user_agent
@@ -5,7 +5,7 @@ module Veri
5
5
  included do
6
6
  include ActionController::Cookies unless self < ActionController::Cookies
7
7
 
8
- helper_method(:current_user, :logged_in?) if respond_to?(:helper_method)
8
+ helper_method(:current_user, :logged_in?, :shapeshifter?, :current_session) if respond_to?(:helper_method)
9
9
  end
10
10
 
11
11
  class_methods do
@@ -23,7 +23,7 @@ module Veri
23
23
  end
24
24
 
25
25
  def current_user
26
- @current_user ||= current_session&.authenticatable
26
+ @current_user ||= current_session&.identity
27
27
  end
28
28
 
29
29
  def current_session
@@ -34,13 +34,11 @@ module Veri
34
34
  def log_in(authenticatable)
35
35
  token = Veri::Session.establish(Veri::Inputs.process(authenticatable, as: :authenticatable), request)
36
36
  cookies.encrypted.permanent[:veri_token] = { value: token, httponly: true }
37
- after_login
38
37
  end
39
38
 
40
39
  def log_out
41
40
  current_session&.terminate
42
41
  cookies.delete(:veri_token)
43
- after_logout
44
42
  end
45
43
 
46
44
  def logged_in?
@@ -51,6 +49,10 @@ module Veri
51
49
  cookies.signed[:veri_return_path]
52
50
  end
53
51
 
52
+ def shapeshifter?
53
+ !!current_session&.shapeshifted?
54
+ end
55
+
54
56
  private
55
57
 
56
58
  def with_authentication
@@ -66,8 +68,5 @@ module Veri
66
68
  def when_unauthenticated
67
69
  request.format.html? ? redirect_back(fallback_location: root_path) : head(:unauthorized)
68
70
  end
69
-
70
- def after_login = nil
71
- def after_logout = nil
72
71
  end
73
72
  end
@@ -11,7 +11,10 @@ module Veri
11
11
  end
12
12
 
13
13
  def update_password(password)
14
- update!(hashed_password: hasher.create(Veri::Inputs.process(password, as: :string)))
14
+ update!(
15
+ hashed_password: hasher.create(Veri::Inputs.process(password, as: :string)),
16
+ password_updated_at: Time.current
17
+ )
15
18
  end
16
19
 
17
20
  def verify_password(password)
@@ -4,11 +4,12 @@ module Veri
4
4
  class Session < ActiveRecord::Base
5
5
  self.table_name = "veri_sessions"
6
6
 
7
- belongs_to :authenticatable, class_name: Veri::Configuration.user_model_name # rubocop:disable Rails/ReflectionClassName
7
+ # rubocop:disable Rails/ReflectionClassName
8
+ belongs_to :authenticatable, class_name: Veri::Configuration.user_model_name
9
+ belongs_to :original_authenticatable, class_name: Veri::Configuration.user_model_name, optional: true
10
+ # rubocop:enable Rails/ReflectionClassName
8
11
 
9
- def active?
10
- !expired? && !inactive?
11
- end
12
+ def active? = !expired? && !inactive?
12
13
 
13
14
  def expired?
14
15
  expires_at < Time.current
@@ -46,6 +47,26 @@ module Veri
46
47
  }
47
48
  end
48
49
 
50
+ def identity = authenticatable
51
+ def shapeshifted? = original_authenticatable.present?
52
+ def true_identity = original_authenticatable || authenticatable
53
+
54
+ def shapeshift(user)
55
+ update!(
56
+ shapeshifted_at: Time.current,
57
+ original_authenticatable: authenticatable,
58
+ authenticatable: Veri::Inputs.process(user, as: :authenticatable)
59
+ )
60
+ end
61
+
62
+ def revert_to_true_identity
63
+ update!(
64
+ shapeshifted_at: nil,
65
+ authenticatable: original_authenticatable,
66
+ original_authenticatable: nil
67
+ )
68
+ end
69
+
49
70
  class << self
50
71
  def establish(authenticatable, request)
51
72
  token = SecureRandom.hex(32)
data/lib/veri/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Veri
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  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.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - enjaku4