# frozen_string_literal: true
require "oauth/helper"
require "oauth/request_proxy/net_http"
module Net
class HTTPGenericRequest
include OAuth::Helper
attr_reader :oauth_helper
# Add the OAuth information to an HTTP request. Depending on the options[:scheme] setting
# this may add a header, additional query string parameters, or additional POST body parameters.
# The default scheme is +header+, in which the OAuth parameters as put into the +Authorization+
# header.
#
# * http - Configured Net::HTTP instance
# * consumer - OAuth::Consumer instance
# * token - OAuth::Token instance
# * options - Request-specific options (e.g. +request_uri+, +consumer+, +token+, +scheme+,
# +signature_method+, +nonce+, +timestamp+, +body_hash+)
#
# This method also modifies the User-Agent header to add the OAuth gem version.
#
# See Also: {OAuth core spec version 1.0, section 5.4.1}[http://oauth.net/core/1.0#rfc.section.5.4.1],
# {OAuth Request Body Hash 1.0 Draft 4}[http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html,
# http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html#when_to_include]
def oauth!(http, consumer = nil, token = nil, options = {})
helper_options = oauth_helper_options(http, consumer, token, options)
@oauth_helper = OAuth::Client::Helper.new(self, helper_options)
@oauth_helper.amend_user_agent_header(self)
@oauth_helper.hash_body if oauth_body_hash_required?(helper_options)
send("set_oauth_#{helper_options[:scheme]}")
end
# Create a string suitable for signing for an HTTP request. This process involves parameter
# normalization as specified in the OAuth specification. The exact normalization also depends
# on the options[:scheme] being used so this must match what will be used for the request
# itself. The default scheme is +header+, in which the OAuth parameters as put into the +Authorization+
# header.
#
# * http - Configured Net::HTTP instance
# * consumer - OAuth::Consumer instance
# * token - OAuth::Token instance
# * options - Request-specific options (e.g. +request_uri+, +consumer+, +token+, +scheme+,
# +signature_method+, +nonce+, +timestamp+)
#
# See Also: {OAuth core spec version 1.0, section 5.4.1}[http://oauth.net/core/1.0#rfc.section.5.4.1],
# {OAuth Request Body Hash 1.0 Draft 4}[http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/drafts/4/spec.html,
# http://oauth.googlecode.com/svn/spec/ext/body_hash/1.0/oauth-bodyhash.html#when_to_include]
def signature_base_string(http, consumer = nil, token = nil, options = {})
helper_options = oauth_helper_options(http, consumer, token, options)
@oauth_helper = OAuth::Client::Helper.new(self, helper_options)
@oauth_helper.hash_body if oauth_body_hash_required?(helper_options)
@oauth_helper.signature_base_string
end
private
def oauth_helper_options(http, consumer, token, options)
{ request_uri: oauth_full_request_uri(http, options),
consumer: consumer,
token: token,
scheme: "header",
signature_method: nil,
nonce: nil,
timestamp: nil,
body_hash_enabled: true }.merge(options)
end
def oauth_full_request_uri(http, options)
uri = URI.parse(path)
uri.host = http.address
uri.port = http.port
if options[:request_endpoint] && options[:site]
is_https = options[:site].match(%r{^https://})
uri.host = options[:site].gsub(%r{^https?://}, "")
uri.port ||= is_https ? 443 : 80
end
uri.scheme = if http.respond_to?(:use_ssl?) && http.use_ssl?
"https"
else
"http"
end
uri.to_s
end
def oauth_body_hash_required?(options)
!@oauth_helper.token_request? && request_body_permitted? && !content_type.to_s.downcase.start_with?("application/x-www-form-urlencoded") && options[:body_hash_enabled]
end
def set_oauth_header
self["Authorization"] = @oauth_helper.header
end
# FIXME: if you're using a POST body and query string parameters, this method
# will move query string parameters into the body unexpectedly. This may
# cause problems with non-x-www-form-urlencoded bodies submitted to URLs
# containing query string params. If duplicate parameters are present in both
# places, all instances should be included when calculating the signature
# base string.
def set_oauth_body
# NOTE: OAuth::Helper and @oauth_helper are not the same, despite sharing all methods defined in OAuth::Helper
# see: https://stackoverflow.com/a/53447775/213191
set_form_data(OAuth::Helper.stringify_keys(@oauth_helper.parameters_with_oauth))
params_with_sig = @oauth_helper.parameters.merge(oauth_signature: @oauth_helper.signature)
set_form_data(OAuth::Helper.stringify_keys(params_with_sig))
end
def set_oauth_query_string
oauth_params_str = @oauth_helper.oauth_parameters.map { |k, v| [escape(k), escape(v)].join("=") }.join("&")
uri = URI.parse(path)
uri.query = if uri.query.to_s == ""
oauth_params_str
else
"#{uri.query}{oauth_params_str}"
end
@path = uri.to_s
@path << "&oauth_signature=#{escape(oauth_helper.signature)}"
end
end
end