Brandur 80d85a522c Implement deep copy for StripeObject and remove marshal/unmarshal
We were previously using a bit of a hack to get a free deep copy
implementation through Ruby's marshaling framework. Lint call this out
as a security problem though, and rightfully so: when combined with
unsanitized user input, unmarshaling can result in very serious security
breaches involving arbitrary code execution.

This patch removes all uses of marshal/unmarshal in favor of
implementing a deep copy method for `StripeObject`. I also reworked some
of the constants around what keys are available for `opts`. I'm still
not completely happy with the results, but I think it's going to need a
slightly larger refactor in order to get somewhere truly good.

There is what could be a breaking change for people doing non-standard
stuff with the library: the opts that we copy with an object are now
whitelisted, so if they were being used to pass around extraneous data,
that might not work as expected anymore. But because this is a contract
that we never committed to, I don't think I'd bump the major version for
change.
2017-09-28 11:02:20 -07:00

56 lines
1.5 KiB
Ruby

module Stripe
module APIOperations
module Request
module ClassMethods
def request(method, url, params = {}, opts = {})
warn_on_opts_in_params(params)
opts = Util.normalize_opts(opts)
opts[:client] ||= StripeClient.active_client
headers = opts.clone
api_key = headers.delete(:api_key)
api_base = headers.delete(:api_base)
client = headers.delete(:client)
# Assume all remaining opts must be headers
resp, opts[:api_key] = client.execute_request(
method, url,
api_base: api_base, api_key: api_key,
headers: headers, params: params
)
# Hash#select returns an array before 1.9
opts_to_persist = {}
opts.each do |k, v|
opts_to_persist[k] = v if Util::OPTS_KEYS_TO_PERSIST.include?(k)
end
[resp, opts_to_persist]
end
private
def warn_on_opts_in_params(params)
Util::OPTS_USER_SPECIFIED.each do |opt|
if params.key?(opt)
$stderr.puts("WARNING: #{opt} should be in opts instead of params.")
end
end
end
end
def self.included(base)
base.extend(ClassMethods)
end
protected
def request(method, url, params = {}, opts = {})
opts = @opts.merge(Util.normalize_opts(opts))
self.class.request(method, url, params, opts)
end
end
end
end