signinable 2.0.16 → 3.0.1

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: 98c939505c7a77333b6244200b4e2f1e6337cd00ab721773db89333910d4b0b4
4
- data.tar.gz: 32917bd4f4f2671a9727f17c8b57b83f852fbd7b5c7259e6abe3f72b69669896
3
+ metadata.gz: c4cb3c9ed394555e10d075ec1b4ef7dfc401e81b1914abaff0ac79a34ed8adb1
4
+ data.tar.gz: d5a98fbe31a1db70c9739eb444bca9f1e070596853a5ef26911839c18d00289f
5
5
  SHA512:
6
- metadata.gz: 4728c3a79d4d85443e8d92a51a156409bb616a4be5782ad236ffe8c5006a8a60bd777655c38559dc390fffc2fc447aef0cedd08c2beeb4d142731e238337f326
7
- data.tar.gz: 1f0ae333d9cd6d4b53338a50b0a16fd2ec592ff7f5dfc87d400958eeddf33a51b8f6386172ecb2754291d811925637ac548968373030bfee09005107499cc06e
6
+ metadata.gz: a2922803d96c5617d587f7a695acc7a6bb902c73a218b0bbbf38f9f1859d9e86da00635a2cd6b6ab1eca6030ac2e46558921749a3204e3fc93ad9d68d5bb6ed0
7
+ data.tar.gz: aaeed33569ef9f0a6298671076a2aac3496874b02cd4a27f4e505d94d8a4859b9d0c23b5a99a289ceef6c7a9052e0947aaa434da4845aa82bc586b32755637b4
data/app/models/signin.rb CHANGED
@@ -13,33 +13,24 @@ class Signin < ActiveRecord::Base
13
13
  scope :active, -> { where('expiration_time IS NULL OR expiration_time > ?', Time.zone.now) }
14
14
 
15
15
  before_validation on: :create do
16
- self.token = generate_token
16
+ self.token = self.class.generate_token
17
17
  end
18
18
 
19
19
  serialize :custom_data if ActiveRecord::Base.connection.instance_values['config'][:adapter].match('mysql')
20
20
 
21
21
  def expire!
22
- renew!(period: 0, ip: ip, user_agent: user_agent)
22
+ update!(
23
+ ip: ip,
24
+ user_agent: user_agent,
25
+ expiration_time: Time.current
26
+ )
23
27
  end
24
28
 
25
29
  def expired?
26
- expireable? && expiration_time.past?
30
+ expiration_time.past?
27
31
  end
28
32
 
29
- def expireable?
30
- !expiration_time.nil?
31
- end
32
-
33
- def renew!(period:, ip:, user_agent:, refresh_token: false)
34
- update_hash = { ip: ip, user_agent: user_agent }
35
- update_hash[:expiration_time] = Time.zone.now + period if expireable?
36
- update_hash[:token] = generate_token if refresh_token
37
- update!(update_hash)
38
- end
39
-
40
- private
41
-
42
- def generate_token
33
+ def self.generate_token
43
34
  SecureRandom.urlsafe_base64(rand(50..100))
44
35
  end
45
36
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ migration_kls = Rails::VERSION::MAJOR > 4 ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
4
+ class ChangeSigninableIdToString < migration_kls
5
+ def self.up
6
+ change_column :signins, :signinable_id, :string, null: false
7
+ end
8
+
9
+ def self.down
10
+ change_column :signins, :signinable_id, :integer, null: false
11
+ end
12
+ end
@@ -9,16 +9,14 @@ module Signinable
9
9
  DEFAULT_REFRESH_EXP = 7200
10
10
  DEFAULT_JWT_EXP = 900
11
11
 
12
- cattr_reader :refresh_exp
13
12
  cattr_reader :simultaneous_signings
14
- cattr_reader :signin_restrictions
15
13
  cattr_reader :jwt_secret
16
14
  cattr_reader :jwt_exp
15
+ cattr_reader :refresh_exp
17
16
 
18
17
  def signinable(options = {})
19
18
  self.refresh_exp = options.fetch(:refresh_exp, DEFAULT_REFRESH_EXP)
20
19
  self.simultaneous_signings = options.fetch(:simultaneous, true)
21
- self.signin_restrictions = options[:restrictions]
22
20
  self.jwt_secret = options.fetch(:jwt_secret)
23
21
  self.jwt_exp = options.fetch(:jwt_exp, DEFAULT_JWT_EXP)
24
22
 
@@ -27,21 +25,19 @@ module Signinable
27
25
  attr_accessor :jwt
28
26
  end
29
27
 
30
- def authenticate_with_token(jwt, ip, user_agent, skip_restrictions: [])
28
+ def authenticate_with_token(jwt, ip, user_agent)
31
29
  jwt_payload = extract_jwt_payload(jwt)
32
- return refresh_jwt(jwt, ip, user_agent, skip_restrictions: skip_restrictions) unless jwt_payload
30
+ return nil unless jwt_payload
33
31
 
34
- signinable = find_by(primary_key => jwt_payload['signinable_id'])
32
+ jwt = refresh_jwt(jwt_payload[:data], ip, user_agent) if jwt_payload[:expired]
33
+
34
+ signinable = find_by(primary_key => jwt_payload[:data]['signinable_id'])
35
35
  return nil unless signinable
36
36
 
37
37
  signinable.jwt = jwt
38
38
  signinable
39
39
  end
40
40
 
41
- def check_signin_permission(signin, restrictions_to_check, skip_restrictions)
42
- signin_permitted?(signin, restrictions_to_check, skip_restrictions)
43
- end
44
-
45
41
  def expiration_period
46
42
  return refresh_exp.call if refresh_exp.respond_to?(:call)
47
43
 
@@ -60,101 +56,78 @@ module Signinable
60
56
  )
61
57
  end
62
58
 
63
- def refresh_jwt(jwt, ip, user_agent, skip_restrictions: [])
64
- token = refresh_token_from_jwt(jwt)
65
- return nil unless token
59
+ def refresh_jwt(jwt_payload, ip, user_agent)
60
+ old_token = jwt_payload['refresh_token']
61
+ new_token = Signin.generate_token
66
62
 
67
- signin = Signin.find_by(token: token)
63
+ result = Signin.where(token: old_token)
64
+ .active
65
+ .update_all(
66
+ token: new_token,
67
+ expiration_time: expiration_period.seconds.from_now,
68
+ ip: ip,
69
+ user_agent: user_agent
70
+ )
68
71
 
69
- return unless signin
70
- return nil if signin.expired?
71
- return nil unless check_signin_permission(signin, { ip: ip, user_agent: user_agent }, skip_restrictions)
72
+ return if result.zero?
72
73
 
73
- signin.renew!(period: expiration_period, ip: ip, user_agent: user_agent, refresh_token: true)
74
- signin.signinable.jwt = generate_jwt(signin.token, signin.signinable_id)
75
- signin.signinable
74
+ generate_jwt(new_token, jwt_payload['signinable_id'])
76
75
  end
77
76
 
78
- def refresh_token_from_jwt(jwt)
79
- JWT.decode(jwt, jwt_secret, true, { verify_expiration: false, algorithm: 'HS256' })[0]['refresh_token']
77
+ def extract_jwt_payload(jwt)
78
+ {
79
+ data: JWT.decode(jwt, jwt_secret, true, { algorithm: 'HS256' })[0],
80
+ expired: false
81
+ }
80
82
  rescue JWT::DecodeError
81
- nil
83
+ begin
84
+ {
85
+ data: JWT.decode(jwt, jwt_secret, true, { verify_expiration: false, algorithm: 'HS256' })[0],
86
+ expired: true
87
+ }
88
+ rescue JWT::DecodeError
89
+ nil
90
+ end
82
91
  end
83
92
 
84
93
  private
85
94
 
86
95
  cattr_writer :refresh_exp
87
96
  cattr_writer :simultaneous_signings
88
- cattr_writer :signin_restrictions
89
97
  cattr_writer :jwt_secret
90
98
  cattr_writer :jwt_exp
91
-
92
- def extract_jwt_payload(jwt)
93
- JWT.decode(jwt, jwt_secret, true, { algorithm: 'HS256' })[0]
94
- rescue JWT::DecodeError
95
- nil
96
- end
97
-
98
- def signin_permitted?(signin, restrictions_to_check, skip_restrictions)
99
- restriction_fields = signin_restriction_fields(signin, skip_restrictions)
100
-
101
- restrictions_to_check.slice(*restriction_fields).each do |field, value|
102
- return false unless signin.send(field) == value
103
- end
104
-
105
- true
106
- end
107
-
108
- def signin_restriction_fields(signin, skip_restrictions)
109
- fields = if signin_restrictions.respond_to?(:call)
110
- signin_restrictions.call(signin.signinable)
111
- elsif signin_restrictions.is_a?(Array)
112
- signin_restrictions
113
- else
114
- []
115
- end
116
- (fields - skip_restrictions) & ALLOWED_RESTRICTIONS
117
- end
118
99
  end
119
100
 
120
- def signin(ip, user_agent, referer, permanent: false, custom_data: {})
121
- expires_in = self.class.expiration_period
122
- expiration_time = expires_in.zero? || permanent ? nil : expires_in.seconds.from_now
101
+ def signin(ip, user_agent, referer, custom_data: {})
123
102
  Signin.where(signinable: self).active.map(&:expire!) unless self.class.simultaneous_signings
103
+
124
104
  signin = Signin.create!(
125
105
  signinable: self,
126
106
  ip: ip,
127
107
  referer: referer,
128
108
  user_agent: user_agent,
129
- expiration_time: expiration_time,
109
+ expiration_time: self.class.expiration_period.seconds.from_now,
130
110
  custom_data: custom_data
131
111
  )
132
112
 
133
113
  self.jwt = self.class.generate_jwt(signin.token, signin.signinable_id)
134
- end
135
114
 
136
- def signout(jwt, ip, user_agent, skip_restrictions: [])
137
- token = self.class.refresh_token_from_jwt(jwt)
138
- return unless token
115
+ signin
116
+ end
139
117
 
140
- signin = Signin.find_by_token(token)
118
+ def signout(jwt)
119
+ jwt_payload = self.class.extract_jwt_payload(jwt)
120
+ return unless jwt_payload
121
+ return if jwt_payload[:expired]
141
122
 
123
+ signin = Signin.find_by(token: jwt_payload[:data]['refresh_token'])
142
124
  return unless signin
143
125
  return if signin.expired?
144
- return unless self.class.check_signin_permission(
145
- signin,
146
- { ip: ip, user_agent: user_agent },
147
- skip_restrictions
148
- )
149
126
 
150
127
  signin.expire!
151
128
 
152
129
  true
153
130
  end
154
-
155
- def last_signin
156
- signins.active.last
157
- end
158
131
  end
159
132
  end
160
133
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Signinable
4
- VERSION = '2.0.16'
4
+ VERSION = '3.0.1'
5
5
  end
@@ -9,5 +9,6 @@ require 'signinable'
9
9
 
10
10
  module Dummy
11
11
  class Application < Rails::Application
12
+ config.load_defaults 7.0
12
13
  end
13
14
  end
Binary file
Binary file
File without changes