workos 2.1.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.semaphore/semaphore.yml +13 -39
  3. data/Gemfile.lock +2 -2
  4. data/README.md +4 -0
  5. data/lib/workos/challenge.rb +55 -0
  6. data/lib/workos/client.rb +2 -0
  7. data/lib/workos/connection.rb +1 -0
  8. data/lib/workos/deprecated_hash_wrapper.rb +76 -0
  9. data/lib/workos/directory.rb +1 -0
  10. data/lib/workos/directory_group.rb +5 -2
  11. data/lib/workos/directory_sync.rb +9 -8
  12. data/lib/workos/directory_user.rb +4 -1
  13. data/lib/workos/errors.rb +3 -1
  14. data/lib/workos/factor.rb +59 -0
  15. data/lib/workos/hash_provider.rb +19 -0
  16. data/lib/workos/mfa.rb +165 -0
  17. data/lib/workos/organization.rb +1 -0
  18. data/lib/workos/profile.rb +1 -0
  19. data/lib/workos/profile_and_token.rb +1 -0
  20. data/lib/workos/types/challenge_struct.rb +18 -0
  21. data/lib/workos/types/factor_struct.rb +19 -0
  22. data/lib/workos/types/passwordless_session_struct.rb +2 -0
  23. data/lib/workos/types/verify_factor_struct.rb +13 -0
  24. data/lib/workos/types.rb +3 -0
  25. data/lib/workos/verify_factor.rb +40 -0
  26. data/lib/workos/version.rb +1 -1
  27. data/lib/workos/webhook.rb +1 -0
  28. data/lib/workos/webhooks.rb +9 -7
  29. data/lib/workos.rb +7 -0
  30. data/spec/lib/workos/directory_sync_spec.rb +4 -0
  31. data/spec/lib/workos/mfa_spec.rb +262 -0
  32. data/spec/lib/workos/sso_spec.rb +0 -2
  33. data/spec/lib/workos/webhooks_spec.rb +1 -1
  34. data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_generic_valid.yml +82 -0
  35. data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_sms_valid.yml +82 -0
  36. data/spec/support/fixtures/vcr_cassettes/mfa/challenge_factor_totp_valid.yml +82 -0
  37. data/spec/support/fixtures/vcr_cassettes/mfa/delete_factor.yml +80 -0
  38. data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_generic_valid.yml +82 -0
  39. data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_sms_valid.yml +82 -0
  40. data/spec/support/fixtures/vcr_cassettes/mfa/enroll_factor_totp_valid.yml +82 -0
  41. data/spec/support/fixtures/vcr_cassettes/mfa/get_factor_invalid.yml +82 -0
  42. data/spec/support/fixtures/vcr_cassettes/mfa/get_factor_valid.yml +82 -0
  43. data/spec/support/fixtures/vcr_cassettes/mfa/verify_factor_generic_expired.yml +84 -0
  44. data/spec/support/fixtures/vcr_cassettes/mfa/verify_factor_generic_invalid.yml +84 -0
  45. data/spec/support/fixtures/vcr_cassettes/mfa/verify_factor_generic_valid.yml +82 -0
  46. data/spec/support/fixtures/vcr_cassettes/mfa/verify_factor_generic_valid_is_false.yml +82 -0
  47. metadata +40 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0500b789496692e53bc6d47d80a21a0b8b802325e1e0f876fe0b94a775aa4f05
4
- data.tar.gz: a7e8e350e7fb1336496e9a09ee7543a120e1b6ed62cc60dffbe1b4ccd2dd4712
3
+ metadata.gz: 286a2f14af16bfc7b9c77e7938c2b8d7366f4a03f9fca4c7892f85f60562e433
4
+ data.tar.gz: 8970807084e7022beb9bb1523c270e645c340e42e452d7f0d7ea0d64958cf1ea
5
5
  SHA512:
6
- metadata.gz: 549c9210c2d765b2d6f264e62f285f7b96c9225e53724798216eb08167be5451825a729f36273fbda7fb713b9a1db49025b3cc6a308a98b969ca0a3631c8ffd9
7
- data.tar.gz: 4a3fdf8d50681db812a0de37c56d93b03c6bb194a892280cfc9d287612ba7494a1bd777f92b28538b12d978b0a1dc354ca7c82e12fd1707c440643c7215685cb
6
+ metadata.gz: e4d3af795ee51a5cb807fda2bdffc2217e0150ec2f4ffe51fb86daab6e376ecd240f03f1b204db2a72265ebc61d5a9c227a13924a262bb6cf7011ce9c87df177
7
+ data.tar.gz: a8977f9bff244978c9c1935e46a411e4e564a86ed51d7523780feab31212857771813190c523f64d5640f13b393ba5f5a3df3ced5729a7ad34df0cdfa3b6014e
@@ -31,45 +31,19 @@ blocks:
31
31
  - name: codecov-workos-ruby
32
32
  jobs:
33
33
  - name: Ruby 1.9.3
34
- commands:
35
- - checkout
36
- - sem-version ruby 1.9.3-p551
37
- - bundle install
38
- - bundle exec rspec
39
- - name: Ruby 2.0.0
40
- commands:
41
- - checkout
42
- - sem-version ruby 2.0.0-p648
43
- - bundle install
44
- - bundle exec rspec
45
- - name: Ruby 2.3.4
46
- commands:
47
- - checkout
48
- - sem-version ruby 2.3.4
49
- - bundle install
50
- - bundle exec rspec
51
- - name: Ruby 2.5.7
52
- commands:
53
- - checkout
54
- - sem-version ruby 2.5.7
55
- - bundle install
56
- - bundle exec rspec
57
- - name: Ruby 2.6.5
58
- commands:
59
- - checkout
60
- - sem-version ruby 2.6.5
61
- - bundle install
62
- - bundle exec rspec
63
- - name: Ruby 2.7.3
64
- commands:
65
- - checkout
66
- - sem-version ruby 2.7.3
67
- - bundle install
68
- - bundle exec rspec
69
- - name: Ruby 3.0.2
70
- commands:
71
- - checkout
72
- - sem-version ruby 3.0.2
34
+ matrix:
35
+ - env_var: RUBY_VERSION
36
+ values:
37
+ - 1.9.3-p551
38
+ - 2.0.0-p648
39
+ - 2.3.4
40
+ - 2.5.7
41
+ - 2.6.5
42
+ - 2.7.3
43
+ - 3.0.2
44
+ commands:
45
+ - checkout
46
+ - sem-version ruby $RUBY_VERSION
73
47
  - bundle install
74
48
  - bundle exec rspec
75
49
  promotions:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- workos (2.1.0)
4
+ workos (2.2.1)
5
5
  sorbet-runtime (~> 0.5)
6
6
 
7
7
  GEM
@@ -60,7 +60,7 @@ GEM
60
60
  simplecov_json_formatter (0.1.2)
61
61
  sorbet (0.5.6388)
62
62
  sorbet-static (= 0.5.6388)
63
- sorbet-runtime (0.5.9300)
63
+ sorbet-runtime (0.5.9944)
64
64
  sorbet-static (0.5.6388-universal-darwin-14)
65
65
  sorbet-static (0.5.6388-universal-darwin-15)
66
66
  sorbet-static (0.5.6388-universal-darwin-16)
data/README.md CHANGED
@@ -38,6 +38,10 @@ Or, you may set the key yourself, such as in an initializer in your application
38
38
  WorkOS.key = '[your api key]'
39
39
  ```
40
40
 
41
+ ## SDK Versioning
42
+
43
+ For our SDKs WorkOS follows a Semantic Versioning ([SemVer](https://semver.org/)) process where all releases will have a version X.Y.Z (like 1.0.0) pattern wherein Z would be a bug fix (e.g., 1.0.1), Y would be a minor release (1.1.0) and X would be a major release (2.0.0). We permit any breaking changes to only be released in major versions and strongly recommend reading changelogs before making any major version upgrades.
44
+
41
45
  ## More Information
42
46
 
43
47
  * [Single Sign-On Guide](https://workos.com/docs/sso/guide)
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ module WorkOS
5
+ # The Challnge class provides a lightweight wrapper around
6
+ # a WorkOS DirectoryUser resource. This class is not meant to be instantiated
7
+ # in DirectoryUser space, and is instantiated internally but exposed.
8
+ class Challenge
9
+ include HashProvider
10
+ extend T::Sig
11
+
12
+ attr_accessor :id, :object, :expires_at, :code, :authentication_factor_id, :updated_at, :created_at
13
+
14
+ sig { params(json: String).void }
15
+ def initialize(json)
16
+ raw = parse_json(json)
17
+ @id = T.let(raw.id, String)
18
+ @object = T.let(raw.object, String)
19
+ @expires_at = raw.expires_at
20
+ @code = raw.code
21
+ @authentication_factor_id = T.let(raw.authentication_factor_id, String)
22
+ @created_at = T.let(raw.created_at, String)
23
+ @updated_at = T.let(raw.updated_at, String)
24
+ end
25
+
26
+ def to_json(*)
27
+ {
28
+ id: id,
29
+ object: object,
30
+ expires_at: expires_at,
31
+ code: code,
32
+ authentication_factor_id: authentication_factor_id,
33
+ created_at: created_at,
34
+ updated_at: updated_at,
35
+ }
36
+ end
37
+
38
+ private
39
+
40
+ sig { params(json_string: String).returns(WorkOS::Types::ChallengeStruct) }
41
+ def parse_json(json_string)
42
+ hash = JSON.parse(json_string, symbolize_names: true)
43
+
44
+ WorkOS::Types::ChallengeStruct.new(
45
+ id: hash[:id],
46
+ object: hash[:object],
47
+ expires_at: hash[:expires_at],
48
+ code: hash[:code],
49
+ authentication_factor_id: hash[:authentication_factor_id],
50
+ created_at: hash[:created_at],
51
+ updated_at: hash[:updated_at],
52
+ )
53
+ end
54
+ end
55
+ end
data/lib/workos/client.rb CHANGED
@@ -144,6 +144,7 @@ module WorkOS
144
144
  )
145
145
  when 422
146
146
  message = json['message']
147
+ code = json['code']
147
148
  errors = extract_error(json['errors']) if json['errors']
148
149
  message += " (#{errors})" if errors
149
150
 
@@ -151,6 +152,7 @@ module WorkOS
151
152
  message: message,
152
153
  http_status: http_status,
153
154
  request_id: response['x-request-id'],
155
+ code: code,
154
156
  )
155
157
  end
156
158
  end
@@ -7,6 +7,7 @@ module WorkOS
7
7
  # in user space, and is instantiated internally but exposed.
8
8
  # Note: status is deprecated - use state instead
9
9
  class Connection
10
+ include HashProvider
10
11
  extend T::Sig
11
12
 
12
13
  attr_accessor :id, :name, :connection_type, :domains, :organization_id,
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WorkOS
4
+ # A Temporary wrapper class for a Hash, currently the base class for
5
+ # WorOS::DirectoryGroup and WorkOS::DirectoryUser. Makes all the Hash
6
+ # methods available to those classes, but will also emit a deprecation
7
+ # warning whenever any of them are used.
8
+ #
9
+ # Once we deprecate Hash compatibility, this model can be deleted.
10
+ class DeprecatedHashWrapper < Hash
11
+ (public_instance_methods - Object.methods).each do |method_name|
12
+ define_method method_name do |*args, &block|
13
+ print_deprecation_warning(method_name)
14
+ super(*args, &block)
15
+ end
16
+ end
17
+
18
+ # call the original implementation of :replace in Hash,
19
+ # so we don't show the deprecation warning
20
+ def replace_without_warning(new_hash)
21
+ method(:replace).super_method&.call(new_hash)
22
+ end
23
+
24
+ def [](attribute_name)
25
+ usage = "#{object_name}.#{attribute_name}"
26
+ warning_message = "WARNING: The Hash style access for #{class_name} attributes is deprecated
27
+ and will be removed in a future version. Please use `#{usage}` or equivalent accessor.\n"
28
+
29
+ print_deprecation_warning('[]', warning_message)
30
+
31
+ super(attribute_name.to_sym)
32
+ end
33
+
34
+ private
35
+
36
+ def deprecation_warning(method_name)
37
+ usage = "#{object_name}.to_h.#{method_name}"
38
+
39
+ "WARNING: Hash compatibility for #{class_name} is deprecated and will be removed
40
+ in a future version. Please use `#{usage}` to access methods on the attribute Hash object.\n"
41
+ end
42
+
43
+ def print_deprecation_warning(method_name, warning_message = deprecation_warning(method_name))
44
+ if RUBY_VERSION > '3'
45
+ warn warning_message, category: :deprecated
46
+ else
47
+ warn warning_message
48
+ end
49
+ end
50
+
51
+ def class_name
52
+ self.class.name
53
+ end
54
+
55
+ # We want to do class_name.demodulize.underscore here, but that's not available in Ruby 1.9, so
56
+ # implementing the demodulize and underscore methods here.
57
+ def object_name
58
+ i = class_name.rindex('::')
59
+ object_name = i ? class_name[(i + 2)..-1] : class_name
60
+ underscore(object_name)
61
+ end
62
+
63
+ def underscore(camel_cased_word)
64
+ return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
65
+
66
+ word = camel_cased_word.to_s.gsub('::', '/')
67
+ word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)((?=a)b)(?=\b|[^a-z])/) do
68
+ "#{Regexp.last_match(1) && '_'}#{Regexp.last_match(2).downcase}"
69
+ end
70
+ word.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { (Regexp.last_match(1) || Regexp.last_match(2)) << '_' }
71
+ word.tr!('-', '_')
72
+ word.downcase!
73
+ word
74
+ end
75
+ end
76
+ end
@@ -6,6 +6,7 @@ module WorkOS
6
6
  # a WorkOS Directory resource. This class is not meant to be instantiated
7
7
  # in user space, and is instantiated internally but exposed.
8
8
  class Directory
9
+ include HashProvider
9
10
  extend T::Sig
10
11
 
11
12
  attr_accessor :id, :domain, :name, :type, :state, :organization_id, :created_at, :updated_at
@@ -5,10 +5,11 @@ module WorkOS
5
5
  # The DirectoryGroup class provides a lightweight wrapper around
6
6
  # a WorkOS DirectoryGroup resource. This class is not meant to be instantiated
7
7
  # in user space, and is instantiated internally but exposed.
8
- class DirectoryGroup
8
+ class DirectoryGroup < DeprecatedHashWrapper
9
+ include HashProvider
9
10
  extend T::Sig
10
11
 
11
- attr_accessor :id, :name
12
+ attr_accessor :id, :name, :custom_attributes, :raw_attributes
12
13
 
13
14
  sig { params(json: String).void }
14
15
  def initialize(json)
@@ -16,6 +17,8 @@ module WorkOS
16
17
 
17
18
  @id = T.let(raw.id, String)
18
19
  @name = T.let(raw.name, String)
20
+
21
+ replace_without_warning(to_json)
19
22
  end
20
23
 
21
24
  def to_json(*)
@@ -26,6 +26,7 @@ module WorkOS
26
26
  # before a provided Directory ID.
27
27
  # @option options [String] after Pagination cursor to receive records
28
28
  # before a provided Directory ID.
29
+ # @option options [String] organization_id The ID for an Organization configured on WorkOS.
29
30
  #
30
31
  # @return [Hash]
31
32
  sig do
@@ -95,7 +96,7 @@ module WorkOS
95
96
  # @option options [String] after Pagination cursor to receive records
96
97
  # before a provided Directory Group ID.
97
98
  #
98
- # @return [Hash]
99
+ # @return [WorkOS::DirectoryGroup]
99
100
  sig do
100
101
  params(
101
102
  options: T::Hash[Symbol, String],
@@ -134,7 +135,7 @@ module WorkOS
134
135
  # @option options [String] after Pagination cursor to receive records
135
136
  # before a provided Directory User ID.
136
137
  #
137
- # @return [Hash]
138
+ # @return [WorkOS::DirectoryUser]
138
139
  sig do
139
140
  params(
140
141
  options: T::Hash[Symbol, String],
@@ -164,8 +165,8 @@ module WorkOS
164
165
  #
165
166
  # @param [String] id The ID of the directory group.
166
167
  #
167
- # @return Hash
168
- sig { params(id: String).returns(T::Hash[String, T.untyped]) }
168
+ # @return WorkOS::DirectoryGroup
169
+ sig { params(id: String).returns(WorkOS::DirectoryGroup) }
169
170
  def get_group(id)
170
171
  response = execute_request(
171
172
  request: get_request(
@@ -174,15 +175,15 @@ module WorkOS
174
175
  ),
175
176
  )
176
177
 
177
- JSON.parse(response.body)
178
+ ::WorkOS::DirectoryGroup.new(response.body)
178
179
  end
179
180
 
180
181
  # Retrieve the directory user with the given ID.
181
182
  #
182
183
  # @param [String] id The ID of the directory user.
183
184
  #
184
- # @return Hash
185
- sig { params(id: String).returns(T::Hash[String, T.untyped]) }
185
+ # @return WorkOS::DirectoryUser
186
+ sig { params(id: String).returns(WorkOS::DirectoryUser) }
186
187
  def get_user(id)
187
188
  response = execute_request(
188
189
  request: get_request(
@@ -191,7 +192,7 @@ module WorkOS
191
192
  ),
192
193
  )
193
194
 
194
- JSON.parse(response.body)
195
+ ::WorkOS::DirectoryUser.new(response.body)
195
196
  end
196
197
 
197
198
  # Delete the directory with the given ID.
@@ -5,7 +5,8 @@ module WorkOS
5
5
  # The DirectoryUser class provides a lightweight wrapper around
6
6
  # a WorkOS DirectoryUser resource. This class is not meant to be instantiated
7
7
  # in DirectoryUser space, and is instantiated internally but exposed.
8
- class DirectoryUser
8
+ class DirectoryUser < DeprecatedHashWrapper
9
+ include HashProvider
9
10
  extend T::Sig
10
11
 
11
12
  attr_accessor :id, :idp_id, :emails, :first_name, :last_name, :username, :state,
@@ -26,6 +27,8 @@ module WorkOS
26
27
  @groups = T.let(raw.groups, Array)
27
28
  @custom_attributes = raw.custom_attributes
28
29
  @raw_attributes = raw.raw_attributes
30
+
31
+ replace_without_warning(to_json)
29
32
  end
30
33
  # rubocop:enable Metrics/AbcSize
31
34
 
data/lib/workos/errors.rb CHANGED
@@ -17,14 +17,16 @@ module WorkOS
17
17
  error_description: T.nilable(String),
18
18
  http_status: T.nilable(Integer),
19
19
  request_id: T.nilable(String),
20
+ code: T.nilable(String),
20
21
  ).void
21
22
  end
22
- def initialize(message: nil, error: nil, error_description: nil, http_status: nil, request_id: nil)
23
+ def initialize(message: nil, error: nil, error_description: nil, http_status: nil, request_id: nil, code: nil)
23
24
  @message = message
24
25
  @error = error
25
26
  @error_description = error_description
26
27
  @http_status = http_status
27
28
  @request_id = request_id
29
+ @code = code
28
30
  end
29
31
 
30
32
  sig { returns(String) }
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ module WorkOS
5
+ # The Factor class provides a lightweight wrapper around
6
+ # a WorkOS DirectoryUser resource. This class is not meant to be instantiated
7
+ # in DirectoryUser space, and is instantiated internally but exposed.
8
+ class Factor
9
+ include HashProvider
10
+ # rubocop:disable Metrics/AbcSize
11
+ extend T::Sig
12
+ attr_accessor :id, :environment_id, :object, :type, :sms, :totp, :updated_at, :created_at
13
+
14
+ sig { params(json: String).void }
15
+ def initialize(json)
16
+ raw = parse_json(json)
17
+ @id = T.let(raw.id, String)
18
+ @environment_id = T.let(raw.environment_id, String)
19
+ @object = T.let(raw.object, String)
20
+ @type = T.let(raw.type, String)
21
+ @created_at = T.let(raw.created_at, String)
22
+ @updated_at = T.let(raw.updated_at, String)
23
+ @totp = raw.totp
24
+ @sms = raw.sms
25
+ end
26
+
27
+ def to_json(*)
28
+ {
29
+ id: id,
30
+ environment_id: environment_id,
31
+ object: object,
32
+ type: type,
33
+ totp: totp,
34
+ sms: sms,
35
+ created_at: created_at,
36
+ updated_at: updated_at,
37
+ }
38
+ end
39
+
40
+ private
41
+
42
+ sig { params(json_string: String).returns(WorkOS::Types::FactorStruct) }
43
+ def parse_json(json_string)
44
+ hash = JSON.parse(json_string, symbolize_names: true)
45
+
46
+ WorkOS::Types::FactorStruct.new(
47
+ id: hash[:id],
48
+ environment_id: hash[:environment_id],
49
+ object: hash[:object],
50
+ type: hash[:type],
51
+ totp: hash[:totp],
52
+ sms: hash[:sms],
53
+ created_at: hash[:created_at],
54
+ updated_at: hash[:updated_at],
55
+ )
56
+ end
57
+ # rubocop:enable Metrics/AbcSize
58
+ end
59
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+ module WorkOS
5
+ # Module to include an explicit method for converting a model into a Hash containing
6
+ # its attributes. Default implementation will simply call to_json. Individual classes
7
+ # may override.
8
+ module HashProvider
9
+ include Kernel
10
+
11
+ def to_json(*)
12
+ raise 'Must be implemented by including class.'
13
+ end
14
+
15
+ def to_h
16
+ to_json
17
+ end
18
+ end
19
+ end
data/lib/workos/mfa.rb ADDED
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+ # typed: true
3
+
4
+
5
+ require 'net/http'
6
+ require 'uri'
7
+
8
+ module WorkOS
9
+ # The MFA module provides convenience methods for working with the WorkOS
10
+ # MFA platform. You'll need a valid API key
11
+ module MFA
12
+ class << self
13
+ extend T::Sig
14
+ include Base
15
+ include Client
16
+ sig { params(id: String).returns(T::Boolean) }
17
+ def delete_factor(id:)
18
+ response = execute_request(
19
+ request: delete_request(
20
+ path: "/auth/factors/#{id}",
21
+ auth: true,
22
+ ),
23
+ )
24
+ response.is_a? Net::HTTPSuccess
25
+ end
26
+
27
+ sig do
28
+ params(id: String).returns(WorkOS::Factor)
29
+ end
30
+ def get_factor(
31
+ id:
32
+ )
33
+ response = execute_request(
34
+ request: get_request(
35
+ path: "/auth/factors/#{id}",
36
+ auth: true,
37
+ ),
38
+ )
39
+ WorkOS::Factor.new(response.body)
40
+ end
41
+
42
+ sig do
43
+ params(
44
+ type: String,
45
+ totp_issuer: T.nilable(String),
46
+ totp_user: T.nilable(String),
47
+ phone_number: T.nilable(String),
48
+ ).void
49
+ end
50
+ # rubocop:disable Metrics/CyclomaticComplexity
51
+ # rubocop:disable Metrics/PerceivedComplexity
52
+
53
+ def validate_args(
54
+ type:,
55
+ totp_issuer: nil,
56
+ totp_user: nil,
57
+ phone_number: nil
58
+ )
59
+ if type != 'sms' && type != 'totp' && type != 'generic_otp'
60
+ raise ArgumentError, "Type argument must be either 'sms' or 'totp'"
61
+ end
62
+ if (type == 'totp' && totp_issuer.nil?) || (type == 'totp' && totp_user.nil?)
63
+ raise ArgumentError, 'Incomplete arguments. Need to specify both totp_issuer and totp_user when type is totp'
64
+ end
65
+ return unless type == 'sms' && phone_number.nil?
66
+
67
+ raise ArgumentError, 'Incomplete arguments. Need to specify phone_number when type is sms'
68
+ end
69
+ # rubocop:enable Metrics/CyclomaticComplexity
70
+ # rubocop:enable Metrics/PerceivedComplexity
71
+
72
+ sig do
73
+ params(
74
+ type: String,
75
+ totp_issuer: T.nilable(String),
76
+ totp_user: T.nilable(String),
77
+ phone_number: T.nilable(String),
78
+ ).returns(WorkOS::Factor)
79
+ end
80
+ # rubocop:disable Metrics/MethodLength
81
+ def enroll_factor(
82
+ type:,
83
+ totp_issuer: nil,
84
+ totp_user: nil,
85
+ phone_number: nil
86
+ )
87
+ validate_args(
88
+ type: type,
89
+ totp_issuer: totp_issuer,
90
+ totp_user: totp_user,
91
+ phone_number: phone_number,
92
+ )
93
+ response = execute_request(request: post_request(
94
+ auth: true,
95
+ body: {
96
+ type: type,
97
+ totp_issuer: totp_issuer,
98
+ totp_user: totp_user,
99
+ phone_number: phone_number,
100
+ },
101
+ path: '/auth/factors/enroll',
102
+ ))
103
+ WorkOS::Factor.new(response.body)
104
+ end
105
+ # rubocop:enable Metrics/MethodLength
106
+
107
+ sig do
108
+ params(
109
+ authentication_factor_id: T.nilable(String),
110
+ sms_template: T.nilable(String),
111
+ ).returns(WorkOS::Challenge)
112
+ end
113
+ def challenge_factor(
114
+ authentication_factor_id: nil,
115
+ sms_template: nil
116
+ )
117
+ if authentication_factor_id.nil?
118
+ raise ArgumentError, "Incomplete arguments: 'authentication_factor_id' is a required argument"
119
+ end
120
+
121
+ request = post_request(
122
+ auth: true,
123
+ body: {
124
+ sms_template: sms_template,
125
+ authentication_factor_id: authentication_factor_id,
126
+ },
127
+ path: '/auth/factors/challenge',
128
+ )
129
+
130
+ response = execute_request(request: request)
131
+ WorkOS::Challenge.new(response.body)
132
+ end
133
+
134
+ sig do
135
+ params(
136
+ authentication_challenge_id: T.nilable(String),
137
+ code: T.nilable(String),
138
+ ).returns(WorkOS::VerifyFactor)
139
+ end
140
+ def verify_factor(
141
+ authentication_challenge_id: nil,
142
+ code: nil
143
+ )
144
+
145
+ if authentication_challenge_id.nil? || code.nil?
146
+ raise ArgumentError, "Incomplete arguments: 'authentication_challenge_id' and 'code' are required arguments"
147
+ end
148
+
149
+ options = {
150
+ "authentication_challenge_id": authentication_challenge_id,
151
+ "code": code,
152
+ }
153
+
154
+ response = execute_request(
155
+ request: post_request(
156
+ path: '/auth/factors/verify',
157
+ auth: true,
158
+ body: options,
159
+ ),
160
+ )
161
+ WorkOS::VerifyFactor.new(response.body)
162
+ end
163
+ end
164
+ end
165
+ end
@@ -6,6 +6,7 @@ module WorkOS
6
6
  # a WorkOS Organization resource. This class is not meant to be instantiated
7
7
  # in user space, and is instantiated internally but exposed.
8
8
  class Organization
9
+ include HashProvider
9
10
  extend T::Sig
10
11
 
11
12
  attr_accessor :id, :domains, :name, :allow_profiles_outside_organization, :created_at, :updated_at
@@ -8,6 +8,7 @@ module WorkOS
8
8
  # is not meant to be instantiated in user space, and
9
9
  # is instantiated internally but exposed.
10
10
  class Profile
11
+ include HashProvider
11
12
  extend T::Sig
12
13
 
13
14
  sig { returns(String) }
@@ -6,6 +6,7 @@ module WorkOS
6
6
  # Access Token. This class is not meant to be instantiated in user space, and
7
7
  # is instantiated internally but exposed.
8
8
  class ProfileAndToken
9
+ include HashProvider
9
10
  extend T::Sig
10
11
 
11
12
  attr_accessor :access_token, :profile
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module WorkOS
5
+ module Types
6
+ # This ChallgengeStruct acts as a typed interface
7
+ # for the Factor class
8
+ class ChallengeStruct < T::Struct
9
+ const :id, String
10
+ const :object, String
11
+ const :expires_at, T.nilable(String)
12
+ const :code, T.nilable(String)
13
+ const :authentication_factor_id, String
14
+ const :created_at, String
15
+ const :updated_at, String
16
+ end
17
+ end
18
+ end