authie 4.0.0.rc9 → 4.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: f06ec249cc2efa9d4924d524769752cc9702cf017a1d0020d010e8d4a9eae9f8
4
- data.tar.gz: f056af849c503c3870f69a707a4409428d6b200cff4df73237cd21e3ca5ce2ed
3
+ metadata.gz: 3fc31edba5c9cfea934c40b4ac410c942f5d0fcb75a236a9a0f8bd671556058a
4
+ data.tar.gz: 6ebbf8156b7092e358c4ed08f2d403a002c4f8930cc7e5b5bfc375cd5bc6e718
5
5
  SHA512:
6
- metadata.gz: 55baf7050e12a28da721b94764740a9267b1ea6b16cb7fe515cf306bfa695463055fae8b2aa16badf47b541f470cb6357b40611d5965d8d51c03a18f7cf985db
7
- data.tar.gz: 4853c8cafca07ec918c2d5f1e3ccfa01988432021ded6350470be15f369561aa534bc1a845521107f8e5d2a5a602d37e160a556d936b09e9b4f8573b9fa70ccb
6
+ metadata.gz: 21b86b8a69c1878736de93952f5b4e88bcb1080470f3b3df9f1e12087a29996f71dc39177020747b2e31fff6a39da88ff560e168b35ce61e602e77eb68c7e45b
7
+ data.tar.gz: 4cf16e7b8af0f80d68cae494c59f7f0c3722c92475c80b47ad2ea4f7b719099ad8e053deb708ee90fe1996db4065869f1f98c92121987cbf68bcae159001465e
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CreateAuthieSessions < ActiveRecord::Migration[4.2]
3
+ class CreateAuthieSessions < ActiveRecord::Migration[6.1]
4
4
  def change
5
5
  create_table :authie_sessions do |t|
6
6
  t.string :token, :browser_id
7
- t.integer :user_id
7
+ t.bigint :user_id
8
8
  t.boolean :active, default: true
9
9
  t.text :data
10
10
  t.datetime :expires_at
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AddIndexesToAuthieSessions < ActiveRecord::Migration[4.2]
3
+ class AddIndexesToAuthieSessions < ActiveRecord::Migration[6.1]
4
4
  def change
5
5
  add_column :authie_sessions, :user_type, :string
6
6
  add_index :authie_sessions, :token, length: 10
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AddParentIdToAuthieSessions < ActiveRecord::Migration[4.2]
3
+ class AddParentIdToAuthieSessions < ActiveRecord::Migration[6.1]
4
4
  def change
5
- add_column :authie_sessions, :parent_id, :integer
5
+ add_column :authie_sessions, :parent_id, :bigint
6
6
  end
7
7
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AddTwoFactorAuthFieldsToAuthie < ActiveRecord::Migration[4.2]
3
+ class AddTwoFactorAuthFieldsToAuthie < ActiveRecord::Migration[6.1]
4
4
  def change
5
5
  add_column :authie_sessions, :two_factored_at, :datetime
6
6
  add_column :authie_sessions, :two_factored_ip, :string
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AddTokenHashesToAuthieSessions < ActiveRecord::Migration[4.2]
3
+ class AddTokenHashesToAuthieSessions < ActiveRecord::Migration[6.1]
4
4
  def change
5
5
  add_column :authie_sessions, :token_hash, :string
6
6
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AddIndexToTokenHashesOnAuthieSessions < ActiveRecord::Migration[4.2]
3
+ class AddIndexToTokenHashesOnAuthieSessions < ActiveRecord::Migration[6.1]
4
4
  def change
5
5
  add_index :authie_sessions, :token_hash, length: 10
6
6
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AddHostToAuthieSessions < ActiveRecord::Migration[4.2]
3
+ class AddHostToAuthieSessions < ActiveRecord::Migration[6.1]
4
4
  def change
5
5
  add_column :authie_sessions, :host, :string
6
6
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class AddTwoFactorRequiredToSessions < ActiveRecord::Migration[4.2]
3
+ class AddTwoFactorRequiredToSessions < ActiveRecord::Migration[6.1]
4
4
  def change
5
5
  add_column :authie_sessions, :skip_two_factor, :boolean, default: false
6
6
  end
data/lib/authie/config.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'authie/event_manager'
4
-
5
3
  module Authie
6
4
  class Config
7
5
  attr_accessor :session_inactivity_timeout
@@ -10,7 +8,6 @@ module Authie
10
8
  attr_accessor :browser_id_cookie_name
11
9
  attr_accessor :session_token_length
12
10
  attr_accessor :extend_session_expiry_on_touch
13
- attr_accessor :events
14
11
 
15
12
  def initialize
16
13
  @session_inactivity_timeout = 12.hours
@@ -19,7 +16,6 @@ module Authie
19
16
  @browser_id_cookie_name = :browser_id
20
17
  @session_token_length = 64
21
18
  @extend_session_expiry_on_touch = false
22
- @events = EventManager.new
23
19
  end
24
20
  end
25
21
 
@@ -32,5 +28,9 @@ module Authie
32
28
  block.call(config)
33
29
  config
34
30
  end
31
+
32
+ def notify(event, args = {}, &block)
33
+ ActiveSupport::Notifications.instrument("#{event}.authie", args, &block)
34
+ end
35
35
  end
36
36
  end
@@ -34,7 +34,9 @@ module Authie
34
34
  httponly: true,
35
35
  secure: @controller.request.ssl?
36
36
  }
37
- Authie.config.events.dispatch(:set_browser_id, proposed_browser_id)
37
+ Authie.notify(:set_browser_id,
38
+ browser_id: proposed_browser_id,
39
+ controller: @controller)
38
40
  end
39
41
  proposed_browser_id
40
42
  end
@@ -44,9 +46,9 @@ module Authie
44
46
  #
45
47
  # @return [Authie::Session, false]
46
48
  def validate_auth_session
47
- return auth_session.validate if logged_in?
49
+ return false unless logged_in?
48
50
 
49
- false
51
+ auth_session.validate
50
52
  end
51
53
 
52
54
  # Touch the session to update details on the latest activity.
@@ -72,13 +74,12 @@ module Authie
72
74
  #
73
75
  # @return [Authie::Session, nil]
74
76
  def create_auth_session(user, **kwargs)
75
- if user
76
- @auth_session = Authie::Session.start(@controller, user: user, **kwargs)
77
- return @auth_session
77
+ if user.nil?
78
+ invalidate_auth_session
79
+ return nil
78
80
  end
79
81
 
80
- invalidate_auth_session
81
- nil
82
+ @auth_session = Authie::Session.start(@controller, user: user, **kwargs)
82
83
  end
83
84
 
84
85
  # Invalidate the existing auth session if one exists. Return true if a sesion has been invalidated
@@ -86,13 +87,11 @@ module Authie
86
87
  #
87
88
  # @return [Boolean]
88
89
  def invalidate_auth_session
89
- if logged_in?
90
- auth_session.invalidate
91
- @auth_session = nil
92
- return true
93
- end
90
+ return false unless logged_in?
94
91
 
95
- false
92
+ auth_session.invalidate
93
+ @auth_session = nil
94
+ true
96
95
  end
97
96
 
98
97
  # Is anyone currently logged in? Return true if there is an auth session present.
@@ -6,7 +6,8 @@ module Authie
6
6
  module ControllerExtension
7
7
  class << self
8
8
  def included(base)
9
- base.helper_method :logged_in?, :current_user, :auth_session
9
+ base.helper_method :logged_in?, :current_user, :auth_session if base.respond_to?(:helper_method)
10
+
10
11
  base.before_action :set_browser_id, :validate_auth_session
11
12
  base.around_action :touch_auth_session
12
13
 
@@ -13,7 +13,14 @@ module Authie
13
13
  attr_reader :session
14
14
 
15
15
  # A parent class that encapsulates all session validity errors.
16
- class ValidityError < Error; end
16
+ class ValidityError < Error
17
+ attr_reader :session
18
+
19
+ def initialize(message, session = nil)
20
+ super(message)
21
+ @session = session
22
+ end
23
+ end
17
24
 
18
25
  # Raised when a session is used but it is no longer active
19
26
  class InactiveSession < ValidityError; end
@@ -94,7 +101,7 @@ module Authie
94
101
  @session.requests += 1
95
102
  extend_session_expiry_if_appropriate
96
103
  @session.save!
97
- Authie.config.events.dispatch(:session_touched, self)
104
+ Authie.notify(:touch, session: self)
98
105
  self
99
106
  end
100
107
 
@@ -105,7 +112,7 @@ module Authie
105
112
  def see_password
106
113
  @session.password_seen_at = Time.now
107
114
  @session.save!
108
- Authie.config.events.dispatch(:seen_password, self)
115
+ Authie.notify(:see_password, session: self)
109
116
  self
110
117
  end
111
118
 
@@ -119,7 +126,7 @@ module Authie
119
126
  @session.two_factored_ip = @controller.request.ip
120
127
  @session.skip_two_factor = skip unless skip.nil?
121
128
  @session.save!
122
- Authie.config.events.dispatch(:marked_as_two_factor, self)
129
+ Authie.notify(:mark_as_two_factor, session: self)
123
130
  self
124
131
  end
125
132
 
@@ -130,7 +137,7 @@ module Authie
130
137
  # @return [Authie::Session]
131
138
  def start
132
139
  set_cookie
133
- Authie.config.events.dispatch(:start_session, session)
140
+ Authie.notify(:session_start, session: self)
134
141
  self
135
142
  end
136
143
 
@@ -145,7 +152,6 @@ module Authie
145
152
 
146
153
  private
147
154
 
148
- # rubocop:disable Naming/AccessorMethodName
149
155
  def set_cookie(value = @session.temporary_token)
150
156
  cookies[:user_session] = {
151
157
  value: value,
@@ -153,10 +159,9 @@ module Authie
153
159
  httponly: true,
154
160
  expires: @session.expires_at
155
161
  }
156
- Authie.config.events.dispatch(:session_cookie_updated, self)
162
+ Authie.notify(:cookie_updated, session: session)
157
163
  true
158
164
  end
159
- # rubocop:enable Naming/AccessorMethodName
160
165
 
161
166
  def cookies
162
167
  @controller.send(:cookies)
@@ -164,9 +169,9 @@ module Authie
164
169
 
165
170
  def validate_browser_id
166
171
  if cookies[:browser_id] != @session.browser_id
172
+ Authie.notify(:browser_id_mismatch_error, session: self)
167
173
  invalidate
168
- Authie.config.events.dispatch(:browser_id_mismatch_error, self)
169
- raise BrowserMismatch, 'Browser ID mismatch'
174
+ raise BrowserMismatch.new('Browser ID mismatch', self)
170
175
  end
171
176
 
172
177
  self
@@ -175,8 +180,8 @@ module Authie
175
180
  def validate_active
176
181
  unless @session.active?
177
182
  invalidate
178
- Authie.config.events.dispatch(:invalid_session_error, self)
179
- raise InactiveSession, 'Session is no longer active'
183
+ Authie.notify(:invalid_session_error, session: self)
184
+ raise InactiveSession.new('Session is no longer active', self)
180
185
  end
181
186
 
182
187
  self
@@ -185,8 +190,8 @@ module Authie
185
190
  def validate_expiry
186
191
  if @session.expired?
187
192
  invalidate
188
- Authie.config.events.dispatch(:expired_session_error, self)
189
- raise ExpiredSession, 'Persistent session has expired'
193
+ Authie.notify(:expired_session_error, session: self)
194
+ raise ExpiredSession.new('Persistent session has expired', self)
190
195
  end
191
196
 
192
197
  self
@@ -195,8 +200,8 @@ module Authie
195
200
  def validate_inactivity
196
201
  if @session.inactive?
197
202
  invalidate
198
- Authie.config.events.dispatch(:inactive_session_error, self)
199
- raise InactiveSession, 'Non-persistent session has expired'
203
+ Authie.notify(:inactive_session_error, session: self)
204
+ raise InactiveSession.new('Non-persistent session has expired', self)
200
205
  end
201
206
 
202
207
  self
@@ -205,8 +210,9 @@ module Authie
205
210
  def validate_host
206
211
  if @session.host && @session.host != @controller.request.host
207
212
  invalidate
208
- Authie.config.events.dispatch(:host_mismatch_error, self)
209
- raise HostMismatch, "Session was created on #{@session.host} but accessed using #{@controller.request.host}"
213
+ Authie.notify(:host_mismatch_error, session: self)
214
+ raise HostMismatch.new("Session was created on #{@session.host} but accessed using #{@controller.request.host}",
215
+ self)
210
216
  end
211
217
 
212
218
  self
@@ -264,6 +270,7 @@ module Authie
264
270
  end
265
271
 
266
272
  delegate :hash_token, to: SessionModel
273
+ delegate :cleanup, to: SessionModel
267
274
  end
268
275
 
269
276
  # Backwards compatibility with Authie < 4.0. These methods were all available on sessions
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_record/base'
3
+ require 'active_record'
4
4
  require 'securerandom'
5
5
  require 'authie/config'
6
6
 
@@ -63,8 +63,10 @@ module Authie
63
63
  end
64
64
 
65
65
  def invalidate!
66
+ active_now = active?
66
67
  self.active = false
67
68
  save!
69
+ Authie.notify(:session_invalidate, session: self) if active_now
68
70
  true
69
71
  end
70
72
 
@@ -79,7 +81,7 @@ module Authie
79
81
  end
80
82
 
81
83
  def invalidate_others!
82
- self.class.where('id != ?', id).for_user(user).each(&:invalidate!).inspect
84
+ self.class.where('id != ?', id).active.for_user(user).each(&:invalidate!)
83
85
  end
84
86
 
85
87
  # Have we seen the user's password recently in this sesion?
@@ -136,13 +138,13 @@ module Authie
136
138
 
137
139
  # Cleanup any old sessions.
138
140
  def cleanup
139
- Authie.config.events.dispatch(:before_cleanup)
140
- # Invalidate transient sessions that haven't been used
141
- active.where('expires_at IS NULL AND last_activity_at < ?',
142
- Authie.config.session_inactivity_timeout.ago).each(&:invalidate!)
143
- # Invalidate persistent sessions that have expired
144
- active.where('expires_at IS NOT NULL AND expires_at < ?', Time.now).each(&:invalidate!)
145
- Authie.config.events.dispatch(:after_cleanup)
141
+ Authie.notify(:cleanup) do
142
+ # Invalidate transient sessions that haven't been used
143
+ active.where('expires_at IS NULL AND last_activity_at < ?',
144
+ Authie.config.session_inactivity_timeout.ago).each(&:invalidate!)
145
+ # Invalidate persistent sessions that have expired
146
+ active.where('expires_at IS NOT NULL AND expires_at < ?', Time.now).each(&:invalidate!)
147
+ end
146
148
  true
147
149
  end
148
150
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authie
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.rc9
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Cooke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-03 00:00:00.000000000 Z
11
+ date: 2023-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -30,194 +30,6 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '8.0'
33
- - !ruby/object:Gem::Dependency
34
- name: appraisal
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - '='
38
- - !ruby/object:Gem::Version
39
- version: 2.4.1
40
- type: :development
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - '='
45
- - !ruby/object:Gem::Version
46
- version: 2.4.1
47
- - !ruby/object:Gem::Dependency
48
- name: rails
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '5.0'
54
- - - "<"
55
- - !ruby/object:Gem::Version
56
- version: '8.0'
57
- type: :development
58
- prerelease: false
59
- version_requirements: !ruby/object:Gem::Requirement
60
- requirements:
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: '5.0'
64
- - - "<"
65
- - !ruby/object:Gem::Version
66
- version: '8.0'
67
- - !ruby/object:Gem::Dependency
68
- name: rspec
69
- requirement: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: '0'
74
- type: :development
75
- prerelease: false
76
- version_requirements: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - ">="
79
- - !ruby/object:Gem::Version
80
- version: '0'
81
- - !ruby/object:Gem::Dependency
82
- name: rspec-core
83
- requirement: !ruby/object:Gem::Requirement
84
- requirements:
85
- - - ">="
86
- - !ruby/object:Gem::Version
87
- version: '0'
88
- type: :development
89
- prerelease: false
90
- version_requirements: !ruby/object:Gem::Requirement
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- version: '0'
95
- - !ruby/object:Gem::Dependency
96
- name: rspec-expectations
97
- requirement: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - ">="
100
- - !ruby/object:Gem::Version
101
- version: '0'
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- requirements:
106
- - - ">="
107
- - !ruby/object:Gem::Version
108
- version: '0'
109
- - !ruby/object:Gem::Dependency
110
- name: rspec-mocks
111
- requirement: !ruby/object:Gem::Requirement
112
- requirements:
113
- - - ">="
114
- - !ruby/object:Gem::Version
115
- version: '0'
116
- type: :development
117
- prerelease: false
118
- version_requirements: !ruby/object:Gem::Requirement
119
- requirements:
120
- - - ">="
121
- - !ruby/object:Gem::Version
122
- version: '0'
123
- - !ruby/object:Gem::Dependency
124
- name: rspec-rails
125
- requirement: !ruby/object:Gem::Requirement
126
- requirements:
127
- - - ">="
128
- - !ruby/object:Gem::Version
129
- version: '0'
130
- type: :development
131
- prerelease: false
132
- version_requirements: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - ">="
135
- - !ruby/object:Gem::Version
136
- version: '0'
137
- - !ruby/object:Gem::Dependency
138
- name: rubocop
139
- requirement: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - '='
142
- - !ruby/object:Gem::Version
143
- version: 1.17.0
144
- type: :development
145
- prerelease: false
146
- version_requirements: !ruby/object:Gem::Requirement
147
- requirements:
148
- - - '='
149
- - !ruby/object:Gem::Version
150
- version: 1.17.0
151
- - !ruby/object:Gem::Dependency
152
- name: simplecov
153
- requirement: !ruby/object:Gem::Requirement
154
- requirements:
155
- - - ">="
156
- - !ruby/object:Gem::Version
157
- version: '0'
158
- type: :development
159
- prerelease: false
160
- version_requirements: !ruby/object:Gem::Requirement
161
- requirements:
162
- - - ">="
163
- - !ruby/object:Gem::Version
164
- version: '0'
165
- - !ruby/object:Gem::Dependency
166
- name: simplecov-console
167
- requirement: !ruby/object:Gem::Requirement
168
- requirements:
169
- - - ">="
170
- - !ruby/object:Gem::Version
171
- version: '0'
172
- type: :development
173
- prerelease: false
174
- version_requirements: !ruby/object:Gem::Requirement
175
- requirements:
176
- - - ">="
177
- - !ruby/object:Gem::Version
178
- version: '0'
179
- - !ruby/object:Gem::Dependency
180
- name: solargraph
181
- requirement: !ruby/object:Gem::Requirement
182
- requirements:
183
- - - ">="
184
- - !ruby/object:Gem::Version
185
- version: '0'
186
- type: :development
187
- prerelease: false
188
- version_requirements: !ruby/object:Gem::Requirement
189
- requirements:
190
- - - ">="
191
- - !ruby/object:Gem::Version
192
- version: '0'
193
- - !ruby/object:Gem::Dependency
194
- name: sqlite3
195
- requirement: !ruby/object:Gem::Requirement
196
- requirements:
197
- - - '='
198
- - !ruby/object:Gem::Version
199
- version: 1.4.2
200
- type: :development
201
- prerelease: false
202
- version_requirements: !ruby/object:Gem::Requirement
203
- requirements:
204
- - - '='
205
- - !ruby/object:Gem::Version
206
- version: 1.4.2
207
- - !ruby/object:Gem::Dependency
208
- name: timecop
209
- requirement: !ruby/object:Gem::Requirement
210
- requirements:
211
- - - ">="
212
- - !ruby/object:Gem::Version
213
- version: '0'
214
- type: :development
215
- prerelease: false
216
- version_requirements: !ruby/object:Gem::Requirement
217
- requirements:
218
- - - ">="
219
- - !ruby/object:Gem::Version
220
- version: '0'
221
33
  description: A Rails library for storing user sessions in a backend database
222
34
  email:
223
35
  - me@adamcooke.io
@@ -239,7 +51,6 @@ files:
239
51
  - lib/authie/controller_extension.rb
240
52
  - lib/authie/engine.rb
241
53
  - lib/authie/error.rb
242
- - lib/authie/event_manager.rb
243
54
  - lib/authie/rack_controller.rb
244
55
  - lib/authie/session.rb
245
56
  - lib/authie/session_model.rb
@@ -260,11 +71,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
260
71
  version: '0'
261
72
  required_rubygems_version: !ruby/object:Gem::Requirement
262
73
  requirements:
263
- - - ">"
74
+ - - ">="
264
75
  - !ruby/object:Gem::Version
265
- version: 1.3.1
76
+ version: '0'
266
77
  requirements: []
267
- rubygems_version: 3.3.7
78
+ rubygems_version: 3.3.26
268
79
  signing_key:
269
80
  specification_version: 4
270
81
  summary: A Rails library for storing user sessions in a backend database
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Authie
4
- class EventManager
5
- attr_reader :callbacks
6
-
7
- def initialize
8
- @callbacks = {}
9
- end
10
-
11
- def dispatch(event, *args)
12
- callbacks = @callbacks[event.to_sym]
13
- return if callbacks.nil?
14
-
15
- callbacks.each do |cb|
16
- cb.call(*args)
17
- end
18
- end
19
-
20
- def on(event, &block)
21
- @callbacks[event.to_sym] ||= []
22
- @callbacks[event.to_sym] << block
23
- end
24
-
25
- def remove(event, block)
26
- cb = @callbacks[event.to_sym]
27
- return if cb.nil?
28
-
29
- cb.delete(block)
30
- end
31
- end
32
- end