setsuzoku 0.11.9 → 0.12.54

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +5 -13
  3. data/lib/setsuzoku.rb +1 -2
  4. data/lib/setsuzoku/api_strategy.rb +6 -4
  5. data/lib/setsuzoku/auth_strategy.rb +28 -14
  6. data/lib/setsuzoku/credential.rb +10 -0
  7. data/lib/setsuzoku/has_config_context.rb +27 -0
  8. data/lib/setsuzoku/pluggable.rb +6 -4
  9. data/lib/setsuzoku/plugin.rb +1 -1
  10. data/lib/setsuzoku/rspec/dynamic_spec_helper.rb +4 -3
  11. data/lib/setsuzoku/service.rb +1 -1
  12. data/lib/setsuzoku/service/web_service.rb +6 -2
  13. data/lib/setsuzoku/service/web_service/api_strategies/rest_strategy.rb +35 -16
  14. data/lib/setsuzoku/service/web_service/api_strategy.rb +13 -8
  15. data/lib/setsuzoku/service/web_service/auth_strategies/basic_auth_strategy.rb +6 -4
  16. data/lib/setsuzoku/service/web_service/auth_strategies/custom_auth_strategy.rb +66 -0
  17. data/lib/setsuzoku/service/web_service/auth_strategies/o_auth_strategy.rb +25 -88
  18. data/lib/setsuzoku/service/web_service/auth_strategies/strategy_can_use_tokens.rb +175 -0
  19. data/lib/setsuzoku/service/web_service/auth_strategy.rb +1 -14
  20. data/lib/setsuzoku/service/web_service/credentials/basic_auth_credential.rb +3 -3
  21. data/lib/setsuzoku/service/web_service/credentials/custom_auth_credential.rb +46 -0
  22. data/lib/setsuzoku/service/web_service/credentials/o_auth_credential.rb +41 -35
  23. data/lib/setsuzoku/service/web_service/credentials/uses_credential_token.rb +68 -0
  24. data/lib/setsuzoku/service/web_service/service.rb +2 -1
  25. data/lib/setsuzoku/version.rb +1 -1
  26. data/setsuzoku.gemspec +0 -1
  27. data/sorbet/rbi/gems/activesupport.rbi +4 -54
  28. data/sorbet/rbi/gems/i18n.rbi +2 -2
  29. data/sorbet/rbi/gems/rspec-core.rbi +3 -155
  30. data/sorbet/rbi/gems/rspec-expectations.rbi +2 -6
  31. data/sorbet/rbi/gems/rspec-mocks.rbi +1 -5
  32. data/sorbet/rbi/gems/rspec-support.rbi +63 -74
  33. data/sorbet/rbi/gems/rspec.rbi +1 -1
  34. data/sorbet/rbi/gems/webmock.rbi +1 -5
  35. data/sorbet/rbi/hidden-definitions/hidden.rbi +3651 -619
  36. data/sorbet/rbi/sorbet-typed/lib/activesupport/all/activesupport.rbi +17 -17
  37. data/sorbet/rbi/sorbet-typed/lib/faraday/all/faraday.rbi +685 -0
  38. data/sorbet/rbi/todo.rbi +1 -0
  39. metadata +8 -20
  40. data/lib/setsuzoku/utilities.rb +0 -7
  41. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +0 -8684
  42. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +0 -111
  43. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +0 -543
@@ -8,7 +8,7 @@ module Setsuzoku
8
8
  # The API OAuth Authentication Interface definition.
9
9
  # Any Plugin that implements this must implement all methods required for OAuth.
10
10
  #
11
- # Defines all necessary methods for handling authentication for any authentication strategy.
11
+ # Defines all necessary methods for the basic auth strategy.
12
12
  class BasicAuthStrategy < WebService::AuthStrategy
13
13
  extend T::Sig
14
14
  extend T::Helpers
@@ -27,10 +27,12 @@ module Setsuzoku
27
27
  sig { override.returns(T::Hash[Symbol, T.untyped]) }
28
28
  def auth_headers
29
29
  {
30
+ authorization: {
30
31
  basic_auth: {
31
- username: self.credential.username,
32
- password: self.credential.password
32
+ username: self.credential.username,
33
+ password: self.credential.password
33
34
  }
35
+ }
34
36
  }
35
37
  end
36
38
 
@@ -38,7 +40,7 @@ module Setsuzoku
38
40
  # if the auth credientials are valid
39
41
  #
40
42
  #
41
- # sig { override.returns(T::Boolean) }
43
+ sig { override.returns(T::Boolean) }
42
44
  def auth_credential_valid?
43
45
  true
44
46
  end
@@ -0,0 +1,66 @@
1
+ # typed: ignore
2
+ # frozen_string_literal: true
3
+
4
+ module Setsuzoku
5
+ module Service
6
+ module WebService
7
+ module AuthStrategies
8
+ # The API Custom Authentication Interface definition.
9
+ # Any Plugin that implements this must implement all methods required for Custom auth.
10
+ #
11
+ # Defines all necessary methods for the custom auth strategy.
12
+ class CustomAuthStrategy < WebService::AuthStrategy
13
+ extend T::Sig
14
+ extend T::Helpers
15
+
16
+ include StrategyCanUseTokens
17
+
18
+ def self.required_instance_methods
19
+ []
20
+ end
21
+
22
+ def self.credential_class
23
+ Setsuzoku::Service::WebService::Credentials::CustomAuthCredential
24
+ end
25
+
26
+ #
27
+ # auth_headers
28
+ sig { override.returns(T::Hash[Symbol, T.untyped]) }
29
+ #
30
+ # Any custom auth headers required to perform authenticated requests.
31
+ #
32
+ # @return [Hash] the auth headers.
33
+ def auth_headers
34
+ self.credential.auth_headers
35
+ end
36
+
37
+ #
38
+ # refresh_expired_token!
39
+ sig { override.void }
40
+ #
41
+ # Construct the custom token_request_body and request a token.
42
+ #
43
+ # @return [void]
44
+ def new_token!
45
+ action = :new_token
46
+ body = self.credential.auth_actions[action][:body]
47
+ get_token!(body, action)
48
+ end
49
+
50
+ #
51
+ # refresh_expired_token!
52
+ sig { override.void }
53
+ #
54
+ # Construct the custom token_request_body and request a token.
55
+ #
56
+ # @return [void]
57
+ def refresh_expired_token!
58
+ action = :refresh_token
59
+ body = self.credential.auth_actions[action][:body]
60
+ get_token!(body, :refresh_token)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,4 +1,4 @@
1
- # typed: false
1
+ # typed: ignore
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Setsuzoku
@@ -8,11 +8,13 @@ module Setsuzoku
8
8
  # The API OAuth Authentication Interface definition.
9
9
  # Any Plugin that implements this must implement all methods required for OAuth.
10
10
  #
11
- # Defines all necessary methods for handling authentication for any authentication strategy.
11
+ # Defines all necessary methods for the OAuth auth strategy.
12
12
  class OAuthStrategy < WebService::AuthStrategy
13
13
  extend T::Sig
14
14
  extend T::Helpers
15
15
 
16
+ include StrategyCanUseTokens
17
+
16
18
  def self.required_instance_methods
17
19
  []
18
20
  end
@@ -25,13 +27,18 @@ module Setsuzoku
25
27
  24.hours
26
28
  end
27
29
 
28
- # Any api request headers that this service needs to set.
29
30
  #
30
- # @return [Hash]
31
+ # auth_headers
31
32
  sig { override.returns(T::Hash[Symbol, T.untyped]) }
33
+ #
34
+ # Oauth auth headers required to perform authenticated requests.
35
+ #
36
+ # @return [Hash] the auth headers.
32
37
  def auth_headers
33
38
  {
34
- token: self.credential.token
39
+ authorization: {
40
+ token: self.credential.token
41
+ }
35
42
  }
36
43
  end
37
44
 
@@ -48,97 +55,26 @@ module Setsuzoku
48
55
  code: args[:code]), :new_token)
49
56
  end
50
57
 
51
- # If the auth credentials are valid for this instance and auth_strategy.
52
- #
53
- # If the token is invalid we should refresh it. And verify that the credentials are now valid.
54
- # Otherwise the credentials are already valid.
55
- #
56
- # @return [Boolean] true if the auth token is valid for the auth_strategy.
57
- sig { override.returns(T::Boolean) }
58
- def auth_credential_valid?
59
- if token_is_invalid?
60
- refresh_expired_token!
61
- !token_is_invalid?
62
- else
63
- true
64
- end
65
- end
66
-
67
- private
68
-
69
- # Determine whether the token is no longer valid.
70
- #
71
- # @return [Boolean] true if the token is invalid.
72
- sig { returns(T::Boolean) }
73
- def token_is_invalid?
74
- active = self.credential.status != 'disabled'
75
- active && !self.credential.expires_on.blank? &&
76
- !self.credential.refresh_token.blank? &&
77
- (self.credential.expires_on < refresh_before_expiration_time)
78
- end
79
-
80
- sig { returns(DateTime) }
81
- def refresh_before_expiration_time
82
- 45.minutes.from_now.to_datetime
83
- end
84
-
85
58
  # Exchange refresh_token for a new token and expires_on.
86
59
  #
87
60
  # @return [Boolean] true if the credential was refreshed successfully
88
- sig { void }
61
+ sig { override.void }
89
62
  def refresh_expired_token!
90
63
  get_token!(params(grant_type: 'refresh_token',
91
64
  refresh_token: self.credential.refresh_token), :refresh_token)
92
65
  end
93
66
 
94
- # Exchange code for token, refresh_token and expires_on
95
- #
96
- # @return void
97
- sig { params(code: String, redirect_url: String).void }
98
- def custom_token!(code: nil, redirect_url: nil)
99
- get_token!(params(grant_type: 'authorization_code',
100
- code: code,
101
- redirect_uri: redirect_url), :refresh_token)
102
- end
67
+ private
103
68
 
104
- # Exchange code for a new token via POST request to API token url,
105
- # and set token, expiry, and status on the integration
106
69
  #
107
- # @param [Hash] body the request body for the token POST request
70
+ # uses_token_by_default?
71
+ sig { returns(T::Boolean) }
108
72
  #
109
- # @return void
110
- sig { params(body: T::Hash[Symbol, String], action: Symbol).void }
111
- def get_token!(body, action)
112
- success = false
113
- request = self.api_strategy.request_class.new(action: action, body: body, without_headers: true)
114
-
115
- resp = self.api_strategy.call_external_api(request: request, strategy: :auth)
116
-
117
- attrs = {}
118
- if resp.data && resp.data[:access_token]
119
- attrs[:status] = 'active'
120
- attrs[:token] = resp.data[:access_token]
121
- attrs[:refresh_token] = resp.data[:refresh_token] if resp.data.key?(:refresh_token)
122
- attrs[:expires_on] = resp.data[:expires_in].to_i.seconds.from_now if resp.data[:expires_in]
123
-
124
- plugin_attrs = self.plugin.credential_fields_to_update(resp) if self.plugin.respond_to?(:credential_fields_to_update)
125
- attrs.merge!(plugin_attrs)
126
- else
127
- attrs[:status] = 'error'
128
- end
129
-
130
- # Only save Setsuzoku known fields, and any additional attributes the plugin specifies
131
- # in credential_fields_to_update.
132
- if self.credential.respond_to?(:"update_columns")
133
- # we issue an update_columns instead of a save/update_attributes
134
- # so as to only mutate these attributes
135
- # and not any other fields that may have been set for the credential
136
- save = self.credential.update_columns(attrs)
137
- self.credential.touch if save && self.credential.respond_to?(:"touch")
138
- save && resp.success
139
- else
140
- resp.success
141
- end
73
+ # OAuth auth_strategy always uses a token.
74
+ #
75
+ # @return [Boolean] if the auth_strategy uses a token or not.
76
+ def uses_token_by_default?
77
+ true
142
78
  end
143
79
 
144
80
  # Add some default params to the params hash.
@@ -150,12 +86,13 @@ module Setsuzoku
150
86
  def params(params)
151
87
  if params.key?(:redirect_uri)
152
88
  params.merge(client_id: self.credential.client_id,
153
- client_secret: self.credential.client_secret)
89
+ client_secret: self.credential.client_secret
90
+ )
154
91
  else
155
92
  params.merge(client_id: self.credential.client_id,
156
93
  client_secret: self.credential.client_secret,
157
- redirect_uri: self.credential.redirect_url_override.nil? ? self.credential.redirect_url : self.credential.redirect_url_override)
158
-
94
+ redirect_uri: self.credential.redirect_url
95
+ )
159
96
  end
160
97
  end
161
98
  end
@@ -0,0 +1,175 @@
1
+ # typed: ignore
2
+ # frozen_string_literal: true
3
+
4
+ module Setsuzoku
5
+ module Service
6
+ module WebService
7
+ module AuthStrategies
8
+ # The API OAuth Authentication Interface definition.
9
+ # Any Plugin that implements this must implement all methods required for OAuth.
10
+ #
11
+ # Defines all necessary methods for handling authentication for any authentication strategy.
12
+ module StrategyCanUseTokens
13
+ extend T::Sig
14
+ extend T::Helpers
15
+
16
+ #
17
+ # refresh_expired_token!
18
+ sig { abstract.void }
19
+ #
20
+ # Construct the custom token_request_body and request a token.
21
+ #
22
+ # @return [void]
23
+ def new_token!; end
24
+
25
+ #
26
+ # refresh_expired_token!
27
+ sig { abstract.void }
28
+ #
29
+ # Construct the custom token_request_body and request a token.
30
+ #
31
+ # @return [void]
32
+ def refresh_expired_token!; end
33
+
34
+ #
35
+ # auth_credential_valid?
36
+ sig { returns(T::Boolean) }
37
+ #
38
+ # If the auth credentials are valid for this instance and auth_strategy.
39
+ #
40
+ # If the token is invalid we should refresh it. And verify that the credentials are now valid.
41
+ # Otherwise the credentials are already valid.
42
+ #
43
+ # @return [Boolean] true if the auth token is valid for the auth_strategy.
44
+ def auth_credential_valid?
45
+ validate_token_credential!
46
+ end
47
+
48
+ private
49
+
50
+ #
51
+ # validate_token_credential!
52
+ sig { returns(T::Boolean) }
53
+ #
54
+ # If the auth credentials are valid for this instance and auth_strategy.
55
+ #
56
+ # If the token is invalid we should refresh it. And verify that the credentials are now valid.
57
+ # Otherwise the credentials are already valid.
58
+ #
59
+ # @return [Boolean] true if the auth token is valid for the auth_strategy.
60
+ def validate_token_credential!
61
+ if self.credential.status == 'disabled'
62
+ false
63
+ elsif uses_token?
64
+ if token_is_invalid?
65
+ self.refresh_expired_token!
66
+ !token_is_invalid?
67
+ else
68
+ true
69
+ end
70
+ else
71
+ true
72
+ end
73
+ end
74
+
75
+ #
76
+ # uses_token?
77
+ sig { returns(T::Boolean) }
78
+ #
79
+ # If the plugin's auth_strategy should use a token.
80
+ #
81
+ # @return [Boolean] if the auth_strategy uses a token or not.
82
+ def uses_token?
83
+ uses_token_by_default? || !!self.credential&.uses_token?
84
+ end
85
+
86
+ #
87
+ # uses_token_by_default?
88
+ sig { returns(T::Boolean) }
89
+ #
90
+ # If the plugin's auth_strategy should use a token by default.
91
+ # Defaulted to false, OAuth will default to true.
92
+ #
93
+ # @return [Boolean] if the auth_strategy uses a token or not.
94
+ def uses_token_by_default?
95
+ false
96
+ end
97
+
98
+ #
99
+ # refresh_expired_token!
100
+ sig { abstract.void }
101
+ #
102
+ # Exchange refresh_token for a new token and expires_on.
103
+ #
104
+ # @return [Boolean] true if the credential was refreshed successfully
105
+ def refresh_expired_token!; end
106
+
107
+ #
108
+ # token_is_invalid?
109
+ sig { returns(T::Boolean) }
110
+ #
111
+ # Determine whether the token is no longer valid.
112
+ #
113
+ # @return [Boolean] true if the token is invalid.
114
+ def token_is_invalid?
115
+ inactive = self.credential.status != 'active'
116
+ expired = self.credential.expires_on.present? &&
117
+ self.credential.refresh_token.present? &&
118
+ (self.credential.expires_on < refresh_before_expiration_time)
119
+
120
+ inactive || expired
121
+ end
122
+
123
+ sig { returns(DateTime) }
124
+ def refresh_before_expiration_time
125
+ 45.minutes.from_now.to_datetime
126
+ end
127
+
128
+ #
129
+ # get_token!
130
+ sig { params(body: T::Hash[Symbol, String], action: Symbol).void }
131
+ #
132
+ # Exchange code for a new token via POST request to API token url,
133
+ # and set token, expiry, and status on the integration
134
+ #
135
+ # @param [Hash] body the request body for the token POST request
136
+ #
137
+ # @return void
138
+ def get_token!(body, action)
139
+ success = false
140
+ request = self.api_strategy.request_class.new(action: action, body: body, without_headers: true)
141
+
142
+ resp = self.api_strategy.call_external_api(request: request, strategy: :auth)
143
+
144
+ return false unless resp.success
145
+
146
+ attrs = self.credential.token_attributes_to_assign(resp)
147
+ attrs[:status] = if attrs[:token]
148
+ 'active'
149
+ else
150
+ 'error'
151
+ end
152
+
153
+ # Assign any additional attributes the plugin's credential needs to know about.
154
+ # E.g. the extension for a phone_number.
155
+ plugin_attrs = self.credential.additional_attributes_to_assign(resp) if self.plugin.respond_to?(:credential_fields_to_update)
156
+ attrs.merge!(plugin_attrs) if plugin_attrs
157
+
158
+ # Only save Setsuzoku known fields, and any additional attributes the plugin specifies
159
+ # in credential_fields_to_update.
160
+ if self.credential.respond_to?(:"update_columns")
161
+ # we issue an update_columns instead of a save/update_attributes
162
+ # so as to only mutate these attributes
163
+ # and not any other fields that may have been set for the credential
164
+ save = self.credential.update_columns(attrs)
165
+ self.credential.touch if save && self.credential.respond_to?(:"touch")
166
+ save
167
+ else
168
+ true
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: false
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Setsuzoku
@@ -27,19 +27,6 @@ module Setsuzoku
27
27
  extend T::Helpers
28
28
  abstract!
29
29
 
30
- # All auth actions that are implemented.
31
- #
32
- # @return [Hash] all auth endpoint definitions for the API.
33
- sig { abstract.returns(T::Hash[T.untyped, T.untyped]) }
34
- def auth_actions; end
35
-
36
- # The base auth url for the plugin.
37
- #
38
- # @return [String] the auth url.
39
- sig { overridable.returns(String) }
40
- def auth_base_url
41
- self.plugin.api_base_url
42
- end
43
30
  end
44
31
  end
45
32
  end