authie 4.0.0.rc9 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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