volcano-sdk 0.7.2 → 0.8.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 +4 -4
- data/README.md +15 -3
- data/lib/volcano/auth.rb +0 -26
- data/lib/volcano/auth_refresh.rb +8 -1
- data/lib/volcano/auth_sessions.rb +1 -10
- data/lib/volcano/auth_sign_out.rb +62 -0
- data/lib/volcano/auth_state.rb +6 -6
- data/lib/volcano/client.rb +6 -5
- data/lib/volcano/realtime/connection.rb +8 -7
- data/lib/volcano/realtime/connection_callbacks.rb +1 -1
- data/lib/volcano/realtime/postgres_database.rb +2 -3
- data/lib/volcano/realtime.rb +1 -1
- data/lib/volcano/session.rb +71 -2
- data/lib/volcano/version.rb +1 -1
- data/lib/volcano.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 255837a17bdecec1c4973e91d21885299b563a70adced0adf20fbbeb5bd8020d
|
|
4
|
+
data.tar.gz: edc269875f2132e437787412be884aeb0149acb81fb48397b750271b970afaa6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b5e51ede8b8946bb3aca753f0e0661d5e93c9ca6c3dccae7bd5dc78a34b64cf645138a2edd09f6c0c402a920505087410b12d14ce5485ae6ae46630295be21cf
|
|
7
|
+
data.tar.gz: 38ca82b2e5e0ca112e2be5d7de5ac4719686622524e162d3db6526d0dcd4462d640ca1df17012265aa87243122176ee5f06083f3b7a8ea4e1090e04569b13711
|
data/README.md
CHANGED
|
@@ -378,6 +378,17 @@ Success returns `nil`. The reset revokes the recovered account's existing
|
|
|
378
378
|
sessions and does not sign it in. The client keeps any unrelated local session
|
|
379
379
|
unchanged; sign in with the new password when the reset flow completes.
|
|
380
380
|
|
|
381
|
+
### Start with a supplied access token
|
|
382
|
+
|
|
383
|
+
Pass `access_token` to `Volcano::Client.new` to start without a refresh token or
|
|
384
|
+
known user identity. Construction makes no request and leaves `refresh_token`,
|
|
385
|
+
`user_id`, and `user` as `nil`. `auth.user` validates and caches the profile
|
|
386
|
+
without changing credentials. Without a refresh token, `refresh_session` raises
|
|
387
|
+
`Volcano::Error::AuthenticationError`. `sign_out` revokes the server session using
|
|
388
|
+
the access token and clears local state. Supply `refresh_token` alongside
|
|
389
|
+
`access_token` to enable refresh.
|
|
390
|
+
See the [token bootstrap example](https://github.com/Kong/volcano-sdk-ruby/blob/main/docs/README.md#use-a-supplied-access-token).
|
|
391
|
+
|
|
381
392
|
### Adopt an existing session
|
|
382
393
|
|
|
383
394
|
```ruby
|
|
@@ -429,10 +440,11 @@ client.auth.sign_out
|
|
|
429
440
|
raise "still signed in" if client.auth.current_session
|
|
430
441
|
```
|
|
431
442
|
|
|
432
|
-
`sign_out`
|
|
443
|
+
`sign_out` uses the access-token session when available, even if a refresh token was supplied.
|
|
444
|
+
It revokes the captured session and clears the captured in-memory
|
|
433
445
|
session. It succeeds without a request when no session exists. If revocation
|
|
434
|
-
fails, the SDK still clears that session and raises the typed error. A
|
|
435
|
-
|
|
446
|
+
fails, the SDK still clears that session and raises the typed error. A concurrent
|
|
447
|
+
refresh of the same session is cleared; a separate sign-in or adoption remains current.
|
|
436
448
|
|
|
437
449
|
### Invoke a function
|
|
438
450
|
|
data/lib/volcano/auth.rb
CHANGED
|
@@ -34,16 +34,6 @@ module Volcano
|
|
|
34
34
|
sign_in_for_generation(email:, password:, generation:)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
def sign_out
|
|
38
|
-
generation, current = @client.capture_session
|
|
39
|
-
return unless current
|
|
40
|
-
|
|
41
|
-
error = revocation_error(current.refresh_token)
|
|
42
|
-
raise Error::SessionChangedError, cause: error unless @client.clear_session_if_current?(generation)
|
|
43
|
-
|
|
44
|
-
raise error if error
|
|
45
|
-
end
|
|
46
|
-
|
|
47
37
|
private
|
|
48
38
|
|
|
49
39
|
def sign_in_for_generation(email:, password:, generation:)
|
|
@@ -66,22 +56,6 @@ module Volcano
|
|
|
66
56
|
end
|
|
67
57
|
end
|
|
68
58
|
|
|
69
|
-
def logout_response(refresh_token)
|
|
70
|
-
Transport.invoke do
|
|
71
|
-
@transport.auth_logout(
|
|
72
|
-
authorization: @client.anon_token,
|
|
73
|
-
refresh_token: refresh_token
|
|
74
|
-
)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def revocation_error(refresh_token)
|
|
79
|
-
Transport.body(logout_response(refresh_token), 204)
|
|
80
|
-
nil
|
|
81
|
-
rescue Error::VolcanoError => e
|
|
82
|
-
e
|
|
83
|
-
end
|
|
84
|
-
|
|
85
59
|
def build_session(payload)
|
|
86
60
|
owned_session(
|
|
87
61
|
access_token: payload.fetch('access_token'),
|
data/lib/volcano/auth_refresh.rb
CHANGED
|
@@ -78,6 +78,9 @@ module Volcano
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def perform_refresh(binding, notifications)
|
|
81
|
+
raise Error::AuthenticationError, 'No refresh token' unless binding.last.refresh_token
|
|
82
|
+
|
|
83
|
+
SessionCredentials.validate_refresh_source(binding.last)
|
|
81
84
|
session = refreshed_session(binding, notifications)
|
|
82
85
|
stored = @client.store_session_if_current?(
|
|
83
86
|
session, binding.first, event: :token_refreshed, notifications: notifications
|
|
@@ -86,7 +89,11 @@ module Volcano
|
|
|
86
89
|
end
|
|
87
90
|
|
|
88
91
|
def refreshed_session(binding, notifications)
|
|
89
|
-
|
|
92
|
+
parse_refresh_session(refresh_payload(binding, notifications))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def parse_refresh_session(payload)
|
|
96
|
+
owned_complete_session(build_session(payload))
|
|
90
97
|
rescue KeyError, TypeError, NoMethodError, ArgumentError => e
|
|
91
98
|
raise Error::TransportError, INCOMPLETE_SESSION, cause: e
|
|
92
99
|
end
|
|
@@ -124,16 +124,7 @@ module Volcano
|
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
def access_token_session_id(access_token)
|
|
127
|
-
|
|
128
|
-
return unless parts.length == 3
|
|
129
|
-
|
|
130
|
-
encoded = parts.fetch(1).tr('-_', '+/')
|
|
131
|
-
padding = '=' * (-encoded.length % 4)
|
|
132
|
-
payload = JSON.parse((encoded + padding).unpack1('m0'))
|
|
133
|
-
session_id = payload['session_id']
|
|
134
|
-
session_id if session_id.is_a?(String) && !session_id.empty?
|
|
135
|
-
rescue ArgumentError, JSON::ParserError
|
|
136
|
-
nil
|
|
127
|
+
SessionCredentials.session_id(access_token)
|
|
137
128
|
end
|
|
138
129
|
end
|
|
139
130
|
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Volcano
|
|
4
|
+
# Revokes the captured server session and clears its local lineage.
|
|
5
|
+
class Auth
|
|
6
|
+
def sign_out
|
|
7
|
+
binding = @client.capture_session_binding
|
|
8
|
+
return unless binding.last
|
|
9
|
+
|
|
10
|
+
notifications = []
|
|
11
|
+
@refresh_lock.synchronize { sign_out_captured(binding, notifications) }
|
|
12
|
+
ensure
|
|
13
|
+
notifications&.each(&:call)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def sign_out_captured(binding, notifications)
|
|
19
|
+
generation, lineage, current = revocation_binding(binding)
|
|
20
|
+
error = revocation_error(current)
|
|
21
|
+
lineage = nil unless access_token_session_id(current.access_token)
|
|
22
|
+
cleared = @client.clear_session_if_current?(generation, lineage: lineage, notifications: notifications)
|
|
23
|
+
raise Error::SessionChangedError, cause: error unless cleared
|
|
24
|
+
|
|
25
|
+
raise error if error
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def revocation_binding(binding)
|
|
29
|
+
active = @client.capture_session_binding
|
|
30
|
+
active.last && active[1] == binding[1] ? active : binding
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def logout_response(refresh_token)
|
|
34
|
+
Transport.invoke do
|
|
35
|
+
@transport.auth_logout(
|
|
36
|
+
authorization: @client.anon_token,
|
|
37
|
+
refresh_token: refresh_token
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def revocation_error(session)
|
|
43
|
+
session_id = access_token_session_id(session.access_token)
|
|
44
|
+
return revoke_access_session(session, session_id) if session_id
|
|
45
|
+
return unless session.refresh_token
|
|
46
|
+
|
|
47
|
+
Transport.body(logout_response(session.refresh_token), 204)
|
|
48
|
+
nil
|
|
49
|
+
rescue Error::VolcanoError => e
|
|
50
|
+
e
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def revoke_access_session(session, session_id)
|
|
54
|
+
error = delete_session_error(session.access_token, session_id)
|
|
55
|
+
return error unless error&.status == 401 && session.refresh_token
|
|
56
|
+
|
|
57
|
+
refreshed = parse_refresh_session(Transport.body(refresh_response(session.refresh_token), 200))
|
|
58
|
+
SessionCredentials.validate_refresh(session, refreshed)
|
|
59
|
+
delete_session_error(refreshed.access_token, session_id)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/volcano/auth_state.rb
CHANGED
|
@@ -24,11 +24,11 @@ module Volcano
|
|
|
24
24
|
CALLBACK_FAILURES = [Exception].freeze
|
|
25
25
|
private_constant :CALLBACK_FAILURES
|
|
26
26
|
|
|
27
|
-
def initialize
|
|
27
|
+
def initialize(session: nil)
|
|
28
28
|
@mutex = Mutex.new
|
|
29
29
|
@generation = 0
|
|
30
30
|
@lineage = 0
|
|
31
|
-
@session =
|
|
31
|
+
@session = session
|
|
32
32
|
@callbacks = {}
|
|
33
33
|
@next_callback_id = 0
|
|
34
34
|
@notifications = []
|
|
@@ -48,9 +48,9 @@ module Volcano
|
|
|
48
48
|
drain_notifications if dispatch
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
def store_if_current?(session, generation, event: :signed_in, notifications: nil)
|
|
51
|
+
def store_if_current?(session, generation, event: :signed_in, notifications: nil, lineage: nil)
|
|
52
52
|
dispatch = @mutex.synchronize do
|
|
53
|
-
return false unless generation == @generation
|
|
53
|
+
return false unless lineage.nil? ? generation == @generation : lineage == @lineage
|
|
54
54
|
|
|
55
55
|
enqueue_notification(replace(session, event), event, session)
|
|
56
56
|
end
|
|
@@ -63,9 +63,8 @@ module Volcano
|
|
|
63
63
|
def update_user_if_current?(user, generation)
|
|
64
64
|
@mutex.synchronize do
|
|
65
65
|
return false unless generation == @generation && @session
|
|
66
|
-
raise Error::AuthenticationError, 'Profile belongs to a different user' unless user['id'] == @session.user_id
|
|
67
66
|
|
|
68
|
-
@session =
|
|
67
|
+
@session = SessionCredentials.with_user(@session, user)
|
|
69
68
|
true
|
|
70
69
|
end
|
|
71
70
|
end
|
|
@@ -82,6 +81,7 @@ module Volcano
|
|
|
82
81
|
private
|
|
83
82
|
|
|
84
83
|
def replace(session, event)
|
|
84
|
+
SessionCredentials.validate_refresh(@session, session) if event == :token_refreshed
|
|
85
85
|
@session = session
|
|
86
86
|
@generation += 1
|
|
87
87
|
@lineage += 1 unless event == :token_refreshed
|
data/lib/volcano/client.rb
CHANGED
|
@@ -19,13 +19,14 @@ module Volcano
|
|
|
19
19
|
api_url: 'https://api.volcano.dev',
|
|
20
20
|
service_key: nil,
|
|
21
21
|
timeout: 60,
|
|
22
|
-
**
|
|
22
|
+
**options
|
|
23
23
|
)
|
|
24
|
-
|
|
24
|
+
session = SessionCredentials.build(options.delete(:access_token), options.delete(:refresh_token))
|
|
25
|
+
transport, socket_factory, reconnect_delay = extract_adapters(options)
|
|
25
26
|
@api_url = api_url.delete_suffix('/')
|
|
26
27
|
@anon_key = anon_key
|
|
27
28
|
@service_key = service_key
|
|
28
|
-
@auth_state = AuthState.new
|
|
29
|
+
@auth_state = AuthState.new(session: session)
|
|
29
30
|
@transport = transport || GeneratedTransport.new(api_url: @api_url, timeout: timeout)
|
|
30
31
|
initialize_facades(socket_factory, reconnect_delay)
|
|
31
32
|
end
|
|
@@ -81,8 +82,8 @@ module Volcano
|
|
|
81
82
|
@auth_state.store_if_current?(session, generation, event: event, notifications: notifications)
|
|
82
83
|
end
|
|
83
84
|
|
|
84
|
-
def clear_session_if_current?(generation, event: :signed_out, notifications: nil)
|
|
85
|
-
@auth_state.store_if_current?(nil, generation, event: event, notifications: notifications)
|
|
85
|
+
def clear_session_if_current?(generation, event: :signed_out, notifications: nil, lineage: nil)
|
|
86
|
+
@auth_state.store_if_current?(nil, generation, event: event, notifications: notifications, lineage: lineage)
|
|
86
87
|
end
|
|
87
88
|
|
|
88
89
|
def subscribe_auth_state_change(...)
|
|
@@ -13,17 +13,18 @@ module Volcano
|
|
|
13
13
|
session = session_for_lineage(session_lineage)
|
|
14
14
|
protocol = build_protocol(socket)
|
|
15
15
|
result = protocol.connect(token: session.access_token)
|
|
16
|
-
|
|
17
|
-
activate_protocol(protocol,
|
|
16
|
+
session_for_lineage(session_lineage)
|
|
17
|
+
activate_protocol(protocol, session_lineage, result)
|
|
18
18
|
rescue StandardError => e
|
|
19
19
|
handle_connection_failure(socket, e)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def active_session_lineage
|
|
23
23
|
_, lineage, session = @client.capture_session_binding
|
|
24
|
-
|
|
24
|
+
raise Error::AuthenticationError, 'No active session' unless session
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
session_for_lineage(lineage)
|
|
27
|
+
lineage
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def session_for_lineage(expected_lineage)
|
|
@@ -33,9 +34,9 @@ module Volcano
|
|
|
33
34
|
raise Error::SessionChangedError
|
|
34
35
|
end
|
|
35
36
|
|
|
36
|
-
def activate_protocol(protocol,
|
|
37
|
+
def activate_protocol(protocol, session_lineage, result)
|
|
37
38
|
@protocol = protocol
|
|
38
|
-
@
|
|
39
|
+
@protocol_session_lineage = session_lineage
|
|
39
40
|
protocol_connected(result)
|
|
40
41
|
protocol
|
|
41
42
|
end
|
|
@@ -55,7 +56,7 @@ module Volcano
|
|
|
55
56
|
ensure
|
|
56
57
|
@manual_disconnect = false
|
|
57
58
|
@channels.each_value(&:mark_closed)
|
|
58
|
-
@
|
|
59
|
+
@protocol_session_lineage = nil
|
|
59
60
|
end
|
|
60
61
|
|
|
61
62
|
def handle_connection_failure(socket, error)
|
|
@@ -117,7 +117,7 @@ module Volcano
|
|
|
117
117
|
def reset_after_protocol_loss
|
|
118
118
|
protocol = @protocol
|
|
119
119
|
@protocol = nil
|
|
120
|
-
@
|
|
120
|
+
@protocol_session_lineage = nil
|
|
121
121
|
@channels.each_value { |channel| channel.protocol_lost(protocol) } if protocol
|
|
122
122
|
end
|
|
123
123
|
end
|
|
@@ -30,15 +30,14 @@ module Volcano
|
|
|
30
30
|
|
|
31
31
|
def capture_protocol_session
|
|
32
32
|
generation, lineage, session = capture_session_binding
|
|
33
|
-
return [generation, lineage, session] if session &&
|
|
33
|
+
return [generation, lineage, session] if session && lineage == @protocol_session_lineage
|
|
34
34
|
|
|
35
35
|
raise Error::SessionChangedError
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def access_token_for_protocol_lineage(expected_lineage)
|
|
39
39
|
_, lineage, session = capture_session_binding
|
|
40
|
-
return session.access_token if session && lineage == expected_lineage &&
|
|
41
|
-
session.user_id == @protocol_user_id
|
|
40
|
+
return session.access_token if session && lineage == expected_lineage && lineage == @protocol_session_lineage
|
|
42
41
|
|
|
43
42
|
raise Error::SessionChangedError
|
|
44
43
|
end
|
data/lib/volcano/realtime.rb
CHANGED
data/lib/volcano/session.rb
CHANGED
|
@@ -9,9 +9,78 @@ module Volcano
|
|
|
9
9
|
end
|
|
10
10
|
private_constant :SESSION_USER_CODER
|
|
11
11
|
|
|
12
|
-
#
|
|
12
|
+
# Owns credential snapshots and preserves validated identity during refresh.
|
|
13
|
+
module SessionCredentials
|
|
14
|
+
def self.build(access_token, refresh_token)
|
|
15
|
+
raise ArgumentError, 'refresh_token requires access_token' if access_token.nil? && !refresh_token.nil?
|
|
16
|
+
return if access_token.nil?
|
|
17
|
+
|
|
18
|
+
Session.new(access_token: credential(access_token, :access_token),
|
|
19
|
+
refresh_token: credential(refresh_token, :refresh_token))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.credential(value, name)
|
|
23
|
+
return if value.nil?
|
|
24
|
+
|
|
25
|
+
raise ArgumentError, "#{name} must be a non-empty string" unless value.is_a?(String) && !value.strip.empty?
|
|
26
|
+
|
|
27
|
+
value.dup.freeze
|
|
28
|
+
end
|
|
29
|
+
private_class_method :credential
|
|
30
|
+
|
|
31
|
+
def self.validate_refresh_source(current)
|
|
32
|
+
return if current.user_id || session_id(current.access_token)
|
|
33
|
+
|
|
34
|
+
raise Error::AuthenticationError, 'Cannot refresh unknown identity without a session identifier'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.validate_refresh(current, refreshed)
|
|
38
|
+
return unless current
|
|
39
|
+
|
|
40
|
+
validate_refresh_source(current)
|
|
41
|
+
expected = session_id(current.access_token)
|
|
42
|
+
if expected && expected != session_id(refreshed&.access_token)
|
|
43
|
+
raise Error::AuthenticationError, 'Refreshed credentials belong to a different server session'
|
|
44
|
+
end
|
|
45
|
+
return unless current.user_id && current.user_id != refreshed&.user_id
|
|
46
|
+
|
|
47
|
+
raise Error::AuthenticationError, 'Refreshed session belongs to a different user'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Untrusted continuity constraint, never authenticated user identity.
|
|
51
|
+
def self.session_id(access_token)
|
|
52
|
+
payload = token_payload(access_token)
|
|
53
|
+
return unless payload.is_a?(Hash)
|
|
54
|
+
|
|
55
|
+
value = payload['session_id']
|
|
56
|
+
value.downcase if value.is_a?(String) && value.match?(/\A[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\z/i)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.token_payload(access_token)
|
|
60
|
+
return unless access_token.is_a?(String)
|
|
61
|
+
|
|
62
|
+
parts = access_token.split('.')
|
|
63
|
+
return unless parts.length == 3
|
|
64
|
+
|
|
65
|
+
encoded = parts.fetch(1).tr('-_', '+/')
|
|
66
|
+
JSON.parse((encoded + ('=' * (-encoded.length % 4))).unpack1('m0'))
|
|
67
|
+
rescue ArgumentError, JSON::ParserError
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
private_class_method :token_payload
|
|
71
|
+
|
|
72
|
+
def self.with_user(session, user)
|
|
73
|
+
user_id = (session.user_id || user.fetch('id')).dup.freeze
|
|
74
|
+
raise Error::AuthenticationError, 'Profile belongs to a different user' unless user['id'] == user_id
|
|
75
|
+
|
|
76
|
+
Session.new(**session.to_h, user_id: user_id, user: user)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
private_constant :SessionCredentials
|
|
80
|
+
|
|
81
|
+
# Local credentials; refresh credentials and user identity may be unknown.
|
|
13
82
|
Session = Data.define(:access_token, :refresh_token, :user_id, :user) do
|
|
14
|
-
def initialize(access_token:, refresh_token
|
|
83
|
+
def initialize(access_token:, refresh_token: nil, user_id: nil, user: nil)
|
|
15
84
|
super(access_token:, refresh_token:, user_id:, user: immutable_user(user))
|
|
16
85
|
end
|
|
17
86
|
|
data/lib/volcano/version.rb
CHANGED
data/lib/volcano.rb
CHANGED
|
@@ -13,6 +13,7 @@ require_relative 'volcano/redaction'
|
|
|
13
13
|
require_relative 'volcano/transport'
|
|
14
14
|
require_relative 'volcano/generated_transport'
|
|
15
15
|
require_relative 'volcano/auth'
|
|
16
|
+
require_relative 'volcano/auth_sign_out'
|
|
16
17
|
require_relative 'volcano/auth_refresh'
|
|
17
18
|
require_relative 'volcano/auth_sign_up'
|
|
18
19
|
require_relative 'volcano/sign_up_result'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: volcano-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kong
|
|
@@ -145,6 +145,7 @@ files:
|
|
|
145
145
|
- lib/volcano/auth_reset_password.rb
|
|
146
146
|
- lib/volcano/auth_reset_password_for_email.rb
|
|
147
147
|
- lib/volcano/auth_sessions.rb
|
|
148
|
+
- lib/volcano/auth_sign_out.rb
|
|
148
149
|
- lib/volcano/auth_sign_up.rb
|
|
149
150
|
- lib/volcano/auth_state.rb
|
|
150
151
|
- lib/volcano/auth_update_user.rb
|