veri 0.2.0 → 0.2.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/veri/configuration.rb +46 -11
- data/lib/veri/controllers/concerns/authentication.rb +6 -1
- data/lib/veri/inputs.rb +13 -9
- data/lib/veri/models/concerns/authenticatable.rb +18 -3
- data/lib/veri/models/session.rb +33 -13
- data/lib/veri/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6119b194fd813a1aad85a20b8513a15fe30143f601e1f2ce6cefa5d46085af70
|
4
|
+
data.tar.gz: c05d56946b5a010977bee885a807f2986e6d811eb3e9cc96cc0cc44ffe98b9f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb7c6dfd8fe97b4c7a29b11cb06d01f29dc1ee86cf962512a6db239fcc2f3be1f0ebabc9875c4122843970daab8250d75cde8f4c63016f4580cae1169a41c3c7
|
7
|
+
data.tar.gz: a96429440653c18be22e9f425ef3dac167fc773666b0f99fb1ab0a08df747c8f27aa4f7d812d76f420a2974a48b46b916a14795f0445307dd0d73cc0f21e2f8b
|
data/CHANGELOG.md
CHANGED
data/lib/veri/configuration.rb
CHANGED
@@ -10,31 +10,66 @@ module Veri
|
|
10
10
|
setting :hashing_algorithm,
|
11
11
|
default: :argon2,
|
12
12
|
reader: true,
|
13
|
-
constructor: -> (value)
|
13
|
+
constructor: -> (value) do
|
14
|
+
Veri::Inputs.process(
|
15
|
+
value,
|
16
|
+
as: :hashing_algorithm,
|
17
|
+
error: Veri::ConfigurationError,
|
18
|
+
message: "Invalid hashing algorithm `#{value.inspect}`, supported algorithms are: #{Veri::Configuration::HASHERS.keys.join(", ")}"
|
19
|
+
)
|
20
|
+
end
|
14
21
|
setting :inactive_session_lifetime,
|
15
22
|
default: nil,
|
16
23
|
reader: true,
|
17
|
-
constructor: -> (value)
|
24
|
+
constructor: -> (value) do
|
25
|
+
Veri::Inputs.process(
|
26
|
+
value,
|
27
|
+
as: :duration,
|
28
|
+
optional: true,
|
29
|
+
error: Veri::ConfigurationError,
|
30
|
+
message: "Invalid inactive session lifetime `#{value.inspect}`, expected an instance of ActiveSupport::Duration or nil"
|
31
|
+
)
|
32
|
+
end
|
18
33
|
setting :total_session_lifetime,
|
19
34
|
default: 14.days,
|
20
35
|
reader: true,
|
21
|
-
constructor: -> (value)
|
36
|
+
constructor: -> (value) do
|
37
|
+
Veri::Inputs.process(
|
38
|
+
value,
|
39
|
+
as: :duration,
|
40
|
+
error: Veri::ConfigurationError,
|
41
|
+
message: "Invalid total session lifetime `#{value.inspect}`, expected an instance of ActiveSupport::Duration"
|
42
|
+
)
|
43
|
+
end
|
22
44
|
setting :user_model_name,
|
23
45
|
default: "User",
|
24
46
|
reader: true,
|
25
|
-
constructor: -> (value)
|
47
|
+
constructor: -> (value) do
|
48
|
+
Veri::Inputs.process(
|
49
|
+
value,
|
50
|
+
as: :non_empty_string,
|
51
|
+
error: Veri::ConfigurationError,
|
52
|
+
message: "Invalid user model name `#{value.inspect}`, expected an ActiveRecord model name as a string"
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
HASHERS = {
|
57
|
+
argon2: Veri::Password::Argon2,
|
58
|
+
bcrypt: Veri::Password::BCrypt,
|
59
|
+
scrypt: Veri::Password::SCrypt
|
60
|
+
}.freeze
|
26
61
|
|
27
62
|
def hasher
|
28
|
-
|
29
|
-
when :argon2 then Veri::Password::Argon2
|
30
|
-
when :bcrypt then Veri::Password::BCrypt
|
31
|
-
when :scrypt then Veri::Password::SCrypt
|
32
|
-
else raise Veri::Error, "Invalid hashing algorithm: #{hashing_algorithm}"
|
33
|
-
end
|
63
|
+
HASHERS.fetch(hashing_algorithm) { raise Veri::Error, "Invalid hashing algorithm: #{hashing_algorithm}" }
|
34
64
|
end
|
35
65
|
|
36
66
|
def user_model
|
37
|
-
Veri::Inputs.process(
|
67
|
+
Veri::Inputs.process(
|
68
|
+
user_model_name,
|
69
|
+
as: :model,
|
70
|
+
error: Veri::ConfigurationError,
|
71
|
+
message: "Invalid user model name `#{user_model_name}`, expected an ActiveRecord model name as a string"
|
72
|
+
)
|
38
73
|
end
|
39
74
|
end
|
40
75
|
end
|
@@ -32,7 +32,12 @@ module Veri
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def log_in(authenticatable)
|
35
|
-
|
35
|
+
processed_authenticatable = Veri::Inputs.process(
|
36
|
+
authenticatable,
|
37
|
+
as: :authenticatable,
|
38
|
+
message: "Expected an instance of #{Veri::Configuration.user_model_name}, got `#{authenticatable.inspect}`"
|
39
|
+
)
|
40
|
+
token = Veri::Session.establish(processed_authenticatable, request)
|
36
41
|
cookies.encrypted.permanent[:veri_token] = { value: token, httponly: true }
|
37
42
|
end
|
38
43
|
|
data/lib/veri/inputs.rb
CHANGED
@@ -6,22 +6,26 @@ module Veri
|
|
6
6
|
|
7
7
|
include Dry.Types()
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
TYPES = {
|
10
|
+
hashing_algorithm: -> { self::Strict::Symbol.enum(:argon2, :bcrypt, :scrypt) },
|
11
|
+
duration: -> { self::Instance(ActiveSupport::Duration) },
|
12
|
+
non_empty_string: -> { self::Strict::String.constrained(min_size: 1) },
|
13
|
+
model: -> { self::Strict::Class.constructor { _1.try(:safe_constantize) || _1 }.constrained(lt: ActiveRecord::Base) },
|
14
|
+
authenticatable: -> { self::Instance(Veri::Configuration.user_model) },
|
15
|
+
request: -> { self::Instance(ActionDispatch::Request) }
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
def process(value, as:, optional: false, error: Veri::InvalidArgumentError, message: nil)
|
19
|
+
checker = type_for(as)
|
11
20
|
checker = checker.optional if optional
|
12
21
|
|
13
22
|
checker[value]
|
14
23
|
rescue Dry::Types::CoercionError => e
|
15
|
-
raise error, e.message
|
24
|
+
raise error, message || e.message
|
16
25
|
end
|
17
26
|
|
18
27
|
private
|
19
28
|
|
20
|
-
def
|
21
|
-
def duration = self::Instance(ActiveSupport::Duration)
|
22
|
-
def string = self::Strict::String
|
23
|
-
def model = self::Strict::Class.constructor { _1.try(:safe_constantize) || _1 }.constrained(lt: ActiveRecord::Base)
|
24
|
-
def authenticatable = self::Instance(Veri::Configuration.user_model)
|
25
|
-
def request = self::Instance(ActionDispatch::Request)
|
29
|
+
def type_for(name) = Veri::Inputs::TYPES.fetch(name).call
|
26
30
|
end
|
27
31
|
end
|
@@ -12,17 +12,32 @@ module Veri
|
|
12
12
|
|
13
13
|
def update_password(password)
|
14
14
|
update!(
|
15
|
-
hashed_password: hasher.create(
|
15
|
+
hashed_password: hasher.create(
|
16
|
+
Veri::Inputs.process(
|
17
|
+
password,
|
18
|
+
as: :non_empty_string,
|
19
|
+
message: "Expected a non-empty string, got `#{password.inspect}`"
|
20
|
+
)
|
21
|
+
),
|
16
22
|
password_updated_at: Time.current
|
17
23
|
)
|
18
24
|
end
|
19
25
|
|
20
26
|
def verify_password(password)
|
21
|
-
hasher.verify(
|
27
|
+
hasher.verify(
|
28
|
+
Veri::Inputs.process(
|
29
|
+
password,
|
30
|
+
as: :non_empty_string,
|
31
|
+
message: "Expected a non-empty string, got `#{password.inspect}`"
|
32
|
+
),
|
33
|
+
hashed_password
|
34
|
+
)
|
22
35
|
end
|
23
36
|
|
24
37
|
private
|
25
38
|
|
26
|
-
def hasher
|
39
|
+
def hasher
|
40
|
+
@hasher ||= Veri::Configuration.hasher
|
41
|
+
end
|
27
42
|
end
|
28
43
|
end
|
data/lib/veri/models/session.rb
CHANGED
@@ -55,7 +55,11 @@ module Veri
|
|
55
55
|
update!(
|
56
56
|
shapeshifted_at: Time.current,
|
57
57
|
original_authenticatable: authenticatable,
|
58
|
-
authenticatable: Veri::Inputs.process(
|
58
|
+
authenticatable: Veri::Inputs.process(
|
59
|
+
user,
|
60
|
+
as: :authenticatable,
|
61
|
+
message: "Expected an instance of #{Veri::Configuration.user_model_name}, got `#{user.inspect}`"
|
62
|
+
)
|
59
63
|
)
|
60
64
|
end
|
61
65
|
|
@@ -68,14 +72,14 @@ module Veri
|
|
68
72
|
end
|
69
73
|
|
70
74
|
class << self
|
71
|
-
def establish(
|
75
|
+
def establish(user, request)
|
72
76
|
token = SecureRandom.hex(32)
|
73
77
|
expires_at = Time.current + Veri::Configuration.total_session_lifetime
|
74
78
|
|
75
79
|
new(
|
76
80
|
hashed_token: Digest::SHA256.hexdigest(token),
|
77
81
|
expires_at:,
|
78
|
-
authenticatable: Veri::Inputs.process(
|
82
|
+
authenticatable: Veri::Inputs.process(user, as: :authenticatable, error: Veri::Error)
|
79
83
|
).update_info(
|
80
84
|
Veri::Inputs.process(request, as: :request, error: Veri::Error)
|
81
85
|
)
|
@@ -83,20 +87,36 @@ module Veri
|
|
83
87
|
token
|
84
88
|
end
|
85
89
|
|
86
|
-
def prune(
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
+
def prune(user = nil)
|
91
|
+
scope = if user
|
92
|
+
where(
|
93
|
+
authenticatable: Veri::Inputs.process(
|
94
|
+
user,
|
95
|
+
as: :authenticatable,
|
96
|
+
optional: true,
|
97
|
+
message: "Expected an instance of #{Veri::Configuration.user_model_name} or nil, got `#{user.inspect}`"
|
98
|
+
)
|
99
|
+
)
|
100
|
+
else
|
101
|
+
all
|
102
|
+
end
|
103
|
+
|
104
|
+
expired_scope = scope.where(expires_at: ...Time.current)
|
105
|
+
|
90
106
|
if Veri::Configuration.inactive_session_lifetime
|
91
|
-
|
92
|
-
|
93
|
-
)
|
107
|
+
inactive_cutoff = Time.current - Veri::Configuration.inactive_session_lifetime
|
108
|
+
expired_scope = expired_scope.or(scope.where(last_seen_at: ...inactive_cutoff))
|
94
109
|
end
|
95
|
-
|
110
|
+
|
111
|
+
expired_scope.delete_all
|
96
112
|
end
|
97
113
|
|
98
|
-
def terminate_all(
|
99
|
-
Veri::Inputs.process(
|
114
|
+
def terminate_all(user)
|
115
|
+
Veri::Inputs.process(
|
116
|
+
user,
|
117
|
+
as: :authenticatable,
|
118
|
+
message: "Expected an instance of #{Veri::Configuration.user_model_name}, got `#{user.inspect}`"
|
119
|
+
).veri_sessions.delete_all
|
100
120
|
end
|
101
121
|
end
|
102
122
|
end
|
data/lib/veri/version.rb
CHANGED