authie 4.0.0.rc10 → 4.1.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: c2ba869656ec43ca7b92803584ad2361ad2a7c443b2b69bc7f7bac2c0e991218
4
- data.tar.gz: 67340e7ab60e5fafb35a17a8760611d5f1c25a3ae67abf75363f7210ec3cb181
3
+ metadata.gz: 1b35fefc8e1d77c5dc713e70d46d29a2e6de782e3d3c6cb35a89f8a31f416406
4
+ data.tar.gz: f4bfa5628f66ef549e2cb0e74b87c2a503a0d49916d1a93aba7af299bc0e7d29
5
5
  SHA512:
6
- metadata.gz: b6f3604a227d448f0d2724eb6566f83c4b665121fd3d9075691bdccd4e72370a230b4916ae1a8fd8b68fff893e81b5bd39170be2c5ebe244817fa33c5365daf7
7
- data.tar.gz: fcde4d28afbc7bab2727150c69be0baa527a89e65bb1047159499247771b2284bec104f54bbd7adf7db52f18dacac58ab0817085d8b42ff8f07e226b201bffe6
6
+ metadata.gz: 47793da24b501a3e3a5f26652cde36431c90f6f43b8d0e1fa8477e366b2ba6f6ee524e989dd5d2520f15b61c567320f701c29caa5c62bf1acfafc1ad1d096415
7
+ data.tar.gz: 98e9993d49250765b479e7bd37703652f381d3dc6fb2cf1d1792498b5c95f81c200bb0ea68ff09be6fe072e7141ed49876b43a0953a94fed012370bbbce5c36f
@@ -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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddCountriesToAuthieSessions < ActiveRecord::Migration[6.1]
4
+ def change
5
+ add_column :authie_sessions, :login_ip_country, :string
6
+ add_column :authie_sessions, :two_factored_ip_country, :string
7
+ add_column :authie_sessions, :last_activity_ip_country, :string
8
+ end
9
+ end
data/lib/authie/config.rb CHANGED
@@ -8,6 +8,7 @@ module Authie
8
8
  attr_accessor :browser_id_cookie_name
9
9
  attr_accessor :session_token_length
10
10
  attr_accessor :extend_session_expiry_on_touch
11
+ attr_accessor :ip_lookup
11
12
 
12
13
  def initialize
13
14
  @session_inactivity_timeout = 12.hours
@@ -16,6 +17,13 @@ module Authie
16
17
  @browser_id_cookie_name = :browser_id
17
18
  @session_token_length = 64
18
19
  @extend_session_expiry_on_touch = false
20
+ @lookup_ip_country_backend = nil
21
+ end
22
+
23
+ def lookup_ip_country(ip)
24
+ return nil if @lookup_ip_country_backend.nil?
25
+
26
+ @lookup_ip_country_backend.call(ip)
19
27
  end
20
28
  end
21
29
 
@@ -46,9 +46,9 @@ module Authie
46
46
  #
47
47
  # @return [Authie::Session, false]
48
48
  def validate_auth_session
49
- return auth_session.validate if logged_in?
49
+ return false unless logged_in?
50
50
 
51
- false
51
+ auth_session.validate
52
52
  end
53
53
 
54
54
  # Touch the session to update details on the latest activity.
@@ -74,13 +74,12 @@ module Authie
74
74
  #
75
75
  # @return [Authie::Session, nil]
76
76
  def create_auth_session(user, **kwargs)
77
- if user
78
- @auth_session = Authie::Session.start(@controller, user: user, **kwargs)
79
- return @auth_session
77
+ if user.nil?
78
+ invalidate_auth_session
79
+ return nil
80
80
  end
81
81
 
82
- invalidate_auth_session
83
- nil
82
+ @auth_session = Authie::Session.start(@controller, user: user, **kwargs)
84
83
  end
85
84
 
86
85
  # Invalidate the existing auth session if one exists. Return true if a sesion has been invalidated
@@ -88,13 +87,11 @@ module Authie
88
87
  #
89
88
  # @return [Boolean]
90
89
  def invalidate_auth_session
91
- if logged_in?
92
- auth_session.invalidate
93
- @auth_session = nil
94
- return true
95
- end
90
+ return false unless logged_in?
96
91
 
97
- false
92
+ auth_session.invalidate
93
+ @auth_session = nil
94
+ true
98
95
  end
99
96
 
100
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
@@ -89,7 +96,11 @@ module Authie
89
96
  # @return [Authie::Session]
90
97
  def touch
91
98
  @session.last_activity_at = Time.now
99
+ if @controller.request.ip != @session.last_activity_ip
100
+ @session.last_activity_ip_country = Authie.config.lookup_ip_country(@controller.request.ip)
101
+ end
92
102
  @session.last_activity_ip = @controller.request.ip
103
+
93
104
  @session.last_activity_path = @controller.request.path
94
105
  @session.requests += 1
95
106
  extend_session_expiry_if_appropriate
@@ -117,6 +128,7 @@ module Authie
117
128
  def mark_as_two_factored(skip: nil)
118
129
  @session.two_factored_at = Time.now
119
130
  @session.two_factored_ip = @controller.request.ip
131
+ @session.two_factored_ip_country = Authie.config.lookup_ip_country(@controller.request.ip)
120
132
  @session.skip_two_factor = skip unless skip.nil?
121
133
  @session.save!
122
134
  Authie.notify(:mark_as_two_factor, session: self)
@@ -145,7 +157,6 @@ module Authie
145
157
 
146
158
  private
147
159
 
148
- # rubocop:disable Naming/AccessorMethodName
149
160
  def set_cookie(value = @session.temporary_token)
150
161
  cookies[:user_session] = {
151
162
  value: value,
@@ -156,7 +167,6 @@ module Authie
156
167
  Authie.notify(:cookie_updated, session: session)
157
168
  true
158
169
  end
159
- # rubocop:enable Naming/AccessorMethodName
160
170
 
161
171
  def cookies
162
172
  @controller.send(:cookies)
@@ -164,9 +174,9 @@ module Authie
164
174
 
165
175
  def validate_browser_id
166
176
  if cookies[:browser_id] != @session.browser_id
167
- invalidate
168
177
  Authie.notify(:browser_id_mismatch_error, session: self)
169
- raise BrowserMismatch, 'Browser ID mismatch'
178
+ invalidate
179
+ raise BrowserMismatch.new('Browser ID mismatch', self)
170
180
  end
171
181
 
172
182
  self
@@ -176,7 +186,7 @@ module Authie
176
186
  unless @session.active?
177
187
  invalidate
178
188
  Authie.notify(:invalid_session_error, session: self)
179
- raise InactiveSession, 'Session is no longer active'
189
+ raise InactiveSession.new('Session is no longer active', self)
180
190
  end
181
191
 
182
192
  self
@@ -186,7 +196,7 @@ module Authie
186
196
  if @session.expired?
187
197
  invalidate
188
198
  Authie.notify(:expired_session_error, session: self)
189
- raise ExpiredSession, 'Persistent session has expired'
199
+ raise ExpiredSession.new('Persistent session has expired', self)
190
200
  end
191
201
 
192
202
  self
@@ -195,8 +205,8 @@ module Authie
195
205
  def validate_inactivity
196
206
  if @session.inactive?
197
207
  invalidate
198
- Authie.notify(:inactive_session_error, session: self)
199
- raise InactiveSession, 'Non-persistent session has expired'
208
+ Authie.notify(:inactive_session_error, session: self)
209
+ raise InactiveSession.new('Non-persistent session has expired', self)
200
210
  end
201
211
 
202
212
  self
@@ -206,7 +216,8 @@ module Authie
206
216
  if @session.host && @session.host != @controller.request.host
207
217
  invalidate
208
218
  Authie.notify(:host_mismatch_error, session: self)
209
- raise HostMismatch, "Session was created on #{@session.host} but accessed using #{@controller.request.host}"
219
+ raise HostMismatch.new("Session was created on #{@session.host} but accessed using #{@controller.request.host}",
220
+ self)
210
221
  end
211
222
 
212
223
  self
@@ -238,6 +249,7 @@ module Authie
238
249
  session.browser_id = cookies[:browser_id]
239
250
  session.login_at = Time.now
240
251
  session.login_ip = controller.request.ip
252
+ session.login_ip_country = Authie.config.lookup_ip_country(session.login_ip)
241
253
  session.host = controller.request.host
242
254
  session.user_agent = controller.request.user_agent
243
255
  session.expires_at = Time.now + Authie.config.persistent_session_length if persistent
@@ -292,9 +304,11 @@ module Authie
292
304
  delegate :invalidate_others!, to: :session
293
305
  delegate :last_activity_at, to: :session
294
306
  delegate :last_activity_ip, to: :session
307
+ delegate :last_activity_ip_country, to: :session
295
308
  delegate :last_activity_path, to: :session
296
309
  delegate :login_at, to: :session
297
310
  delegate :login_ip, to: :session
311
+ delegate :login_ip_country, to: :session
298
312
  delegate :password_seen_at, to: :session
299
313
  delegate :persisted?, to: :session
300
314
  delegate :persistent?, to: :session
@@ -305,6 +319,7 @@ module Authie
305
319
  delegate :token_hash, to: :session
306
320
  delegate :two_factored_at, to: :session
307
321
  delegate :two_factored_ip, to: :session
322
+ delegate :two_factored_ip_country, to: :session
308
323
  delegate :two_factored?, to: :session
309
324
  delegate :skip_two_factor?, to: :session
310
325
  delegate :update, to: :session
@@ -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?
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.rc10
4
+ version: 4.1.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-20 00:00:00.000000000 Z
11
+ date: 2023-06-27 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
@@ -233,6 +45,7 @@ files:
233
45
  - db/migrate/20170421174100_add_index_to_token_hashes_on_authie_sessions.rb
234
46
  - db/migrate/20180215152200_add_host_to_authie_sessions.rb
235
47
  - db/migrate/20220502180100_add_two_factor_required_to_sessions.rb
48
+ - db/migrate/20230627165500_add_countries_to_authie_sessions.rb
236
49
  - lib/authie.rb
237
50
  - lib/authie/config.rb
238
51
  - lib/authie/controller_delegate.rb
@@ -259,11 +72,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
259
72
  version: '0'
260
73
  required_rubygems_version: !ruby/object:Gem::Requirement
261
74
  requirements:
262
- - - ">"
75
+ - - ">="
263
76
  - !ruby/object:Gem::Version
264
- version: 1.3.1
77
+ version: '0'
265
78
  requirements: []
266
- rubygems_version: 3.3.7
79
+ rubygems_version: 3.3.26
267
80
  signing_key:
268
81
  specification_version: 4
269
82
  summary: A Rails library for storing user sessions in a backend database