clerk-sdk-ruby 8.0.0 → 8.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.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/lib/clerk/actortokens.rb +1 -1
  3. data/lib/clerk/billing.rb +336 -0
  4. data/lib/clerk/directories.rb +1534 -0
  5. data/lib/clerk/domains.rb +7 -4
  6. data/lib/clerk/models/components/amount_off.rb +44 -0
  7. data/lib/clerk/models/components/amount_off.rbi +19 -0
  8. data/lib/clerk/models/components/applycommercediscountrequest.rb +32 -0
  9. data/lib/clerk/models/components/applycommercediscountrequest.rbi +13 -0
  10. data/lib/clerk/models/components/automation_disposition.rb +21 -0
  11. data/lib/clerk/models/components/automation_disposition.rbi +11 -0
  12. data/lib/clerk/models/components/billingstatement.rb +1 -1
  13. data/lib/clerk/models/components/{group.rb → billingstatement_group.rb} +1 -1
  14. data/lib/clerk/models/components/{group.rbi → billingstatement_group.rbi} +2 -2
  15. data/lib/clerk/models/components/biometriccredential.rb +72 -0
  16. data/lib/clerk/models/components/biometriccredential.rbi +33 -0
  17. data/lib/clerk/models/components/biometriccredential_algorithm.rb +19 -0
  18. data/lib/clerk/models/components/biometriccredential_algorithm.rbi +11 -0
  19. data/lib/clerk/models/components/biometriccredential_list.rb +36 -0
  20. data/lib/clerk/models/components/biometriccredential_list.rbi +15 -0
  21. data/lib/clerk/models/components/biometriccredential_object.rb +19 -0
  22. data/lib/clerk/models/components/biometriccredential_object.rbi +11 -0
  23. data/lib/clerk/models/components/biometriccredential_platform.rb +20 -0
  24. data/lib/clerk/models/components/biometriccredential_platform.rbi +11 -0
  25. data/lib/clerk/models/components/biometriccredential_status.rb +20 -0
  26. data/lib/clerk/models/components/biometriccredential_status.rbi +11 -0
  27. data/lib/clerk/models/components/commercediscountredemptionresponse.rb +93 -0
  28. data/lib/clerk/models/components/commercediscountredemptionresponse.rbi +43 -0
  29. data/lib/clerk/models/components/commercediscountredemptionresponse_amount.rb +45 -0
  30. data/lib/clerk/models/components/commercediscountredemptionresponse_amount.rbi +19 -0
  31. data/lib/clerk/models/components/commercediscountredemptionresponse_object.rb +19 -0
  32. data/lib/clerk/models/components/commercediscountredemptionresponse_object.rbi +11 -0
  33. data/lib/clerk/models/components/commercediscountredemptionresponse_status.rb +21 -0
  34. data/lib/clerk/models/components/commercediscountredemptionresponse_status.rbi +11 -0
  35. data/lib/clerk/models/components/createbillingpricerequest.rb +2 -2
  36. data/lib/clerk/models/components/directory.rb +80 -0
  37. data/lib/clerk/models/components/directory.rbi +37 -0
  38. data/lib/clerk/models/components/directory_custom_attribute.rb +52 -0
  39. data/lib/clerk/models/components/directory_custom_attribute.rbi +23 -0
  40. data/lib/clerk/models/components/directory_group.rb +36 -0
  41. data/lib/clerk/models/components/directory_group.rbi +15 -0
  42. data/lib/clerk/models/components/directory_list.rb +36 -0
  43. data/lib/clerk/models/components/directory_list.rbi +15 -0
  44. data/lib/clerk/models/components/directory_object.rb +19 -0
  45. data/lib/clerk/models/components/directory_object.rbi +11 -0
  46. data/lib/clerk/models/components/directorygrouprolemapping.rb +76 -0
  47. data/lib/clerk/models/components/directorygrouprolemapping.rbi +35 -0
  48. data/lib/clerk/models/components/directorygrouprolemapping_deleted.rb +43 -0
  49. data/lib/clerk/models/components/directorygrouprolemapping_deleted.rbi +17 -0
  50. data/lib/clerk/models/components/directorygrouprolemapping_deleted_object.rb +19 -0
  51. data/lib/clerk/models/components/directorygrouprolemapping_deleted_object.rbi +11 -0
  52. data/lib/clerk/models/components/directorygrouprolemapping_list.rb +36 -0
  53. data/lib/clerk/models/components/directorygrouprolemapping_list.rbi +15 -0
  54. data/lib/clerk/models/components/directorygrouprolemapping_object.rb +19 -0
  55. data/lib/clerk/models/components/directorygrouprolemapping_object.rbi +11 -0
  56. data/lib/clerk/models/components/dnstarget.rb +49 -0
  57. data/lib/clerk/models/components/dnstarget.rbi +21 -0
  58. data/lib/clerk/models/components/domain.rb +7 -2
  59. data/lib/clerk/models/components/domain.rbi +2 -0
  60. data/lib/clerk/models/components/effect.rb +20 -0
  61. data/lib/clerk/models/components/{platform.rbi → effect.rbi} +2 -2
  62. data/lib/clerk/models/components/enterpriseconnection_custom_attribute.rb +5 -1
  63. data/lib/clerk/models/components/enterpriseconnection_custom_attribute.rbi +2 -0
  64. data/lib/clerk/models/components/instance.rb +13 -1
  65. data/lib/clerk/models/components/instance.rbi +6 -0
  66. data/lib/clerk/models/components/instanceprotect.rb +10 -2
  67. data/lib/clerk/models/components/instanceprotect.rbi +4 -0
  68. data/lib/clerk/models/components/instancesettings.rb +1 -1
  69. data/lib/clerk/models/components/level.rb +21 -0
  70. data/lib/clerk/models/components/{algorithm.rbi → level.rbi} +2 -2
  71. data/lib/clerk/models/components/oauthapplication.rb +7 -2
  72. data/lib/clerk/models/components/oauthapplication.rbi +2 -0
  73. data/lib/clerk/models/components/oauthapplicationsettings.rb +11 -2
  74. data/lib/clerk/models/components/oauthapplicationsettings.rbi +4 -0
  75. data/lib/clerk/models/components/oauthapplicationwithsecret.rb +7 -2
  76. data/lib/clerk/models/components/oauthapplicationwithsecret.rbi +2 -0
  77. data/lib/clerk/models/components/organization.rb +6 -1
  78. data/lib/clerk/models/components/organization.rbi +2 -0
  79. data/lib/clerk/models/components/organizationmembership_organization.rb +6 -1
  80. data/lib/clerk/models/components/organizationmembership_organization.rbi +2 -0
  81. data/lib/clerk/models/components/organizationwithlogo.rb +6 -1
  82. data/lib/clerk/models/components/organizationwithlogo.rbi +2 -0
  83. data/lib/clerk/models/components/record_type.rb +20 -0
  84. data/lib/clerk/models/components/record_type.rbi +11 -0
  85. data/lib/clerk/models/components/reverification.rb +74 -0
  86. data/lib/clerk/models/components/reverification.rbi +31 -0
  87. data/lib/clerk/models/components/reverification_object.rb +20 -0
  88. data/lib/clerk/models/components/reverification_object.rbi +11 -0
  89. data/lib/clerk/models/components/reverification_status.rb +21 -0
  90. data/lib/clerk/models/components/reverification_status.rbi +11 -0
  91. data/lib/clerk/models/components/scim_group.rb +36 -0
  92. data/lib/clerk/models/components/scim_group.rbi +15 -0
  93. data/lib/clerk/models/components/scimdirectory.rb +8 -8
  94. data/lib/clerk/models/components/scimdirectory_custom_attribute.rb +5 -1
  95. data/lib/clerk/models/components/scimdirectory_custom_attribute.rbi +2 -0
  96. data/lib/clerk/models/components/scimdirectory_list.rb +2 -2
  97. data/lib/clerk/models/components/scimgrouprolemapping.rb +14 -2
  98. data/lib/clerk/models/components/scimgrouprolemapping.rbi +6 -0
  99. data/lib/clerk/models/components/scimusermetadata.rb +64 -0
  100. data/lib/clerk/models/components/scimusermetadata.rbi +27 -0
  101. data/lib/clerk/models/components/scimusermetadata_group.rb +36 -0
  102. data/lib/clerk/models/components/scimusermetadata_group.rbi +15 -0
  103. data/lib/clerk/models/components/source.rb +21 -0
  104. data/lib/clerk/models/components/source.rbi +11 -0
  105. data/lib/clerk/models/components/trusteddevice.rb +2 -2
  106. data/lib/clerk/models/components/{algorithm.rb → trusteddevice_algorithm.rb} +1 -1
  107. data/lib/clerk/models/components/trusteddevice_algorithm.rbi +11 -0
  108. data/lib/clerk/models/components/{platform.rb → trusteddevice_platform.rb} +1 -1
  109. data/lib/clerk/models/components/trusteddevice_platform.rbi +11 -0
  110. data/lib/clerk/models/components/user.rb +16 -3
  111. data/lib/clerk/models/components/user.rbi +4 -0
  112. data/lib/clerk/models/components/user_directory.rb +65 -0
  113. data/lib/clerk/models/components/user_directory.rbi +27 -0
  114. data/lib/clerk/models/components/user_scim.rb +27 -6
  115. data/lib/clerk/models/components/user_scim.rbi +10 -0
  116. data/lib/clerk/models/components.rb +38 -3
  117. data/lib/clerk/models/operations/adddomain_request.rb +3 -6
  118. data/lib/clerk/models/operations/applybillingsubscriptionitemdiscount_request.rb +36 -0
  119. data/lib/clerk/models/operations/applybillingsubscriptionitemdiscount_request.rbi +15 -0
  120. data/lib/clerk/models/operations/applybillingsubscriptionitemdiscount_response.rb +44 -0
  121. data/lib/clerk/models/operations/applybillingsubscriptionitemdiscount_response.rbi +19 -0
  122. data/lib/clerk/models/operations/clerkidpoauthaccesstoken.rb +5 -1
  123. data/lib/clerk/models/operations/clerkidpoauthaccesstoken.rbi +2 -0
  124. data/lib/clerk/models/operations/createdirectory_group_role_mapping.rb +52 -0
  125. data/lib/clerk/models/operations/createdirectory_group_role_mapping.rbi +23 -0
  126. data/lib/clerk/models/operations/createdirectory_request.rb +44 -0
  127. data/lib/clerk/models/operations/createdirectory_request.rbi +19 -0
  128. data/lib/clerk/models/operations/createdirectory_response.rb +44 -0
  129. data/lib/clerk/models/operations/createdirectory_response.rbi +19 -0
  130. data/lib/clerk/models/operations/createdirectorygrouprolemapping_request.rb +36 -0
  131. data/lib/clerk/models/operations/createdirectorygrouprolemapping_request.rbi +15 -0
  132. data/lib/clerk/models/operations/createdirectorygrouprolemapping_requestbody.rb +46 -0
  133. data/lib/clerk/models/operations/createdirectorygrouprolemapping_requestbody.rbi +19 -0
  134. data/lib/clerk/models/operations/createdirectorygrouprolemapping_response.rb +44 -0
  135. data/lib/clerk/models/operations/createdirectorygrouprolemapping_response.rbi +19 -0
  136. data/lib/clerk/models/operations/createenterpriseconnection_custom_attribute.rb +5 -1
  137. data/lib/clerk/models/operations/createenterpriseconnection_custom_attribute.rbi +2 -0
  138. data/lib/clerk/models/operations/createoauthapplication_request.rb +6 -2
  139. data/lib/clerk/models/operations/createoauthapplication_request.rbi +2 -0
  140. data/lib/clerk/models/operations/{group_role_mapping.rb → createscimdirectory_group_role_mapping.rb} +1 -1
  141. data/lib/clerk/models/operations/{group_role_mapping.rbi → createscimdirectory_group_role_mapping.rbi} +2 -2
  142. data/lib/clerk/models/operations/createscimdirectory_request.rb +4 -4
  143. data/lib/clerk/models/operations/createscimdirectory_response.rb +1 -1
  144. data/lib/clerk/models/operations/createscimgrouprolemapping_request.rb +1 -1
  145. data/lib/clerk/models/operations/createuser_request.rb +8 -2
  146. data/lib/clerk/models/operations/createuser_request.rbi +2 -0
  147. data/lib/clerk/models/operations/deletedirectory_request.rb +32 -0
  148. data/lib/clerk/models/operations/deletedirectory_request.rbi +13 -0
  149. data/lib/clerk/models/operations/deletedirectory_response.rb +44 -0
  150. data/lib/clerk/models/operations/deletedirectory_response.rbi +19 -0
  151. data/lib/clerk/models/operations/deletedirectorygrouprolemapping_request.rb +36 -0
  152. data/lib/clerk/models/operations/deletedirectorygrouprolemapping_request.rbi +15 -0
  153. data/lib/clerk/models/operations/deletedirectorygrouprolemapping_response.rb +44 -0
  154. data/lib/clerk/models/operations/deletedirectorygrouprolemapping_response.rbi +19 -0
  155. data/lib/clerk/models/operations/deletedomain_request.rb +1 -1
  156. data/lib/clerk/models/operations/deletescimdirectory_request.rb +1 -1
  157. data/lib/clerk/models/operations/deletescimgrouprolemapping_request.rb +1 -1
  158. data/lib/clerk/models/operations/getdirectory_request.rb +32 -0
  159. data/lib/clerk/models/operations/getdirectory_request.rbi +13 -0
  160. data/lib/clerk/models/operations/getdirectory_response.rb +44 -0
  161. data/lib/clerk/models/operations/getdirectory_response.rbi +19 -0
  162. data/lib/clerk/models/operations/getreverification_request.rb +36 -0
  163. data/lib/clerk/models/operations/getreverification_request.rbi +15 -0
  164. data/lib/clerk/models/operations/getreverification_response.rb +44 -0
  165. data/lib/clerk/models/operations/getreverification_response.rbi +19 -0
  166. data/lib/clerk/models/operations/getscimdirectory_request.rb +1 -1
  167. data/lib/clerk/models/operations/getscimdirectory_response.rb +1 -1
  168. data/lib/clerk/models/operations/getuserlist_request.rb +13 -1
  169. data/lib/clerk/models/operations/getuserlist_request.rbi +2 -0
  170. data/lib/clerk/models/operations/listdirectories_request.rb +39 -0
  171. data/lib/clerk/models/operations/listdirectories_request.rbi +15 -0
  172. data/lib/clerk/models/operations/listdirectories_response.rb +44 -0
  173. data/lib/clerk/models/operations/listdirectories_response.rbi +19 -0
  174. data/lib/clerk/models/operations/listdirectorygrouprolemappings_request.rb +32 -0
  175. data/lib/clerk/models/operations/listdirectorygrouprolemappings_request.rbi +13 -0
  176. data/lib/clerk/models/operations/listdirectorygrouprolemappings_response.rb +44 -0
  177. data/lib/clerk/models/operations/listdirectorygrouprolemappings_response.rbi +19 -0
  178. data/lib/clerk/models/operations/listoauthapplications_request.rb +2 -0
  179. data/lib/clerk/models/operations/listscimdirectories_response.rb +1 -1
  180. data/lib/clerk/models/operations/listscimgrouprolemappings_request.rb +1 -1
  181. data/lib/clerk/models/operations/listuserbiometriccredentials_request.rb +32 -0
  182. data/lib/clerk/models/operations/listuserbiometriccredentials_request.rbi +13 -0
  183. data/lib/clerk/models/operations/listuserbiometriccredentials_response.rb +44 -0
  184. data/lib/clerk/models/operations/listuserbiometriccredentials_response.rbi +19 -0
  185. data/lib/clerk/models/operations/removebillingsubscriptionitemdiscount_request.rb +36 -0
  186. data/lib/clerk/models/operations/removebillingsubscriptionitemdiscount_request.rbi +15 -0
  187. data/lib/clerk/models/operations/removebillingsubscriptionitemdiscount_response.rb +44 -0
  188. data/lib/clerk/models/operations/removebillingsubscriptionitemdiscount_response.rbi +19 -0
  189. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_mapping.rb +40 -0
  190. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_mapping.rbi +17 -0
  191. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_request.rb +36 -0
  192. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_request.rbi +15 -0
  193. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_requestbody.rb +32 -0
  194. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_requestbody.rbi +13 -0
  195. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_response.rb +44 -0
  196. data/lib/clerk/models/operations/replacedirectorygrouprolemappings_response.rbi +19 -0
  197. data/lib/clerk/models/operations/{mapping.rb → replacescimgrouprolemappings_mapping.rb} +1 -1
  198. data/lib/clerk/models/operations/{mapping.rbi → replacescimgrouprolemappings_mapping.rbi} +2 -2
  199. data/lib/clerk/models/operations/replacescimgrouprolemappings_request.rb +1 -1
  200. data/lib/clerk/models/operations/replacescimgrouprolemappings_requestbody.rb +1 -1
  201. data/lib/clerk/models/operations/revokeuserbiometriccredential_request.rb +36 -0
  202. data/lib/clerk/models/operations/revokeuserbiometriccredential_request.rbi +15 -0
  203. data/lib/clerk/models/operations/revokeuserbiometriccredential_response.rb +44 -0
  204. data/lib/clerk/models/operations/revokeuserbiometriccredential_response.rbi +19 -0
  205. data/lib/clerk/models/operations/rotatedirectoryapikey_request.rb +32 -0
  206. data/lib/clerk/models/operations/rotatedirectoryapikey_request.rbi +13 -0
  207. data/lib/clerk/models/operations/rotatedirectoryapikey_response.rb +44 -0
  208. data/lib/clerk/models/operations/rotatedirectoryapikey_response.rbi +19 -0
  209. data/lib/clerk/models/operations/rotatescimdirectoryapikey_request.rb +1 -1
  210. data/lib/clerk/models/operations/rotatescimdirectoryapikey_response.rb +1 -1
  211. data/lib/clerk/models/operations/updatedirectory_request.rb +36 -0
  212. data/lib/clerk/models/operations/updatedirectory_request.rbi +15 -0
  213. data/lib/clerk/models/operations/updatedirectory_requestbody.rb +49 -0
  214. data/lib/clerk/models/operations/updatedirectory_requestbody.rbi +21 -0
  215. data/lib/clerk/models/operations/updatedirectory_response.rb +44 -0
  216. data/lib/clerk/models/operations/updatedirectory_response.rbi +19 -0
  217. data/lib/clerk/models/operations/updateenterpriseconnection_custom_attribute.rb +5 -1
  218. data/lib/clerk/models/operations/updateenterpriseconnection_custom_attribute.rbi +2 -0
  219. data/lib/clerk/models/operations/updateinstance_request.rb +15 -5
  220. data/lib/clerk/models/operations/updateinstance_request.rbi +6 -2
  221. data/lib/clerk/models/operations/updateinstanceoauthapplicationsettings_request.rb +11 -2
  222. data/lib/clerk/models/operations/updateinstanceoauthapplicationsettings_request.rbi +4 -0
  223. data/lib/clerk/models/operations/updateinstanceprotect_request.rb +1 -1
  224. data/lib/clerk/models/operations/updateoauthapplication_requestbody.rb +9 -5
  225. data/lib/clerk/models/operations/updateoauthapplication_requestbody.rbi +4 -2
  226. data/lib/clerk/models/operations/updateorganization_requestbody.rb +6 -1
  227. data/lib/clerk/models/operations/updateorganization_requestbody.rbi +2 -0
  228. data/lib/clerk/models/operations/updatescimdirectory_request.rb +1 -1
  229. data/lib/clerk/models/operations/updatescimdirectory_requestbody.rb +4 -4
  230. data/lib/clerk/models/operations/updatescimdirectory_response.rb +1 -1
  231. data/lib/clerk/models/operations/updateuser_requestbody.rb +1 -1
  232. data/lib/clerk/models/operations.rb +37 -2
  233. data/lib/clerk/openapiclient.rb +2 -1
  234. data/lib/clerk/phonenumbers.rb +10 -2
  235. data/lib/clerk/scimdirectories.rb +23 -20
  236. data/lib/clerk/sdk.rb +21 -1
  237. data/lib/clerk/sdkconfiguration.rb +3 -3
  238. data/lib/clerk/sessions.rb +146 -0
  239. data/lib/clerk/users.rb +329 -1
  240. data/lib/clerk/utils/utils.rb +6 -2
  241. data/lib/clerk_sdk_ruby.rb +1 -0
  242. data/test/clerk/org_permissions_v2_test.rb +130 -0
  243. metadata +154 -12
@@ -636,6 +636,152 @@ module Clerk
636
636
 
637
637
 
638
638
 
639
+ def get_reverification(session_id:, reverification_id:, retries: nil, timeout_ms: nil, http_headers: nil)
640
+ # get_reverification - Retrieve a reverification
641
+ # Retrieve a reverification scoped to a session. A resource server can use this to validate a reverification id it received from its client: confirm it is real, scoped to the expected session, completed, and how fresh each factor is. Single-use / replay detection is the caller's responsibility (the id is stable, so the caller dedups consumed ids).
642
+ #
643
+ request = Models::Operations::GetReverificationRequest.new(
644
+ session_id: session_id,
645
+ reverification_id: reverification_id
646
+ )
647
+ url, params = @sdk_configuration.get_server_details
648
+ base_url = Utils.template_url(url, params)
649
+ url = Utils.generate_url(
650
+ Models::Operations::GetReverificationRequest,
651
+ base_url,
652
+ '/sessions/{session_id}/reverifications/{reverification_id}',
653
+ request
654
+ )
655
+ headers = {}
656
+
657
+ headers['Accept'] = 'application/json'
658
+ headers['user-agent'] = @sdk_configuration.user_agent
659
+ retries ||= @sdk_configuration.retry_config
660
+ retries ||= Utils::RetryConfig.new(
661
+ backoff: Utils::BackoffStrategy.new(
662
+ exponent: 1.5,
663
+ initial_interval: 500,
664
+ max_elapsed_time: 3_600_000,
665
+ max_interval: 60_000
666
+ ),
667
+ retry_connection_errors: true,
668
+ strategy: 'backoff'
669
+ )
670
+ retry_options = retries.to_faraday_retry_options(initial_time: Time.now)
671
+ retry_options[:retry_statuses] = [500, 501, 502, 503, 504, 505]
672
+
673
+ security = @sdk_configuration.security_source&.call
674
+
675
+ timeout = (timeout_ms.to_f / 1000) unless timeout_ms.nil?
676
+ timeout ||= @sdk_configuration.timeout
677
+
678
+
679
+ connection = @sdk_configuration.client.dup
680
+ connection.use Utils::RetryMiddleware, retry_options
681
+
682
+ hook_ctx = SDKHooks::HookContext.new(
683
+ config: @sdk_configuration,
684
+ base_url: base_url,
685
+ oauth2_scopes: nil,
686
+ operation_id: 'GetReverification',
687
+ security_source: @sdk_configuration.security_source
688
+ )
689
+
690
+ error = nil
691
+ http_response = nil
692
+
693
+
694
+ begin
695
+ http_response = connection.get(url) do |req|
696
+ req.headers.merge!(headers)
697
+ req.options.timeout = timeout unless timeout.nil?
698
+ Utils.configure_request_security(req, security)
699
+ http_headers&.each do |key, value|
700
+ req.headers[key.to_s] = value
701
+ end
702
+
703
+ @sdk_configuration.hooks.before_request(
704
+ hook_ctx: SDKHooks::BeforeRequestHookContext.new(
705
+ hook_ctx: hook_ctx
706
+ ),
707
+ request: req
708
+ )
709
+ end
710
+ rescue StandardError => e
711
+ error = e
712
+ ensure
713
+ if http_response.nil? || Utils.error_status?(http_response.status)
714
+ http_response = @sdk_configuration.hooks.after_error(
715
+ error: error,
716
+ hook_ctx: SDKHooks::AfterErrorHookContext.new(
717
+ hook_ctx: hook_ctx
718
+ ),
719
+ response: http_response
720
+ )
721
+ else
722
+ http_response = @sdk_configuration.hooks.after_success(
723
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
724
+ hook_ctx: hook_ctx
725
+ ),
726
+ response: http_response
727
+ )
728
+ end
729
+
730
+ if http_response.nil?
731
+ raise error if !error.nil?
732
+ raise 'no response'
733
+ end
734
+ end
735
+
736
+ content_type = http_response.headers.fetch('Content-Type', 'application/octet-stream')
737
+ if Utils.match_status_code(http_response.status, ['200'])
738
+ if Utils.match_content_type(content_type, 'application/json')
739
+ http_response = @sdk_configuration.hooks.after_success(
740
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
741
+ hook_ctx: hook_ctx
742
+ ),
743
+ response: http_response
744
+ )
745
+ response_data = http_response.env.response_body
746
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Components::Reverification)
747
+ response = Models::Operations::GetReverificationResponse.new(
748
+ status_code: http_response.status,
749
+ content_type: content_type,
750
+ raw_response: http_response,
751
+ reverification: obj
752
+ )
753
+
754
+ return response
755
+ else
756
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
757
+ end
758
+ elsif Utils.match_status_code(http_response.status, ['400', '401', '404'])
759
+ if Utils.match_content_type(content_type, 'application/json')
760
+ http_response = @sdk_configuration.hooks.after_success(
761
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
762
+ hook_ctx: hook_ctx
763
+ ),
764
+ response: http_response
765
+ )
766
+ response_data = http_response.env.response_body
767
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Errors::ClerkErrors)
768
+ obj.raw_response = http_response
769
+ raise obj
770
+ else
771
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
772
+ end
773
+ elsif Utils.match_status_code(http_response.status, ['4XX'])
774
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
775
+ elsif Utils.match_status_code(http_response.status, ['5XX'])
776
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
777
+ else
778
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown status code received'
779
+
780
+ end
781
+ end
782
+
783
+
784
+
639
785
  def revoke(session_id:, retries: nil, timeout_ms: nil, http_headers: nil)
640
786
  # revoke - Revoke a session
641
787
  # Sets the status of a session as "revoked", which is an unauthenticated state.
data/lib/clerk/users.rb CHANGED
@@ -45,6 +45,11 @@ module Clerk
45
45
  # list - List all users
46
46
  # Returns a list of all users.
47
47
  # The users are returned sorted by creation date, with the newest users appearing first.
48
+ #
49
+ # To walk more than a few pages, paginate with `starting_after` rather than `offset`.
50
+ # A cursor page costs the same no matter how far into the list it sits, while a large `offset`
51
+ # has to walk and discard every row before it, so it gets progressively slower and eventually
52
+ # times out. Cursor pagination requires the `created_at` ordering, which is the default.
48
53
  url, params = @sdk_configuration.get_server_details
49
54
  base_url = Utils.template_url(url, params)
50
55
  url = "#{base_url}/users"
@@ -4171,7 +4176,7 @@ module Clerk
4171
4176
 
4172
4177
  def delete_passkey(user_id:, passkey_identification_id:, retries: nil, timeout_ms: nil, http_headers: nil)
4173
4178
  # delete_passkey - Delete a user passkey
4174
- # Delete the passkey identification for a given user and notify them through email.
4179
+ # Delete the passkey identification for a given user. The user is notified through email or SMS unless the passkey registration was never completed.
4175
4180
  request = Models::Operations::UserPasskeyDeleteRequest.new(
4176
4181
  user_id: user_id,
4177
4182
  passkey_identification_id: passkey_identification_id
@@ -4332,6 +4337,8 @@ module Clerk
4332
4337
  def list_trusted_devices(user_id:, retries: nil, timeout_ms: nil, http_headers: nil)
4333
4338
  # list_trusted_devices - List a user's trusted devices
4334
4339
  # Returns the active trusted devices enrolled by the user.
4340
+ #
4341
+ # @deprecated method: This will be removed in a future release, please migrate away from it as soon as possible.
4335
4342
  request = Models::Operations::ListUserTrustedDevicesRequest.new(
4336
4343
  user_id: user_id
4337
4344
  )
@@ -4491,6 +4498,8 @@ module Clerk
4491
4498
  def revoke_trusted_device(user_id:, trusted_device_id:, retries: nil, timeout_ms: nil, http_headers: nil)
4492
4499
  # revoke_trusted_device - Revoke a user's trusted device
4493
4500
  # Revokes an active trusted device enrolled by the user.
4501
+ #
4502
+ # @deprecated method: This will be removed in a future release, please migrate away from it as soon as possible.
4494
4503
  request = Models::Operations::RevokeUserTrustedDeviceRequest.new(
4495
4504
  user_id: user_id,
4496
4505
  trusted_device_id: trusted_device_id
@@ -4648,6 +4657,325 @@ module Clerk
4648
4657
 
4649
4658
 
4650
4659
 
4660
+ def list_biometric_credentials(user_id:, retries: nil, timeout_ms: nil, http_headers: nil)
4661
+ # list_biometric_credentials - List a user's biometric credentials
4662
+ # Returns the active biometric credentials enrolled by the user.
4663
+ request = Models::Operations::ListUserBiometricCredentialsRequest.new(
4664
+ user_id: user_id
4665
+ )
4666
+ url, params = @sdk_configuration.get_server_details
4667
+ base_url = Utils.template_url(url, params)
4668
+ url = Utils.generate_url(
4669
+ Models::Operations::ListUserBiometricCredentialsRequest,
4670
+ base_url,
4671
+ '/users/{user_id}/biometric_credentials',
4672
+ request
4673
+ )
4674
+ headers = {}
4675
+
4676
+ headers['Accept'] = 'application/json'
4677
+ headers['user-agent'] = @sdk_configuration.user_agent
4678
+ retries ||= @sdk_configuration.retry_config
4679
+ retries ||= Utils::RetryConfig.new(
4680
+ backoff: Utils::BackoffStrategy.new(
4681
+ exponent: 1.5,
4682
+ initial_interval: 500,
4683
+ max_elapsed_time: 3_600_000,
4684
+ max_interval: 60_000
4685
+ ),
4686
+ retry_connection_errors: true,
4687
+ strategy: 'backoff'
4688
+ )
4689
+ retry_options = retries.to_faraday_retry_options(initial_time: Time.now)
4690
+ retry_options[:retry_statuses] = [500, 501, 502, 503, 504, 505]
4691
+
4692
+ security = @sdk_configuration.security_source&.call
4693
+
4694
+ timeout = (timeout_ms.to_f / 1000) unless timeout_ms.nil?
4695
+ timeout ||= @sdk_configuration.timeout
4696
+
4697
+
4698
+ connection = @sdk_configuration.client.dup
4699
+ connection.use Utils::RetryMiddleware, retry_options
4700
+
4701
+ hook_ctx = SDKHooks::HookContext.new(
4702
+ config: @sdk_configuration,
4703
+ base_url: base_url,
4704
+ oauth2_scopes: nil,
4705
+ operation_id: 'ListUserBiometricCredentials',
4706
+ security_source: @sdk_configuration.security_source
4707
+ )
4708
+
4709
+ error = nil
4710
+ http_response = nil
4711
+
4712
+
4713
+ begin
4714
+ http_response = connection.get(url) do |req|
4715
+ req.headers.merge!(headers)
4716
+ req.options.timeout = timeout unless timeout.nil?
4717
+ Utils.configure_request_security(req, security)
4718
+ http_headers&.each do |key, value|
4719
+ req.headers[key.to_s] = value
4720
+ end
4721
+
4722
+ @sdk_configuration.hooks.before_request(
4723
+ hook_ctx: SDKHooks::BeforeRequestHookContext.new(
4724
+ hook_ctx: hook_ctx
4725
+ ),
4726
+ request: req
4727
+ )
4728
+ end
4729
+ rescue StandardError => e
4730
+ error = e
4731
+ ensure
4732
+ if http_response.nil? || Utils.error_status?(http_response.status)
4733
+ http_response = @sdk_configuration.hooks.after_error(
4734
+ error: error,
4735
+ hook_ctx: SDKHooks::AfterErrorHookContext.new(
4736
+ hook_ctx: hook_ctx
4737
+ ),
4738
+ response: http_response
4739
+ )
4740
+ else
4741
+ http_response = @sdk_configuration.hooks.after_success(
4742
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4743
+ hook_ctx: hook_ctx
4744
+ ),
4745
+ response: http_response
4746
+ )
4747
+ end
4748
+
4749
+ if http_response.nil?
4750
+ raise error if !error.nil?
4751
+ raise 'no response'
4752
+ end
4753
+ end
4754
+
4755
+ content_type = http_response.headers.fetch('Content-Type', 'application/octet-stream')
4756
+ if Utils.match_status_code(http_response.status, ['200'])
4757
+ if Utils.match_content_type(content_type, 'application/json')
4758
+ http_response = @sdk_configuration.hooks.after_success(
4759
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4760
+ hook_ctx: hook_ctx
4761
+ ),
4762
+ response: http_response
4763
+ )
4764
+ response_data = http_response.env.response_body
4765
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Components::BiometricCredentialList)
4766
+ response = Models::Operations::ListUserBiometricCredentialsResponse.new(
4767
+ status_code: http_response.status,
4768
+ content_type: content_type,
4769
+ raw_response: http_response,
4770
+ biometric_credential_list: obj
4771
+ )
4772
+
4773
+ return response
4774
+ else
4775
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
4776
+ end
4777
+ elsif Utils.match_status_code(http_response.status, ['403', '404'])
4778
+ if Utils.match_content_type(content_type, 'application/json')
4779
+ http_response = @sdk_configuration.hooks.after_success(
4780
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4781
+ hook_ctx: hook_ctx
4782
+ ),
4783
+ response: http_response
4784
+ )
4785
+ response_data = http_response.env.response_body
4786
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Errors::ClerkErrors)
4787
+ obj.raw_response = http_response
4788
+ raise obj
4789
+ else
4790
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
4791
+ end
4792
+ elsif Utils.match_status_code(http_response.status, ['500'])
4793
+ if Utils.match_content_type(content_type, 'application/json')
4794
+ http_response = @sdk_configuration.hooks.after_success(
4795
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4796
+ hook_ctx: hook_ctx
4797
+ ),
4798
+ response: http_response
4799
+ )
4800
+ response_data = http_response.env.response_body
4801
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Errors::ClerkErrors)
4802
+ obj.raw_response = http_response
4803
+ raise obj
4804
+ else
4805
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
4806
+ end
4807
+ elsif Utils.match_status_code(http_response.status, ['4XX'])
4808
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
4809
+ elsif Utils.match_status_code(http_response.status, ['5XX'])
4810
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
4811
+ else
4812
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown status code received'
4813
+
4814
+ end
4815
+ end
4816
+
4817
+
4818
+
4819
+ def revoke_biometric_credential(user_id:, biometric_credential_id:, retries: nil, timeout_ms: nil, http_headers: nil)
4820
+ # revoke_biometric_credential - Revoke a user's biometric credential
4821
+ # Revokes an active biometric credential enrolled by the user.
4822
+ request = Models::Operations::RevokeUserBiometricCredentialRequest.new(
4823
+ user_id: user_id,
4824
+ biometric_credential_id: biometric_credential_id
4825
+ )
4826
+ url, params = @sdk_configuration.get_server_details
4827
+ base_url = Utils.template_url(url, params)
4828
+ url = Utils.generate_url(
4829
+ Models::Operations::RevokeUserBiometricCredentialRequest,
4830
+ base_url,
4831
+ '/users/{user_id}/biometric_credentials/{biometric_credential_id}',
4832
+ request
4833
+ )
4834
+ headers = {}
4835
+
4836
+ headers['Accept'] = 'application/json'
4837
+ headers['user-agent'] = @sdk_configuration.user_agent
4838
+ retries ||= @sdk_configuration.retry_config
4839
+ retries ||= Utils::RetryConfig.new(
4840
+ backoff: Utils::BackoffStrategy.new(
4841
+ exponent: 1.5,
4842
+ initial_interval: 500,
4843
+ max_elapsed_time: 3_600_000,
4844
+ max_interval: 60_000
4845
+ ),
4846
+ retry_connection_errors: true,
4847
+ strategy: 'backoff'
4848
+ )
4849
+ retry_options = retries.to_faraday_retry_options(initial_time: Time.now)
4850
+ retry_options[:retry_statuses] = [500, 501, 502, 503, 504, 505]
4851
+
4852
+ security = @sdk_configuration.security_source&.call
4853
+
4854
+ timeout = (timeout_ms.to_f / 1000) unless timeout_ms.nil?
4855
+ timeout ||= @sdk_configuration.timeout
4856
+
4857
+
4858
+ connection = @sdk_configuration.client.dup
4859
+ connection.use Utils::RetryMiddleware, retry_options
4860
+
4861
+ hook_ctx = SDKHooks::HookContext.new(
4862
+ config: @sdk_configuration,
4863
+ base_url: base_url,
4864
+ oauth2_scopes: nil,
4865
+ operation_id: 'RevokeUserBiometricCredential',
4866
+ security_source: @sdk_configuration.security_source
4867
+ )
4868
+
4869
+ error = nil
4870
+ http_response = nil
4871
+
4872
+
4873
+ begin
4874
+ http_response = connection.delete(url) do |req|
4875
+ req.headers.merge!(headers)
4876
+ req.options.timeout = timeout unless timeout.nil?
4877
+ Utils.configure_request_security(req, security)
4878
+ http_headers&.each do |key, value|
4879
+ req.headers[key.to_s] = value
4880
+ end
4881
+
4882
+ @sdk_configuration.hooks.before_request(
4883
+ hook_ctx: SDKHooks::BeforeRequestHookContext.new(
4884
+ hook_ctx: hook_ctx
4885
+ ),
4886
+ request: req
4887
+ )
4888
+ end
4889
+ rescue StandardError => e
4890
+ error = e
4891
+ ensure
4892
+ if http_response.nil? || Utils.error_status?(http_response.status)
4893
+ http_response = @sdk_configuration.hooks.after_error(
4894
+ error: error,
4895
+ hook_ctx: SDKHooks::AfterErrorHookContext.new(
4896
+ hook_ctx: hook_ctx
4897
+ ),
4898
+ response: http_response
4899
+ )
4900
+ else
4901
+ http_response = @sdk_configuration.hooks.after_success(
4902
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4903
+ hook_ctx: hook_ctx
4904
+ ),
4905
+ response: http_response
4906
+ )
4907
+ end
4908
+
4909
+ if http_response.nil?
4910
+ raise error if !error.nil?
4911
+ raise 'no response'
4912
+ end
4913
+ end
4914
+
4915
+ content_type = http_response.headers.fetch('Content-Type', 'application/octet-stream')
4916
+ if Utils.match_status_code(http_response.status, ['200'])
4917
+ if Utils.match_content_type(content_type, 'application/json')
4918
+ http_response = @sdk_configuration.hooks.after_success(
4919
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4920
+ hook_ctx: hook_ctx
4921
+ ),
4922
+ response: http_response
4923
+ )
4924
+ response_data = http_response.env.response_body
4925
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Components::BiometricCredential)
4926
+ response = Models::Operations::RevokeUserBiometricCredentialResponse.new(
4927
+ status_code: http_response.status,
4928
+ content_type: content_type,
4929
+ raw_response: http_response,
4930
+ biometric_credential: obj
4931
+ )
4932
+
4933
+ return response
4934
+ else
4935
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
4936
+ end
4937
+ elsif Utils.match_status_code(http_response.status, ['403', '404'])
4938
+ if Utils.match_content_type(content_type, 'application/json')
4939
+ http_response = @sdk_configuration.hooks.after_success(
4940
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4941
+ hook_ctx: hook_ctx
4942
+ ),
4943
+ response: http_response
4944
+ )
4945
+ response_data = http_response.env.response_body
4946
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Errors::ClerkErrors)
4947
+ obj.raw_response = http_response
4948
+ raise obj
4949
+ else
4950
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
4951
+ end
4952
+ elsif Utils.match_status_code(http_response.status, ['500'])
4953
+ if Utils.match_content_type(content_type, 'application/json')
4954
+ http_response = @sdk_configuration.hooks.after_success(
4955
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
4956
+ hook_ctx: hook_ctx
4957
+ ),
4958
+ response: http_response
4959
+ )
4960
+ response_data = http_response.env.response_body
4961
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Errors::ClerkErrors)
4962
+ obj.raw_response = http_response
4963
+ raise obj
4964
+ else
4965
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
4966
+ end
4967
+ elsif Utils.match_status_code(http_response.status, ['4XX'])
4968
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
4969
+ elsif Utils.match_status_code(http_response.status, ['5XX'])
4970
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
4971
+ else
4972
+ raise ::Clerk::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown status code received'
4973
+
4974
+ end
4975
+ end
4976
+
4977
+
4978
+
4651
4979
  def delete_web3_wallet(user_id:, web3_wallet_identification_id:, retries: nil, timeout_ms: nil, http_headers: nil)
4652
4980
  # delete_web3_wallet - Delete a user web3 wallet
4653
4981
  # Delete the web3 wallet identification for a given user.
@@ -78,11 +78,15 @@ module Clerk
78
78
 
79
79
 
80
80
  def self.match_content_type(content_type, pattern)
81
- return true if content_type == pattern || ['*', '*/*'].include?(pattern)
81
+ return true if ['*', '*/*'].include?(pattern)
82
+
83
+ # Media types are case-insensitive (RFC 9110 section 8.3.1).
84
+ pattern = pattern.strip.downcase
85
+ return true if content_type.strip.downcase == pattern
82
86
 
83
87
  pieces = content_type.split(';')
84
88
  pieces.each do |piece|
85
- return true if pattern == piece.strip
89
+ return true if pattern == piece.strip.downcase
86
90
  end
87
91
 
88
92
  false
@@ -44,6 +44,7 @@ module Clerk
44
44
  autoload :OrganizationPermissions, 'clerk/organizationpermissions'
45
45
  autoload :RoleSets, 'clerk/rolesets'
46
46
  autoload :ScimDirectories, 'clerk/scimdirectories'
47
+ autoload :Directories, 'clerk/directories'
47
48
  autoload :AdminPortalLinkTokens, 'clerk/admin_portal_link_tokens'
48
49
  autoload :APIKeys, 'clerk/api_keys'
49
50
  autoload :M2m, 'clerk/m2m'
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../../lib/clerk'
5
+
6
+ module Clerk
7
+ # Coverage for Clerk::SDK#compute_org_permissions_from_v2_token, which decodes
8
+ # the `fea` / `o.per` / `o.fpm` triple of a v2 session token into
9
+ # `org:<feature>:<action>` strings.
10
+ class OrgPermissionsV2Test < Minitest::Test
11
+ ACTIONS = (0...64).map { |n| "act_#{n}" }.freeze
12
+
13
+ def sdk
14
+ @sdk ||= Clerk::SDK.new(secret_key: 'sk_test_not_used')
15
+ end
16
+
17
+ def permissions_for(fea:, per:, fpm:)
18
+ claims = {'fea' => fea, 'o' => {'per' => per, 'fpm' => fpm}}
19
+ sdk.send(:compute_org_permissions_from_v2_token, claims)
20
+ end
21
+
22
+ # --- happy path (regression guard) ----------------------------------------
23
+
24
+ def test_small_masks_decode_with_bit_zero_least_significant
25
+ result = permissions_for(
26
+ fea: 'o:leads,o:whatsapp',
27
+ per: 'chat_read,chat_send,connect,view_history',
28
+ fpm: '3,10'
29
+ )
30
+
31
+ assert_equal ['org:leads:chat_read', 'org:leads:chat_send',
32
+ 'org:whatsapp:chat_send', 'org:whatsapp:view_history'], result
33
+ end
34
+
35
+ def test_zero_mask_grants_nothing
36
+ assert_empty permissions_for(fea: 'o:leads', per: 'chat_read,chat_send', fpm: '0')
37
+ end
38
+
39
+ def test_non_org_scoped_features_are_skipped
40
+ result = permissions_for(
41
+ fea: 'u:billing,o:leads',
42
+ per: 'chat_read,chat_send',
43
+ fpm: '3,1'
44
+ )
45
+
46
+ assert_equal ['org:leads:chat_read'], result
47
+ end
48
+
49
+ # --- wide masks ------------------------------------------------------------
50
+
51
+ def test_mask_with_bit_62_set
52
+ result = permissions_for(fea: 'o:leads', per: ACTIONS.join(','), fpm: (2**62).to_s)
53
+
54
+ assert_equal ['org:leads:act_62'], result
55
+ end
56
+
57
+ def test_positive_bignum_mask_with_bit_63_set
58
+ # 2**63 + 1 -- above the signed 64-bit range, but Ruby Integers are
59
+ # arbitrary-precision so this must still decode to indices 0 and 63.
60
+ result = permissions_for(fea: 'o:leads', per: ACTIONS.join(','), fpm: '9223372036854775809')
61
+
62
+ assert_equal ['org:leads:act_0', 'org:leads:act_63'], result
63
+ end
64
+
65
+ # --- the security regression: negative masks must fail closed --------------
66
+
67
+ def test_negative_mask_grants_nothing
68
+ # A signed 64-bit overflow on the producing side yields a negative mask.
69
+ # `(-9223372036854775807).to_s(2)` is "-111...1", which -- walked character
70
+ # by character -- would otherwise grant 63 permissions.
71
+ result = permissions_for(fea: 'o:leads', per: ACTIONS.join(','), fpm: '-9223372036854775807')
72
+
73
+ assert_empty result
74
+ end
75
+
76
+ def test_negative_mask_does_not_affect_other_features
77
+ result = permissions_for(
78
+ fea: 'o:leads,o:whatsapp',
79
+ per: ACTIONS.join(','),
80
+ fpm: '3,-9223372036854775807'
81
+ )
82
+
83
+ assert_equal ['org:leads:act_0', 'org:leads:act_1'], result
84
+ end
85
+
86
+ def test_non_numeric_masks_grant_nothing
87
+ ['abc', '1e3', '0x10', ' 3', '3 ', '1.5', '+3', ''].each do |mask|
88
+ assert_empty permissions_for(fea: 'o:leads', per: ACTIONS.join(','), fpm: mask),
89
+ "expected mask #{mask.inspect} to grant nothing"
90
+ end
91
+ end
92
+
93
+ # --- malformed claims must not raise ---------------------------------------
94
+
95
+ def test_more_mappings_than_features_does_not_raise
96
+ result = permissions_for(fea: 'o:leads', per: 'chat_read,chat_send', fpm: '1,3,7')
97
+
98
+ assert_equal ['org:leads:chat_read'], result
99
+ end
100
+
101
+ def test_feature_without_a_scope_separator_does_not_raise
102
+ result = permissions_for(fea: 'leads,o:whatsapp', per: 'chat_read', fpm: '1,1')
103
+
104
+ assert_equal ['org:whatsapp:chat_read'], result
105
+ end
106
+
107
+ def test_missing_claims_do_not_raise
108
+ assert_empty permissions_for(fea: nil, per: nil, fpm: nil)
109
+ assert_empty permissions_for(fea: 'o:leads', per: nil, fpm: '3')
110
+ assert_empty permissions_for(fea: nil, per: 'chat_read', fpm: '3')
111
+ end
112
+
113
+ # --- masks wider than the permission vocabulary ----------------------------
114
+
115
+ def test_mask_wider_than_permission_list_does_not_emit_empty_permissions
116
+ # 0b1111 against a two-action vocabulary: only the first two bits map.
117
+ result = permissions_for(fea: 'o:leads', per: 'chat_read,chat_send', fpm: '15')
118
+
119
+ assert_equal ['org:leads:chat_read', 'org:leads:chat_send'], result
120
+ refute(result.any? { |permission| permission.end_with?(':') },
121
+ "expected no permissions with an empty action name, got #{result.inspect}")
122
+ end
123
+
124
+ def test_high_bit_beyond_permission_list_is_ignored
125
+ result = permissions_for(fea: 'o:leads', per: 'chat_read', fpm: (2**63 | 1).to_s)
126
+
127
+ assert_equal ['org:leads:chat_read'], result
128
+ end
129
+ end
130
+ end