I am trying to pull campaign stats from Clickbank API in ruby. When I run the sample code Clickbank provided. I get the following error:
uninitialized constant Net::HTTPS (NameError). What am I missing?
Example Code.
require 'net/http'
require 'net/https'
http = Net::HTTPS.new('api.clickbank.com')
http.use_ssl = false
path = '/rest/1.3/orders/list'
headers = {
'Authorization' => '<< DEVKEY >>:<< APIKEY>>',
'Accept' => 'application/json'
}
resp, data = http.get(path, nil, headers)
puts 'Code = ' + resp.code
puts 'Message = ' + resp.message
resp.each {|key, val| puts key + ' = ' + val}
puts data
Yes I put my dev and api key into
In Ruby 2.4.1 enable ssl as a parameter of Net::HTTP.start
Net::HTTP.start(uri.host, uri.port, use_ssl: true)
https://ruby-doc.org/stdlib-2.4.1/libdoc/net/http/rdoc/Net/HTTP.html#class-Net::HTTP-label-HTTPS
Use Net:HTTP and enable SSL instead of using Net::HTTPS and disabling SSL.
Example:
http = Net::HTTP.new('api.clickbank.com')
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
You actually don't want to disable ssl as that API requires it. I was able to get it working like so based on the documentation for http found here: http://ruby-doc.org/stdlib-2.1.1/libdoc/net/http/rdoc/Net/HTTP.html
require 'net/http'
uri = URI('https://api.clickbank.com/rest/1.3/orders/list')
req = Net::HTTP::Get.new(uri)
# set headers on the request
req['Authorization'] = '<< DEVKEY >>:<< APIKEY>>'
req['Accept'] = 'application/json'
# perform the request
resp, data = Net::HTTP.start(uri.hostname, uri.port) {|http|
http.request(req)
}
puts 'Code = ' + resp.code
puts 'Message = ' + resp.message
resp.each {|key, val| puts key + ' = ' + val}
puts data
Related
I'm trying to get an Oauth request token from Twitter - I'm following their guide (links below) and I've gone over every single step about 10 times but I cannot figure out why I'm getting this error:
{\"errors\":[{\"code\":32,\"message\":\"Could not authenticate you.\"}]}
They use Oauth 1.0. I'm supposed to combine all the percent-encoded params in my request, percent encode them, add the request method (POST) and the request url, use that plus my api key secret to create a signature, and add the signature to my final Post request. The signature docs are on this page and the subsequent Post request docs are on this page. I used the example code given in the guide to generate a signature and I got the same result the guide did, so I don't think the actual signature generation is a problem.
I triple checked my api key and api key secret and callback url.
Here's my full code. Can anyone see a problem?
require 'net/http'
require 'uri'
require 'json'
require 'base64'
require 'cgi'
require 'openssl'
oauth_callback = "http://www.example.localhost:3000/twittercallback"
oauth_consumer_key = '[KEY]'
oauth_timestamp = Time.now.to_i
oauth_nonce = SecureRandom.hex(10) + oauth_timestamp.to_s
oauth_signature_method = "HMAC-SHA1"
oauth_version = "1.0"
one1 = CGI.escape "oauth_callback"
one2 = CGI.escape oauth_callback
two1 = CGI.escape "oauth_consumer_key"
two2 = CGI.escape oauth_consumer_key
three1 = CGI.escape "oauth_nonce"
three2 = CGI.escape oauth_nonce
four1 = CGI.escape "oauth_signature_method"
four2 = CGI.escape oauth_signature_method
five1 = CGI.escape "oauth_timestamp"
five2 = CGI.escape oauth_timestamp.to_s
six1 = CGI.escape "oauth_version"
six2 = CGI.escape oauth_version
string = "#{one1}=#{one2}&#{two1}=#{two2}&#{three1}=#{three2}&#{four1}=#{four2}&#{five1}=#{five2}&#{six1}=#{six2}"
encoded_string = CGI.escape string
url = "https://api.twitter.com/oauth/request_token"
encoded_url = CGI.escape url
encoded_string = "POST&" + encoded_url + "&" + encoded_string
signing_key = '[SECRET]'
encoded_signing_key = (CGI.escape signing_key) + "&"
digest = OpenSSL::Digest::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, encoded_signing_key, encoded_string)
signature = Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
uri = URI.parse("https://api.twitter.com/oauth/request_token")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/x-www-form-urlencoded"
oauth = 'OAuth oauth_callback="' + (CGI.escape oauth_callback) + '", oauth_nonce="' + (oauth_nonce + 'dsd') + '", oauth_signature_method="HMAC-SHA1", oauth_timestamp="' + oauth_timestamp.to_s + '", oauth_consumer_key="`<KEY>", oauth_signature="' + (CGI.escape signature) + '", oauth_version="1.0"'
request['Authorization'] = oauth
request.body = ""
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
here's my request["Authorization"] header
"OAuth oauth_callback=\"http%3A%2F%2Fwww.example.localhost%3A3000%2Ftwittercallback\", oauth_nonce=\"e5686f142ca58a45af233fb66876671592457549dsd\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1592457549\", oauth_consumer_key=\"[KEY]\", oauth_signature=\"n9MNLO%2Ft%2FT6WX0Myu5JcTICXNAQ%3D\", oauth_version=\"1.0\""
and this is the example header from Twitter's docs:
OAuth oauth_nonce="K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw", oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1300228849", oauth_consumer_key="OqEqJeafRSF11jBMStrZz", oauth_signature="Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D", oauth_version="1.0"
You don't provide the required Authorization header, but separate headers for each parameter. You need to combine the parameters in the following form as a string with OAuth as first:
OAuth oauth_nonce="K7ny27JTpKVsTgdyLdDfmQQWVLERj2zAK5BslRsqyw",oauth_callback="http%3A%2F%2Fmyapp.com%3A3005%2Ftwitter%2Fprocess_callback",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1300228849",oauth_consumer_key="OqEqJeafRSF11jBMStrZz",oauth_signature="Pc%2BMLdv028fxCErFyi8KXFM%2BddU%3D",oauth_version="1.0"
And provide that in the Authorization header:
request['Authorization'] = <OAuth string>
There are a lot of other issues in your code why it's not working:
Wrong escaping of the parameters
Escaping the signing key
Adding dsd to the nonce in the Authorization header
Wrong order of data in the Authorization header (needs to be lexicographically, e.g. for most libraries alphabetical)
So this results in the following if we rework your code:
require 'net/http'
require 'uri'
require 'base64'
require 'cgi'
require 'openssl'
require 'securerandom'
oauth_consumer_key = CGI::escape('D6O7BIWc6MTgl0A8UaRRt83In')
oauth_timestamp = CGI::escape(Time.now.to_i.to_s)
oauth_nonce = CGI::escape(SecureRandom.hex(10) + oauth_timestamp.to_s)
oauth_signature_method = CGI::escape("HMAC-SHA1")
oauth_version = CGI::escape("1.0")
one1 = CGI::escape("oauth_consumer_key")
one2 = oauth_consumer_key
two1 = CGI::escape("oauth_nonce")
two2 = oauth_nonce
three1 = CGI::escape("oauth_signature_method")
three2 = oauth_signature_method
four1 = CGI::escape("oauth_timestamp")
four2 = oauth_timestamp
five1 = CGI::escape("oauth_version")
five2 = oauth_version
string = "#{one1}=#{one2}&#{two1}=#{two2}&#{three1}=#{three2}&#{four1}=#{four2}&#{five1}=#{five2}"
encoded_string = CGI.escape string
url = "https://api.twitter.com/oauth/request_token"
encoded_url = CGI.escape url
encoded_string = "POST&" + encoded_url + "&" + encoded_string
signing_key = 'xJPBJ2OdV6nM8r9e6ZysbnHTrZYm4R7LaY9OafNNNY3BkT4Oym'
encoded_signing_key = signing_key + '&'
digest = OpenSSL::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, encoded_signing_key, encoded_string)
signature = Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
uri = URI.parse("https://api.twitter.com/oauth/request_token")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/x-www-form-urlencoded"
oauth = 'OAuth ' + one1 + '="' + oauth_consumer_key + '", ' + two1 + '="' + oauth_nonce + '", ' + CGI::escape('oauth_signature') + '="' + (CGI.escape signature) + '", ' + three1 + '="HMAC-SHA1", ' + four1 + '="' + oauth_timestamp.to_s + '", ' + five1 + '="1.0"'
puts oauth
request['Authorization'] = oauth
request.body = ""
req_options = {
use_ssl: uri.scheme == "https",
}
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
puts response
puts response.body
I would also like to give you a way to handle the parameters in a better way to generate the base_string and the header:
require 'net/http'
require 'uri'
require 'base64'
require 'cgi'
require 'openssl'
require 'securerandom'
oauth_consumer_key = '<KEY>'
oauth_consumer_secret = '<SECRET>'
oauth_consumer_secret += '&'
oauth_timestamp = Time.now.getutc.to_i.to_s
oauth_nonce = SecureRandom.hex(10) + oauth_timestamp
oauth_signature_method = "HMAC-SHA1"
oauth_version = "1.0"
url = "https://api.twitter.com/oauth/request_token"
uri = URI.parse(url)
params = {
'oauth_consumer_key' => oauth_consumer_key,
'oauth_nonce' => oauth_nonce,
'oauth_signature_method' => oauth_signature_method,
'oauth_timestamp' => oauth_timestamp.to_s,
'oauth_version' => oauth_version
}
base_string = "POST&" + CGI::escape(url) + "&" + CGI::escape(params.sort.collect{ |k,v| "#{CGI::escape(k)}=#{CGI::escape(v)}" }.join('&'))
oauth_signature = Base64.encode64("#{OpenSSL::HMAC.digest('sha1', oauth_consumer_secret, base_string)}").chomp
params['oauth_signature'] = oauth_signature
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
header = "OAuth " + params.sort.collect {|k,v| "#{CGI::escape(k)}=\"#{CGI::escape(v)}\""}.join(", ")
rsp, data = http.post(uri, nil, {'Authorization' => header })
puts rsp
puts rsp.body
Another suggestion is to use the existing OAuth gem available. When you use this well known library you are also able to get support from Twitter.
gem install oauth
require 'oauth'
oauth_consumer = OAuth::Consumer.new("<KEY>", "<SECRET>", :site => "https://api.twitter.com")
access_token = OAuth::AccessToken.new(oauth_consumer)
request_token = access_token.request(:post, "/oauth/request_token")
rsp = request_token.body
puts rsp
I would like to limit searching images using
"filter query parameters ( https://msdn.microsoft.com/en-us/library/dn760791.aspx )". But I always get photos whose size is around 250 - 300 pixel( both of width and height), although I want them, which is bigger than 500 x 500 pixel.
I know there is already similar question(Bing Image Search API filter by image size), but I couldn't solve the problem.
I'm using Ruby and the code is following.
What is the problem?
require "open-uri"
require "FileUtils"
require 'net/http'
require 'json'
#dirName = "/Users/hoge/img"
FileUtils.mkdir_p(#dirName) unless FileTest.exist?(#dirName)
def save_image(url, num)
filePath = "#{#dirName}/christ#{num.to_s}.jpg"
open(filePath, 'wb') do |output|
open(url) do |data|
output.write(data.read)
end
end
end
search_word = 'christ painting'
count = 5
size = 'Large'
uri = URI('https://api.cognitive.microsoft.com/bing/v5.0/images/search')
uri.query = URI.encode_www_form({
'q' => search_word,
'count' => count,
'size' => size
})
request = Net::HTTP::Post.new(uri.request_uri)
request['Content-Type'] = 'multipart/form-data'
request['Ocp-Apim-Subscription-Key'] = 'mykey' # Fix Me
request.body = "{body}"
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
end
count.times do |i|
begin
image_url = JSON.parse(response.body)["value"][i]["thumbnailUrl"]
save_image(image_url, i)
rescue => e
puts "image#{i} is error!"
puts e
end
end
I am trying to use SAS authenticaion in a ruby script and i keep getting 401 (Access denied) response from the event hub, it seems I am generating the SAS token incorrectly.
Below is the code I have used, it is based on https://azure.microsoft.com/en-us/documentation/articles/service-bus-sas-overview/ Javascript example that i have rewritten as ruby (please note it might be not idiomatic)
require "optparse"
require "CGI"
require 'openssl'
require "base64"
require "Faraday"
require 'Digest'
def generateToken(url,keyname,keyvalue)
encoded = CGI::escape(url)
ttl = (Time.now + 60*5).to_i
signature = "#{encoded}\n#{ttl}".encode('utf-8')
# puts signature
key = Base64.strict_decode64(keyvalue)
dig = OpenSSL::HMAC.digest('sha256', key, signature)
# dig = Digest::HMAC.digest(signature, key, Digest::SHA256)
hash = CGI.escape(Base64.strict_encode64(dig))
# puts hash
return "SharedAccessSignature sig=#{hash}&se=#{ttl}&skn=#{keyname}&sr=#{encoded}"
end
def build_connection(url,token)
conn = Faraday.new(:url => url) do |faraday|
faraday.request :url_encoded # form-encode POST params
faraday.response :logger # log requests to STDOUT
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
end
conn.headers['Content-Type'] = 'application/json'
conn.headers['Authorization'] = token
return conn
end
if __FILE__ == $0
ARGV << '-h' if ARGV.empty?
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: generateSasToken.rb [options]"
opts.on('-u URL', '--url URL', 'url for access') { |v| options[:url] = v }
opts.on('--keyname NAME','set key name') { |v| options[:keyname] = v }
opts.on('--key KEY','set key value') { |v| options[:keyvalue] = v }
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
end.parse!
token = generateToken(options[:url],options[:keyname],options[:keyvalue])
puts token
conn = build_connection(options[:url],token)
puts conn.headers
response = conn.post do |req|
req.body = '{"temprature":50}'
req.headers['content-length'] = req.body.length.to_s
end
puts response
end
any help in understanding why the token is incorrect would be great
After comparing my code against the python sdk this is the correct way to generate the token:
require "optparse"
require "CGI"
require 'openssl'
require "base64"
require "Faraday"
require 'Digest'
def generateToken(url,keyname,keyvalue)
encoded = CGI::escape(url)
ttl = (Time.now + 60*5).to_i
signature = "#{encoded}\n#{ttl}"
# puts signature
key = keyvalue
#dig = OpenSSL::HMAC.digest('sha256', key, signature)
dig = Digest::HMAC.digest(signature, key, Digest::SHA256)
hash = CGI.escape(Base64.strict_encode64(dig))
# puts hash
return "SharedAccessSignature sig=#{hash}&se=#{ttl}&skn=#{keyname}&sr=#{encoded}"
end
def build_connection(url,token)
conn = Faraday.new(:url => url) do |faraday|
faraday.request :url_encoded # form-encode POST params
faraday.response :logger # log requests to STDOUT
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
end
conn.headers['Content-Type'] = 'application/json'
conn.headers['Authorization'] = token
return conn
end
if __FILE__ == $0
ARGV << '-h' if ARGV.empty?
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: generateSasToken.rb [options]"
opts.on('-u URL', '--url URL', 'url for access') { |v| options[:url] = v }
opts.on('--keyname NAME','set key name') { |v| options[:keyname] = v }
opts.on('--key KEY','set key value') { |v| options[:keyvalue] = v }
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
end.parse!
token = generateToken(options[:url],options[:keyname],options[:keyvalue])
conn = build_connection(options[:url],token)
puts conn.headers
response = conn.post do |req|
req.body = '{"temprature":50}'
req.headers['content-length'] = req.body.length.to_s
end
puts response
end
this was much simpler than expected no need to encode to utf8 or to decode the key.
For example, to get response 200 OK from "example.com", necessary:
require 'net/http'
uri = URI('http://example.com/index.html')
res = Net::HTTP.get_response(uri)
puts res.code # => '200'
puts res.message # => 'OK'
How to make similar for pop.gmail.com?
Try this:
require "net/pop"
Net::POP3.enable_ssl(OpenSSL::SSL::VERIFY_NONE)
conn = Net::POP3.new("pop.gmail.com", 995)
conn.start(user_name, password)
conn.started?
I have four arguments taken from user input in the script. All other string interpolation arguments work fine except for URI.parse.
Snippets from the code are:
require 'net/http'
#ARGVs:
prompt = 'test: '
url = ARGV[0]
user = ARGV[1]
pass = ARGV[2]
xml_user = ARGV[3]
# User supplied input:
puts "Whats the URL?"
print prompt
url = STDIN.gets.chomp()
# HTTP connection
uri = URI.parse('#{url}')
req = Net::HTTP.new(uri.hostname, uri.port)
# Header: Creds to get a session
user_and_pass = "#{user}" + ':' + "#{pass}"
base64user_and_pass = Base64.encode64(user_and_pass)
# POST method
res = req.post(uri.path, xml_data, {'Content-Type' => 'text/xml', 'Content-Length' => xml_data.length.to_s,
'Authorization' => "Basic #{base64user_and_pass}", "Connection" => "keep-alive" })
puts res.body
Error:
Ruby200-x64/lib/ruby/2.0.0/uri/common.rb:176:in `split': bad URI(is not URI?): #{url} (URI::InvalidURIError)
A point in the right direction would be appreciated.
uri = URI.parse('#{url}')
should be:
uri = URI.parse(url)
Here's a bit more idiomatic-Ruby version of the code:
require 'net/http'
PROMPT = 'test: '
# ARGVs:
url, user, pass, xml_user = ARGV[0, 4]
# User supplied input:
puts "Whats the URL?"
print PROMPT
url = STDIN.gets.chomp()
# HTTP connection
uri = URI.parse(url)
req = Net::HTTP.new(uri.hostname, uri.port)
# Header: Creds to get a session
base64user_and_pass = Base64.encode64("#{ user }:#{ pass }")
# POST method
res = req.post(
uri.path,
xml_data,
{
'Content-Type' => 'text/xml',
'Content-Length' => xml_data.length.to_s,
'Authorization' => "Basic #{ base64user_and_pass }",
"Connection" => "keep-alive"
}
)
puts res.body
Don't do things like:
user_and_pass = "#{user}" + ':' + "#{pass}"
and:
uri = URI.parse('#{url}')
user, pass and url are already strings, so sticking them inside a string and interpolating their values is a waste of CPU. As developers we need to be aware of our data-types.
It could be written as one of these:
user_and_pass = user + ':' + pass
user_and_pass = '%s:%s' % [user, pass]
user_and_pass = [user, pass].join(':')
But it's more idiomatic to see it how I wrote it above.