stripe 4.21.3 → 5.52.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (226) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +254 -1
  3. data/CODE_OF_CONDUCT.md +77 -0
  4. data/Gemfile +10 -16
  5. data/Makefile +7 -0
  6. data/README.md +115 -47
  7. data/Rakefile +8 -7
  8. data/VERSION +1 -1
  9. data/lib/stripe/api_operations/create.rb +1 -1
  10. data/lib/stripe/api_operations/delete.rb +7 -3
  11. data/lib/stripe/api_operations/list.rb +1 -12
  12. data/lib/stripe/api_operations/nested_resource.rb +29 -26
  13. data/lib/stripe/api_operations/request.rb +82 -6
  14. data/lib/stripe/api_operations/save.rb +7 -4
  15. data/lib/stripe/api_operations/search.rb +19 -0
  16. data/lib/stripe/api_resource.rb +22 -17
  17. data/lib/stripe/api_resource_test_helpers.rb +47 -0
  18. data/lib/stripe/connection_manager.rb +200 -0
  19. data/lib/stripe/error_object.rb +93 -0
  20. data/lib/stripe/errors.rb +24 -3
  21. data/lib/stripe/instrumentation.rb +84 -0
  22. data/lib/stripe/list_object.rb +34 -5
  23. data/lib/stripe/multipart_encoder.rb +131 -0
  24. data/lib/stripe/oauth.rb +8 -6
  25. data/lib/stripe/object_types.rb +20 -5
  26. data/lib/stripe/resources/account.rb +12 -16
  27. data/lib/stripe/resources/account_link.rb +2 -1
  28. data/lib/stripe/resources/alipay_account.rb +1 -1
  29. data/lib/stripe/resources/apple_pay_domain.rb +2 -1
  30. data/lib/stripe/resources/application_fee.rb +2 -12
  31. data/lib/stripe/resources/application_fee_refund.rb +3 -2
  32. data/lib/stripe/resources/balance.rb +2 -1
  33. data/lib/stripe/resources/balance_transaction.rb +2 -5
  34. data/lib/stripe/resources/bank_account.rb +3 -2
  35. data/lib/stripe/resources/billing_portal/configuration.rb +14 -0
  36. data/lib/stripe/resources/billing_portal/session.rb +12 -0
  37. data/lib/stripe/resources/bitcoin_receiver.rb +2 -1
  38. data/lib/stripe/resources/bitcoin_transaction.rb +4 -3
  39. data/lib/stripe/resources/capability.rb +3 -2
  40. data/lib/stripe/resources/card.rb +2 -1
  41. data/lib/stripe/resources/charge.rb +13 -65
  42. data/lib/stripe/resources/checkout/session.rb +17 -1
  43. data/lib/stripe/resources/country_spec.rb +2 -1
  44. data/lib/stripe/resources/coupon.rb +2 -1
  45. data/lib/stripe/resources/credit_note.rb +18 -3
  46. data/lib/stripe/resources/credit_note_line_item.rb +8 -0
  47. data/lib/stripe/resources/customer.rb +35 -59
  48. data/lib/stripe/resources/customer_balance_transaction.rb +4 -3
  49. data/lib/stripe/resources/discount.rb +2 -1
  50. data/lib/stripe/resources/dispute.rb +8 -9
  51. data/lib/stripe/resources/ephemeral_key.rb +2 -1
  52. data/lib/stripe/resources/event.rb +2 -1
  53. data/lib/stripe/resources/exchange_rate.rb +2 -1
  54. data/lib/stripe/resources/file.rb +6 -14
  55. data/lib/stripe/resources/file_link.rb +2 -1
  56. data/lib/stripe/resources/funding_instructions.rb +16 -0
  57. data/lib/stripe/resources/identity/verification_report.rb +12 -0
  58. data/lib/stripe/resources/identity/verification_session.rb +35 -0
  59. data/lib/stripe/resources/invoice.rb +47 -12
  60. data/lib/stripe/resources/invoice_item.rb +2 -1
  61. data/lib/stripe/resources/invoice_line_item.rb +2 -1
  62. data/lib/stripe/resources/issuing/authorization.rb +14 -5
  63. data/lib/stripe/resources/issuing/card.rb +8 -3
  64. data/lib/stripe/resources/issuing/card_details.rb +3 -2
  65. data/lib/stripe/resources/issuing/cardholder.rb +2 -1
  66. data/lib/stripe/resources/issuing/dispute.rb +13 -1
  67. data/lib/stripe/resources/issuing/transaction.rb +2 -1
  68. data/lib/stripe/resources/line_item.rb +8 -0
  69. data/lib/stripe/resources/login_link.rb +2 -1
  70. data/lib/stripe/resources/mandate.rb +8 -0
  71. data/lib/stripe/resources/order.rb +14 -13
  72. data/lib/stripe/resources/order_return.rb +2 -1
  73. data/lib/stripe/resources/payment_intent.rb +59 -7
  74. data/lib/stripe/resources/payment_link.rb +23 -0
  75. data/lib/stripe/resources/payment_method.rb +14 -5
  76. data/lib/stripe/resources/payout.rb +16 -7
  77. data/lib/stripe/resources/person.rb +2 -1
  78. data/lib/stripe/resources/plan.rb +2 -1
  79. data/lib/stripe/resources/price.rb +21 -0
  80. data/lib/stripe/resources/product.rb +11 -1
  81. data/lib/stripe/resources/promotion_code.rb +12 -0
  82. data/lib/stripe/resources/quote.rb +105 -0
  83. data/lib/stripe/resources/radar/early_fraud_warning.rb +2 -1
  84. data/lib/stripe/resources/radar/value_list.rb +2 -1
  85. data/lib/stripe/resources/radar/value_list_item.rb +2 -1
  86. data/lib/stripe/resources/recipient.rb +2 -5
  87. data/lib/stripe/resources/recipient_transfer.rb +1 -1
  88. data/lib/stripe/resources/refund.rb +13 -1
  89. data/lib/stripe/resources/reporting/report_run.rb +2 -1
  90. data/lib/stripe/resources/reporting/report_type.rb +2 -1
  91. data/lib/stripe/resources/reversal.rb +4 -3
  92. data/lib/stripe/resources/review.rb +8 -3
  93. data/lib/stripe/resources/setup_attempt.rb +10 -0
  94. data/lib/stripe/resources/setup_intent.rb +24 -5
  95. data/lib/stripe/resources/shipping_rate.rb +12 -0
  96. data/lib/stripe/resources/sigma/scheduled_query_run.rb +2 -1
  97. data/lib/stripe/resources/sku.rb +2 -1
  98. data/lib/stripe/resources/source.rb +17 -12
  99. data/lib/stripe/resources/source_transaction.rb +2 -1
  100. data/lib/stripe/resources/subscription.rb +16 -6
  101. data/lib/stripe/resources/subscription_item.rb +11 -2
  102. data/lib/stripe/resources/subscription_schedule.rb +14 -13
  103. data/lib/stripe/resources/tax_code.rb +10 -0
  104. data/lib/stripe/resources/tax_id.rb +2 -1
  105. data/lib/stripe/resources/tax_rate.rb +2 -1
  106. data/lib/stripe/resources/terminal/configuration.rb +15 -0
  107. data/lib/stripe/resources/terminal/connection_token.rb +2 -1
  108. data/lib/stripe/resources/terminal/location.rb +2 -1
  109. data/lib/stripe/resources/terminal/reader.rb +62 -1
  110. data/lib/stripe/resources/test_helpers/test_clock.rb +25 -0
  111. data/lib/stripe/resources/three_d_secure.rb +2 -1
  112. data/lib/stripe/resources/token.rb +2 -1
  113. data/lib/stripe/resources/topup.rb +8 -3
  114. data/lib/stripe/resources/transfer.rb +8 -8
  115. data/lib/stripe/resources/usage_record.rb +2 -17
  116. data/lib/stripe/resources/usage_record_summary.rb +2 -1
  117. data/lib/stripe/resources/webhook_endpoint.rb +2 -1
  118. data/lib/stripe/resources.rb +18 -2
  119. data/lib/stripe/search_result_object.rb +86 -0
  120. data/lib/stripe/stripe_client.rb +617 -243
  121. data/lib/stripe/stripe_configuration.rb +194 -0
  122. data/lib/stripe/stripe_object.rb +30 -25
  123. data/lib/stripe/stripe_response.rb +87 -27
  124. data/lib/stripe/util.rb +88 -18
  125. data/lib/stripe/version.rb +1 -1
  126. data/lib/stripe/webhook.rb +39 -8
  127. data/lib/stripe.rb +43 -131
  128. data/stripe.gemspec +17 -13
  129. metadata +36 -220
  130. data/.editorconfig +0 -10
  131. data/.gitattributes +0 -4
  132. data/.github/ISSUE_TEMPLATE.md +0 -5
  133. data/.gitignore +0 -8
  134. data/.rubocop.yml +0 -43
  135. data/.rubocop_todo.yml +0 -38
  136. data/.travis.yml +0 -43
  137. data/.vscode/extensions.json +0 -7
  138. data/.vscode/settings.json +0 -8
  139. data/lib/stripe/resources/issuer_fraud_record.rb +0 -9
  140. data/lib/stripe/resources/subscription_schedule_revision.rb +0 -34
  141. data/test/api_stub_helpers.rb +0 -1
  142. data/test/openapi/README.md +0 -9
  143. data/test/stripe/account_link_test.rb +0 -18
  144. data/test/stripe/account_test.rb +0 -428
  145. data/test/stripe/alipay_account_test.rb +0 -37
  146. data/test/stripe/api_operations_test.rb +0 -80
  147. data/test/stripe/api_resource_test.rb +0 -544
  148. data/test/stripe/apple_pay_domain_test.rb +0 -46
  149. data/test/stripe/application_fee_refund_test.rb +0 -37
  150. data/test/stripe/application_fee_test.rb +0 -58
  151. data/test/stripe/balance_test.rb +0 -13
  152. data/test/stripe/bank_account_test.rb +0 -36
  153. data/test/stripe/capability_test.rb +0 -45
  154. data/test/stripe/charge_test.rb +0 -80
  155. data/test/stripe/checkout/session_test.rb +0 -41
  156. data/test/stripe/country_spec_test.rb +0 -20
  157. data/test/stripe/coupon_test.rb +0 -61
  158. data/test/stripe/credit_note_test.rb +0 -61
  159. data/test/stripe/customer_balance_transaction_test.rb +0 -37
  160. data/test/stripe/customer_card_test.rb +0 -42
  161. data/test/stripe/customer_test.rb +0 -269
  162. data/test/stripe/dispute_test.rb +0 -51
  163. data/test/stripe/ephemeral_key_test.rb +0 -93
  164. data/test/stripe/errors_test.rb +0 -20
  165. data/test/stripe/exchange_rate_test.rb +0 -20
  166. data/test/stripe/file_link_test.rb +0 -41
  167. data/test/stripe/file_test.rb +0 -97
  168. data/test/stripe/file_upload_test.rb +0 -79
  169. data/test/stripe/invoice_item_test.rb +0 -66
  170. data/test/stripe/invoice_line_item_test.rb +0 -8
  171. data/test/stripe/invoice_test.rb +0 -213
  172. data/test/stripe/issuer_fraud_record_test.rb +0 -20
  173. data/test/stripe/issuing/authorization_test.rb +0 -72
  174. data/test/stripe/issuing/card_test.rb +0 -62
  175. data/test/stripe/issuing/cardholder_test.rb +0 -53
  176. data/test/stripe/issuing/dispute_test.rb +0 -45
  177. data/test/stripe/issuing/transaction_test.rb +0 -48
  178. data/test/stripe/list_object_test.rb +0 -156
  179. data/test/stripe/login_link_test.rb +0 -37
  180. data/test/stripe/oauth_test.rb +0 -88
  181. data/test/stripe/order_return_test.rb +0 -21
  182. data/test/stripe/order_test.rb +0 -82
  183. data/test/stripe/payment_intent_test.rb +0 -107
  184. data/test/stripe/payment_method_test.rb +0 -84
  185. data/test/stripe/payout_test.rb +0 -57
  186. data/test/stripe/person_test.rb +0 -46
  187. data/test/stripe/plan_test.rb +0 -98
  188. data/test/stripe/product_test.rb +0 -59
  189. data/test/stripe/radar/early_fraud_warning_test.rb +0 -22
  190. data/test/stripe/radar/value_list_item_test.rb +0 -48
  191. data/test/stripe/radar/value_list_test.rb +0 -61
  192. data/test/stripe/recipient_test.rb +0 -62
  193. data/test/stripe/refund_test.rb +0 -39
  194. data/test/stripe/reporting/report_run_test.rb +0 -33
  195. data/test/stripe/reporting/report_type_test.rb +0 -22
  196. data/test/stripe/reversal_test.rb +0 -43
  197. data/test/stripe/review_test.rb +0 -27
  198. data/test/stripe/setup_intent_test.rb +0 -84
  199. data/test/stripe/sigma/scheduled_query_run_test.rb +0 -22
  200. data/test/stripe/sku_test.rb +0 -60
  201. data/test/stripe/source_test.rb +0 -99
  202. data/test/stripe/source_transaction_test.rb +0 -19
  203. data/test/stripe/stripe_client_test.rb +0 -842
  204. data/test/stripe/stripe_object_test.rb +0 -525
  205. data/test/stripe/stripe_response_test.rb +0 -49
  206. data/test/stripe/subscription_item_test.rb +0 -63
  207. data/test/stripe/subscription_schedule_revision_test.rb +0 -37
  208. data/test/stripe/subscription_schedule_test.rb +0 -116
  209. data/test/stripe/subscription_test.rb +0 -80
  210. data/test/stripe/tax_id_test.rb +0 -31
  211. data/test/stripe/tax_rate_test.rb +0 -43
  212. data/test/stripe/terminal/connection_token_test.rb +0 -16
  213. data/test/stripe/terminal/location_test.rb +0 -68
  214. data/test/stripe/terminal/reader_test.rb +0 -62
  215. data/test/stripe/three_d_secure_test.rb +0 -23
  216. data/test/stripe/topup_test.rb +0 -62
  217. data/test/stripe/transfer_test.rb +0 -88
  218. data/test/stripe/usage_record_summary_test.rb +0 -19
  219. data/test/stripe/usage_record_test.rb +0 -28
  220. data/test/stripe/util_test.rb +0 -402
  221. data/test/stripe/webhook_endpoint_test.rb +0 -59
  222. data/test/stripe/webhook_test.rb +0 -96
  223. data/test/stripe_mock.rb +0 -77
  224. data/test/stripe_test.rb +0 -63
  225. data/test/test_data.rb +0 -61
  226. data/test/test_helper.rb +0 -71
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Stripe
4
+ # Configurable options:
5
+ #
6
+ # =ca_bundle_path=
7
+ # The location of a file containing a bundle of CA certificates. By default
8
+ # the library will use an included bundle that can successfully validate
9
+ # Stripe certificates.
10
+ #
11
+ # =log_level=
12
+ # When set prompts the library to log some extra information to $stdout and
13
+ # $stderr about what it's doing. For example, it'll produce information about
14
+ # requests, responses, and errors that are received. Valid log levels are
15
+ # `debug` and `info`, with `debug` being a little more verbose in places.
16
+ #
17
+ # Use of this configuration is only useful when `.logger` is _not_ set. When
18
+ # it is, the decision what levels to print is entirely deferred to the logger.
19
+ #
20
+ # =logger=
21
+ # The logger should support the same interface as the `Logger` class that's
22
+ # part of Ruby's standard library (hint, anything in `Rails.logger` will
23
+ # likely be suitable).
24
+ #
25
+ # If `.logger` is set, the value of `.log_level` is ignored. The decision on
26
+ # what levels to print is entirely deferred to the logger.
27
+ class StripeConfiguration
28
+ attr_accessor :api_key
29
+ attr_accessor :api_version
30
+ attr_accessor :client_id
31
+ attr_accessor :enable_telemetry
32
+ attr_accessor :logger
33
+ attr_accessor :stripe_account
34
+
35
+ attr_reader :api_base
36
+ attr_reader :uploads_base
37
+ attr_reader :connect_base
38
+ attr_reader :ca_bundle_path
39
+ attr_reader :log_level
40
+ attr_reader :initial_network_retry_delay
41
+ attr_reader :max_network_retries
42
+ attr_reader :max_network_retry_delay
43
+ attr_reader :open_timeout
44
+ attr_reader :read_timeout
45
+ attr_reader :write_timeout
46
+ attr_reader :proxy
47
+ attr_reader :verify_ssl_certs
48
+
49
+ def self.setup
50
+ new.tap do |instance|
51
+ yield(instance) if block_given?
52
+ end
53
+ end
54
+
55
+ # Create a new config based off an existing one. This is useful when the
56
+ # caller wants to override the global configuration
57
+ def reverse_duplicate_merge(hash)
58
+ dup.tap do |instance|
59
+ hash.each do |option, value|
60
+ instance.public_send("#{option}=", value)
61
+ end
62
+ end
63
+ end
64
+
65
+ def initialize
66
+ @ca_bundle_path = Stripe::DEFAULT_CA_BUNDLE_PATH
67
+ @enable_telemetry = true
68
+ @verify_ssl_certs = true
69
+
70
+ @max_network_retries = 0
71
+ @initial_network_retry_delay = 0.5
72
+ @max_network_retry_delay = 2
73
+
74
+ @open_timeout = 30
75
+ @read_timeout = 80
76
+ @write_timeout = 30
77
+
78
+ @api_base = "https://api.stripe.com"
79
+ @connect_base = "https://connect.stripe.com"
80
+ @uploads_base = "https://files.stripe.com"
81
+ end
82
+
83
+ def log_level=(val)
84
+ # Backwards compatibility for values that we briefly allowed
85
+ if val == "debug"
86
+ val = Stripe::LEVEL_DEBUG
87
+ elsif val == "info"
88
+ val = Stripe::LEVEL_INFO
89
+ end
90
+
91
+ levels = [Stripe::LEVEL_INFO, Stripe::LEVEL_DEBUG, Stripe::LEVEL_ERROR]
92
+
93
+ if !val.nil? && !levels.include?(val)
94
+ raise ArgumentError,
95
+ "log_level should only be set to `nil`, `debug` or `info`"
96
+ end
97
+ @log_level = val
98
+ end
99
+
100
+ def max_network_retries=(val)
101
+ @max_network_retries = val.to_i
102
+ end
103
+
104
+ def max_network_retry_delay=(val)
105
+ @max_network_retry_delay = val.to_i
106
+ end
107
+
108
+ def initial_network_retry_delay=(val)
109
+ @initial_network_retry_delay = val.to_i
110
+ end
111
+
112
+ def open_timeout=(open_timeout)
113
+ @open_timeout = open_timeout
114
+ StripeClient.clear_all_connection_managers(config: self)
115
+ end
116
+
117
+ def read_timeout=(read_timeout)
118
+ @read_timeout = read_timeout
119
+ StripeClient.clear_all_connection_managers(config: self)
120
+ end
121
+
122
+ def write_timeout=(write_timeout)
123
+ unless Net::HTTP.instance_methods.include?(:write_timeout=)
124
+ raise NotImplementedError
125
+ end
126
+
127
+ @write_timeout = write_timeout
128
+ StripeClient.clear_all_connection_managers(config: self)
129
+ end
130
+
131
+ def proxy=(proxy)
132
+ @proxy = proxy
133
+ StripeClient.clear_all_connection_managers(config: self)
134
+ end
135
+
136
+ def verify_ssl_certs=(verify_ssl_certs)
137
+ @verify_ssl_certs = verify_ssl_certs
138
+ StripeClient.clear_all_connection_managers(config: self)
139
+ end
140
+
141
+ def uploads_base=(uploads_base)
142
+ @uploads_base = uploads_base
143
+ StripeClient.clear_all_connection_managers(config: self)
144
+ end
145
+
146
+ def connect_base=(connect_base)
147
+ @connect_base = connect_base
148
+ StripeClient.clear_all_connection_managers(config: self)
149
+ end
150
+
151
+ def api_base=(api_base)
152
+ @api_base = api_base
153
+ StripeClient.clear_all_connection_managers(config: self)
154
+ end
155
+
156
+ def ca_bundle_path=(path)
157
+ @ca_bundle_path = path
158
+
159
+ # empty this field so a new store is initialized
160
+ @ca_store = nil
161
+
162
+ StripeClient.clear_all_connection_managers(config: self)
163
+ end
164
+
165
+ # A certificate store initialized from the the bundle in #ca_bundle_path and
166
+ # which is used to validate TLS on every request.
167
+ #
168
+ # This was added to the give the gem "pseudo thread safety" in that it seems
169
+ # when initiating many parallel requests marshaling the certificate store is
170
+ # the most likely point of failure (see issue #382). Any program attempting
171
+ # to leverage this pseudo safety should make a call to this method (i.e.
172
+ # `Stripe.ca_store`) in their initialization code because it marshals lazily
173
+ # and is itself not thread safe.
174
+ def ca_store
175
+ @ca_store ||= begin
176
+ store = OpenSSL::X509::Store.new
177
+ store.add_file(ca_bundle_path)
178
+ store
179
+ end
180
+ end
181
+
182
+ def enable_telemetry?
183
+ enable_telemetry
184
+ end
185
+
186
+ # Generates a deterministic key to identify configuration objects with
187
+ # identical configuration values.
188
+ def key
189
+ instance_variables
190
+ .collect { |variable| instance_variable_get(variable) }
191
+ .join
192
+ end
193
+ end
194
+ end
@@ -127,18 +127,6 @@ module Stripe
127
127
  JSON.pretty_generate(@values)
128
128
  end
129
129
 
130
- # Re-initializes the object based on a hash of values (usually one that's
131
- # come back from an API call). Adds or removes value accessors as necessary
132
- # and updates the state of internal data.
133
- #
134
- # Please don't use this method. If you're trying to do mass assignment, try
135
- # #initialize_from instead.
136
- def refresh_from(values, opts, partial = false)
137
- initialize_from(values, opts, partial)
138
- end
139
- extend Gem::Deprecate
140
- deprecate :refresh_from, "#update_attributes", 2016, 1
141
-
142
130
  # Mass assigns attributes on the model.
143
131
  #
144
132
  # This is a version of +update_attributes+ that takes some extra options
@@ -147,7 +135,8 @@ module Stripe
147
135
  # ==== Attributes
148
136
  #
149
137
  # * +values+ - Hash of values to use to update the current attributes of
150
- # the object.
138
+ # the object. If you are on ruby 2.7 or higher make sure to wrap in curly
139
+ # braces to be ruby 3 compatible.
151
140
  # * +opts+ - Options for +StripeObject+ like an API key that will be reused
152
141
  # on subsequent API calls.
153
142
  #
@@ -192,7 +181,9 @@ module Stripe
192
181
 
193
182
  def to_hash
194
183
  maybe_to_hash = lambda do |value|
195
- value && value.respond_to?(:to_hash) ? value.to_hash : value
184
+ return nil if value.nil?
185
+
186
+ value.respond_to?(:to_hash) ? value.to_hash : value
196
187
  end
197
188
 
198
189
  @values.each_with_object({}) do |(key, value), acc|
@@ -256,6 +247,7 @@ module Stripe
256
247
  #
257
248
  unsaved = @unsaved_values.include?(k)
258
249
  next unless options[:force] || unsaved || v.is_a?(StripeObject)
250
+
259
251
  update_hash[k.to_sym] = serialize_params_value(
260
252
  @values[k], @original_values[k], unsaved, options[:force], key: k
261
253
  )
@@ -268,16 +260,6 @@ module Stripe
268
260
  update_hash
269
261
  end
270
262
 
271
- class << self
272
- # This class method has been deprecated in favor of the instance method
273
- # of the same name.
274
- def serialize_params(obj, options = {})
275
- obj.serialize_params(options)
276
- end
277
- extend Gem::Deprecate
278
- deprecate :serialize_params, "#serialize_params", 2016, 9
279
- end
280
-
281
263
  # A protected field is one that doesn't get an accessor assigned to it
282
264
  # (i.e. `obj.public = ...`) and one which is not allowed to be updated via
283
265
  # the class level `Model.update(id, { ... })`.
@@ -285,6 +267,27 @@ module Stripe
285
267
  []
286
268
  end
287
269
 
270
+ # When designing APIs, we now make a conscious effort server-side to avoid
271
+ # naming fields after important built-ins in various languages (e.g. class,
272
+ # method, etc.).
273
+ #
274
+ # However, a long time ago we made the mistake (either consciously or by
275
+ # accident) of initializing our `metadata` fields as instances of
276
+ # `StripeObject`, and metadata can have a wide range of different keys
277
+ # defined in it. This is somewhat a convenient in that it allows users to
278
+ # access data like `obj.metadata.my_field`, but is almost certainly not
279
+ # worth the cost.
280
+ #
281
+ # Naming metadata fields bad things like `class` causes `initialize_from`
282
+ # to produce strange results, so we ban known offenders here.
283
+ #
284
+ # In a future major version we should consider leaving `metadata` as a hash
285
+ # and forcing people to access it with `obj.metadata[:my_field]` because
286
+ # the potential for trouble is just too high. For now, reserve names.
287
+ RESERVED_FIELD_NAMES = [
288
+ :class,
289
+ ].freeze
290
+
288
291
  protected def metaclass
289
292
  class << self; self; end
290
293
  end
@@ -295,6 +298,7 @@ module Stripe
295
298
 
296
299
  metaclass.instance_eval do
297
300
  keys.each do |k|
301
+ next if RESERVED_FIELD_NAMES.include?(k)
298
302
  next if protected_fields.include?(k)
299
303
  next if @@permanent_attributes.include?(k)
300
304
 
@@ -330,6 +334,7 @@ module Stripe
330
334
 
331
335
  metaclass.instance_eval do
332
336
  keys.each do |k|
337
+ next if RESERVED_FIELD_NAMES.include?(k)
333
338
  next if protected_fields.include?(k)
334
339
  next if @@permanent_attributes.include?(k)
335
340
 
@@ -393,7 +398,7 @@ module Stripe
393
398
  begin
394
399
  super
395
400
  rescue NoMethodError => e
396
- # If we notice the accessed name if our set of transient values we can
401
+ # If we notice the accessed name of our set of transient values we can
397
402
  # give the user a slightly more helpful error message. If not, just
398
403
  # raise right away.
399
404
  raise unless @transient_values.include?(name)
@@ -1,16 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stripe
4
- # StripeResponse encapsulates some vitals of a response that came back from
5
- # the Stripe API.
6
- class StripeResponse
7
- # The data contained by the HTTP body of the response deserialized from
8
- # JSON.
9
- attr_accessor :data
4
+ # Headers provides an access wrapper to an API response's header data. It
5
+ # mainly exists so that we don't need to expose the entire
6
+ # `Net::HTTPResponse` object while still getting some of its benefits like
7
+ # case-insensitive access to header names and flattening of header values.
8
+ class StripeResponseHeaders
9
+ # Initializes a Headers object from a Net::HTTP::HTTPResponse object.
10
+ def self.from_net_http(resp)
11
+ new(resp.to_hash)
12
+ end
10
13
 
11
- # The raw HTTP body of the response.
12
- attr_accessor :http_body
14
+ # `hash` is expected to be a hash mapping header names to arrays of
15
+ # header values. This is the default format generated by calling
16
+ # `#to_hash` on a `Net::HTTPResponse` object because headers can be
17
+ # repeated multiple times. Using `#[]` will collapse values down to just
18
+ # the first.
19
+ def initialize(hash)
20
+ if !hash.is_a?(Hash) ||
21
+ !hash.keys.all? { |n| n.is_a?(String) } ||
22
+ !hash.values.all? { |a| a.is_a?(Array) } ||
23
+ !hash.values.all? { |a| a.all? { |v| v.is_a?(String) } }
24
+ raise ArgumentError,
25
+ "expect hash to be a map of string header names to arrays of " \
26
+ "header values"
27
+ end
13
28
 
29
+ @hash = {}
30
+
31
+ # This shouldn't be strictly necessary because `Net::HTTPResponse` will
32
+ # produce a hash with all headers downcased, but do it anyway just in
33
+ # case an object of this class was constructed manually.
34
+ #
35
+ # Also has the effect of duplicating the hash, which is desirable for a
36
+ # little extra object safety.
37
+ hash.each do |k, v|
38
+ @hash[k.downcase] = v
39
+ end
40
+ end
41
+
42
+ def [](name)
43
+ values = @hash[name.downcase]
44
+ if values && values.count > 1
45
+ warn("Duplicate header values for `#{name}`; returning only first")
46
+ end
47
+ values ? values.first : nil
48
+ end
49
+ end
50
+
51
+ module StripeResponseBase
14
52
  # A Hash of the HTTP headers of the response.
15
53
  attr_accessor :http_headers
16
54
 
@@ -20,30 +58,52 @@ module Stripe
20
58
  # The Stripe request ID of the response.
21
59
  attr_accessor :request_id
22
60
 
23
- # Initializes a StripeResponse object from a Hash like the kind returned as
24
- # part of a Faraday exception.
25
- #
26
- # This may throw JSON::ParserError if the response body is not valid JSON.
27
- def self.from_faraday_hash(http_resp)
28
- resp = StripeResponse.new
29
- resp.data = JSON.parse(http_resp[:body], symbolize_names: true)
30
- resp.http_body = http_resp[:body]
31
- resp.http_headers = http_resp[:headers]
32
- resp.http_status = http_resp[:status]
33
- resp.request_id = http_resp[:headers]["Request-Id"]
34
- resp
61
+ def self.populate_for_net_http(resp, http_resp)
62
+ resp.http_headers = StripeResponseHeaders.from_net_http(http_resp)
63
+ resp.http_status = http_resp.code.to_i
64
+ resp.request_id = http_resp["request-id"]
35
65
  end
66
+ end
36
67
 
37
- # Initializes a StripeResponse object from a Faraday HTTP response object.
38
- #
39
- # This may throw JSON::ParserError if the response body is not valid JSON.
40
- def self.from_faraday_response(http_resp)
68
+ # StripeResponse encapsulates some vitals of a response that came back from
69
+ # the Stripe API.
70
+ class StripeResponse
71
+ include StripeResponseBase
72
+ # The data contained by the HTTP body of the response deserialized from
73
+ # JSON.
74
+ attr_accessor :data
75
+
76
+ # The raw HTTP body of the response.
77
+ attr_accessor :http_body
78
+
79
+ # Initializes a StripeResponse object from a Net::HTTP::HTTPResponse
80
+ # object.
81
+ def self.from_net_http(http_resp)
41
82
  resp = StripeResponse.new
42
83
  resp.data = JSON.parse(http_resp.body, symbolize_names: true)
43
84
  resp.http_body = http_resp.body
44
- resp.http_headers = http_resp.headers
45
- resp.http_status = http_resp.status
46
- resp.request_id = http_resp.headers["Request-Id"]
85
+ StripeResponseBase.populate_for_net_http(resp, http_resp)
86
+ resp
87
+ end
88
+ end
89
+
90
+ # We have to alias StripeResponseHeaders to StripeResponse::Headers, as this
91
+ # class used to be embedded within StripeResponse and we want to be backwards
92
+ # compatible.
93
+ StripeResponse::Headers = StripeResponseHeaders
94
+
95
+ # StripeHeadersOnlyResponse includes only header-related vitals of the
96
+ # response. This is used for streaming requests where the response was read
97
+ # directly in a block and we explicitly don't want to store the body of the
98
+ # response in memory.
99
+ class StripeHeadersOnlyResponse
100
+ include StripeResponseBase
101
+
102
+ # Initializes a StripeHeadersOnlyResponse object from a
103
+ # Net::HTTP::HTTPResponse object.
104
+ def self.from_net_http(http_resp)
105
+ resp = StripeHeadersOnlyResponse.new
106
+ StripeResponseBase.populate_for_net_http(resp, http_resp)
47
107
  resp
48
108
  end
49
109
  end
data/lib/stripe/util.rb CHANGED
@@ -43,6 +43,57 @@ module Stripe
43
43
  @object_classes ||= Stripe::ObjectTypes.object_names_to_classes
44
44
  end
45
45
 
46
+ def self.object_name_matches_class?(object_name, klass)
47
+ Util.object_classes[object_name] == klass
48
+ end
49
+
50
+ # Adds a custom method to a resource class. This is used to add support for
51
+ # non-CRUDL API requests, e.g. capturing charges. custom_method takes the
52
+ # following parameters:
53
+ # - name: the name of the custom method to create (as a symbol)
54
+ # - http_verb: the HTTP verb for the API request (:get, :post, or :delete)
55
+ # - http_path: the path to append to the resource's URL. If not provided,
56
+ # the name is used as the path
57
+ # - resource: the resource implementation class
58
+ # - target: the class that custom static method will be added to
59
+ #
60
+ # For example, this call:
61
+ # custom_method :capture, http_verb: post
62
+ # adds a `capture` class method to the resource class that, when called,
63
+ # will send a POST request to `/v1/<object_name>/capture`.
64
+ def self.custom_method(resource, target, name, http_verb, http_path)
65
+ unless %i[get post delete].include?(http_verb)
66
+ raise ArgumentError,
67
+ "Invalid http_verb value: #{http_verb.inspect}. Should be one " \
68
+ "of :get, :post or :delete."
69
+ end
70
+ unless target.respond_to?(:resource_url)
71
+ raise ArgumentError,
72
+ "Invalid target value: #{target}. Target class should have a " \
73
+ "`resource_url` method."
74
+ end
75
+ http_path ||= name.to_s
76
+ target.define_singleton_method(name) do |id, params = {}, opts = {}|
77
+ unless id.is_a?(String)
78
+ raise ArgumentError,
79
+ "id should be a string representing the ID of an API resource"
80
+ end
81
+
82
+ url = "#{target.resource_url}/"\
83
+ "#{CGI.escape(id)}/"\
84
+ "#{CGI.escape(http_path)}"
85
+
86
+ resp, opts = resource.execute_resource_request(
87
+ http_verb,
88
+ url,
89
+ params,
90
+ opts
91
+ )
92
+
93
+ Util.convert_to_stripe_object(resp.data, opts)
94
+ end
95
+ end
96
+
46
97
  # Converts a hash of fields or an array of hashes into a +StripeObject+ or
47
98
  # array of +StripeObject+s. These new objects will be created as a concrete
48
99
  # type as dictated by their `object` field (e.g. an `object` value of
@@ -72,24 +123,30 @@ module Stripe
72
123
  end
73
124
 
74
125
  def self.log_error(message, data = {})
75
- if !Stripe.logger.nil? ||
76
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_ERROR
126
+ config = data.delete(:config) || Stripe.config
127
+ logger = config.logger || Stripe.logger
128
+ if !logger.nil? ||
129
+ !config.log_level.nil? && config.log_level <= Stripe::LEVEL_ERROR
77
130
  log_internal(message, data, color: :cyan, level: Stripe::LEVEL_ERROR,
78
131
  logger: Stripe.logger, out: $stderr)
79
132
  end
80
133
  end
81
134
 
82
135
  def self.log_info(message, data = {})
83
- if !Stripe.logger.nil? ||
84
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_INFO
136
+ config = data.delete(:config) || Stripe.config
137
+ logger = config.logger || Stripe.logger
138
+ if !logger.nil? ||
139
+ !config.log_level.nil? && config.log_level <= Stripe::LEVEL_INFO
85
140
  log_internal(message, data, color: :cyan, level: Stripe::LEVEL_INFO,
86
141
  logger: Stripe.logger, out: $stdout)
87
142
  end
88
143
  end
89
144
 
90
145
  def self.log_debug(message, data = {})
91
- if !Stripe.logger.nil? ||
92
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_DEBUG
146
+ config = data.delete(:config) || Stripe.config
147
+ logger = config.logger || Stripe.logger
148
+ if !logger.nil? ||
149
+ !config.log_level.nil? && config.log_level <= Stripe::LEVEL_DEBUG
93
150
  log_internal(message, data, color: :blue, level: Stripe::LEVEL_DEBUG,
94
151
  logger: Stripe.logger, out: $stdout)
95
152
  end
@@ -168,6 +225,18 @@ module Stripe
168
225
  result
169
226
  end
170
227
 
228
+ # `Time.now` can be unstable in cases like an administrator manually
229
+ # updating its value or a reconcilation via NTP. For this reason, prefer
230
+ # the use of the system's monotonic clock especially where comparing times
231
+ # to calculate an elapsed duration.
232
+ #
233
+ # Shortcut for getting monotonic time, mostly for purposes of line length
234
+ # and test stubbing. Returns time in seconds since the event used for
235
+ # monotonic reference purposes by the platform (e.g. system boot time).
236
+ def self.monotonic_time
237
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
238
+ end
239
+
171
240
  def self.normalize_id(id)
172
241
  if id.is_a?(Hash) # overloaded id
173
242
  params_hash = id.dup
@@ -186,7 +255,9 @@ module Stripe
186
255
  { api_key: opts }
187
256
  when Hash
188
257
  check_api_key!(opts.fetch(:api_key)) if opts.key?(:api_key)
189
- opts.clone
258
+ # Explicitly use dup here instead of clone to avoid preserving freeze
259
+ # state on input params.
260
+ opts.dup
190
261
  else
191
262
  raise TypeError, "normalize_opts expects a string or a hash"
192
263
  end
@@ -194,11 +265,13 @@ module Stripe
194
265
 
195
266
  def self.check_string_argument!(key)
196
267
  raise TypeError, "argument must be a string" unless key.is_a?(String)
268
+
197
269
  key
198
270
  end
199
271
 
200
272
  def self.check_api_key!(key)
201
273
  raise TypeError, "api_key must be a string" unless key.is_a?(String)
274
+
202
275
  key
203
276
  end
204
277
 
@@ -241,14 +314,14 @@ module Stripe
241
314
  #
242
315
 
243
316
  COLOR_CODES = {
244
- black: 0, light_black: 60,
245
- red: 1, light_red: 61,
246
- green: 2, light_green: 62,
247
- yellow: 3, light_yellow: 63,
248
- blue: 4, light_blue: 64,
317
+ black: 0, light_black: 60,
318
+ red: 1, light_red: 61,
319
+ green: 2, light_green: 62,
320
+ yellow: 3, light_yellow: 63,
321
+ blue: 4, light_blue: 64,
249
322
  magenta: 5, light_magenta: 65,
250
- cyan: 6, light_cyan: 66,
251
- white: 7, light_white: 67,
323
+ cyan: 6, light_cyan: 66,
324
+ white: 7, light_white: 67,
252
325
  default: 9,
253
326
  }.freeze
254
327
  private_constant :COLOR_CODES
@@ -277,10 +350,7 @@ module Stripe
277
350
  end
278
351
  private_class_method :level_name
279
352
 
280
- # TODO: Make these named required arguments when we drop support for Ruby
281
- # 2.0.
282
- def self.log_internal(message, data = {}, color: nil, level: nil,
283
- logger: nil, out: nil)
353
+ def self.log_internal(message, data = {}, color:, level:, logger:, out:)
284
354
  data_str = data.reject { |_k, v| v.nil? }
285
355
  .map do |(k, v)|
286
356
  format("%<key>s=%<value>s",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Stripe
4
- VERSION = "4.21.3".freeze
4
+ VERSION = "5.52.0"
5
5
  end