I'm trying to access balance of Bitstamp account with API.
secret = "secret"
key = "key"
nonce = (1000*Time.now.to_f).to_i.to_s
client_id = "123123"
message = nonce + client_id + key
signature = HMAC::SHA256.hexdigest(secret, message).upcase
puts open("https://www.bitstamp.net/api/balance/?nonce=#{nonce}&key=#{key}&signature=#{signature}").read
it clearly generates all required attributes
https://www.bitstamp.net/api/balance/?nonce=1392137355403&key=key&signature=955A3FFC6FEBE69385B9503307873DBCD21E9B7B8EDE67817FFF70961189CE50
yet the error says attributes are missing, why?
{"error": "Missing key, signature and nonce parameters"}
The problem was that I was sending the request as GET instead of POST. Here is the full code I am using now that works.
require 'open-uri'
require 'json'
require 'base64'
require 'openssl'
require 'hmac-sha2'
require 'net/http'
require 'net/https'
require 'uri'
def bitstamp_private_request(method, attrs = {})
secret = "xxx"
key = "xxx"
client_id = "xxx"
nonce = nonce_generator
message = nonce + client_id + key
signature = HMAC::SHA256.hexdigest(secret, message).upcase
url = URI.parse("https://www.bitstamp.net/api/#{method}/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
data = {
nonce: nonce,
key: key,
signature: signature
}
data.merge!(attrs)
data = data.map { |k,v| "#{k}=#{v}"}.join('&')
headers = {
'Content-Type' => 'application/x-www-form-urlencoded'
}
resp = http.post(url.path, data, headers)
console_log "https://www.bitstamp.net/api/#{method}/"
resp.body
end
def nonce_generator
(Time.now.to_f*1000).to_i.to_s
end
Related
I am trying to learn how to make simple requests to the Coinbase API in Ruby. This is mostly for my own entertainment and education. The Ruby GEM is so out of date I thought I'd start working on my own system instead of relying on it. To that end I wanted to get the basics working before I tried to turn it into a gem.
Here is the beginnings of my module.
And no matter what, when I try to get /accounts I get a 401 response.
#status=401 #reason_phrase="Unauthorized" #response_body="{\"message\":\"Invalid API Key\"}
# Simple Coinbase Requests
require 'base64'
require 'openssl'
require 'json'
require 'faraday'
module Coinbase
module Request
class API
def initialize key = '', secret = '', passphrase = '', sandbox = false
#url = sandbox ? 'https://api-public.sandbox.pro.coinbase.com' : 'https://api-public.pro.coinbase.com'
#key = key
#secret = secret
#passphrase = passphrase
#content_type = 'application/json'
end
# Get Accounts
def accounts
self.get '/accounts'
end
# Do the work of a HTTP Get
def get path
timestamp = Time.now.to_i.to_s
headers = auth_headers path, '', 'GET', timestamp
connection = Faraday.new(url: 'https://api-public.sandbox.pro.coinbase.com', headers: headers, ssl: { :verify => false })
# puts connection.inspect
connection.get path
end
# Auth Headers
# CB-ACCESS-KEY The api key as a string.
# CB-ACCESS-SIGN The base64-encoded signature (see Signing a Message).
# CB-ACCESS-TIMESTAMP A timestamp for your request.
# CB-ACCESS-PASSPHRASE The passphrase you specified when
def auth_headers path = '', body = '', method = 'GET', timestamp = nil
{
'Content-Type': 'Application/JSON',
'CB-ACCESS-SIGN': self.signature(path, body, method, timestamp),
'CB-ACCESS-TIMESTAMP': timestamp,
'CB-ACCESS-KEY': #key,
'CB-ACCESS-PASSPHRASE': #passphrase
}
end
# Generate a signature
def signature path = '', body = '', method = 'GET', timestamp = nil
body = body.to_json if body.is_a?(Hash)
secret = Base64.decode64 #secret
hash = OpenSSL::HMAC.digest 'sha256', secret, "#{timestamp}#{method}#{path}#{body}"
Base64.strict_encode64 hash
end
end
end
end
I'm calling it using the following (THE KEY/SECRET/PASSPHRASE ARE FAKE for this example)
coinbase = Coinbase::Request::API.new('123426bc3a583fb8393141fb7777fake',
'+FAKEbGoG1eT1WVFWNJxFtTE/y4kIYq2Lbf6FAKEw5j2756GXgaqg5iXTsqPJXKkStZ7nPoTT2RGKwiJfRFAKE==',
'FAKEPASSPHRASE',
true)
puts coinbase.accounts.inspect
The signature "what" (as defined as "#{timestamp}#{method}#{path}#{body}" in your docs) for this simple request would be something like 1624063589GET/accounts
The headers come out to {:"Content-Type"=>"Application/JSON", :"CB-ACCESS-SIGN"=>"rs29GSZuRspthioywb5IkaHQmPIwH5DRDW5LHoYUvw8=", :"CB-ACCESS-TIMESTAMP"=>"1624063726", :"CB-ACCESS-KEY"=>"123426bc3a583fb8393141fb22328113", :"CB-ACCESS-PASSPHRASE"=>"FAKEPASSPHRASE"}
Once connected the headers come out as seen below in the faraday response object.
This is the full response object output which is what I would expect to get with fake keys as used but I get the same thing when I use the keys I generated here: https://pro.coinbase.com/profile/ap
#<Faraday::Response:0x00000001621a8e58 #on_complete_callbacks=[], #env=#<Faraday::Env #method=:get #url=#<URI::HTTPS https://api-public.sandbox.pro.coinbase.com/accounts> #request=#<Faraday::RequestOptions (empty)> #request_headers={"Content-type"=>"Application/JSON", "Cb-access-sign"=>"vEfjUnFy+3qQqRa2lxvEC5O32xOa6t7NgGAxO8OYrpo=", "Cb-access-timestamp"=>"1624063280", "Cb-access-key"=>"123426bc3a583fb8393141fb22328113", "Cb-access-passphrase"=>"FAKEPASSPHRASE", "User-Agent"=>"Faraday v1.4.2"} #ssl=#<Faraday::SSLOptions (empty)> #response=#<Faraday::Response:0x00000001621a8e58 ...> #response_headers={"date"=>"Sat, 19 Jun 2021 00:41:21 GMT", "content-type"=>"application/json; charset=utf-8", "content-length"=>"29", "connection"=>"keep-alive", "access-control-allow-headers"=>"Content-Type, Accept, cb-session, cb-fp, cb-form-factor", "access-control-allow-methods"=>"GET,POST,DELETE,PUT", "access-control-allow-origin"=>"*", "access-control-expose-headers"=>"cb-before, cb-after, cb-gdpr", "access-control-max-age"=>"7200", "cache-control"=>"no-store", "etag"=>"W/\"1d-mmRSeO9uba2rhQtGfy4YjixIkt4\"", "strict-transport-security"=>"max-age=15552000; includeSubDomains", "x-content-type-options"=>"nosniff", "x-dns-prefetch-control"=>"off", "x-download-options"=>"noopen", "x-frame-options"=>"SAMEORIGIN", "x-xss-protection"=>"1; mode=block", "cf-cache-status"=>"MISS", "cf-request-id"=>"0ac3501f6300005ae1c99c3000000001", "expect-ct"=>"max-age=604800, report-uri=\"https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct\"", "vary"=>"Accept-Encoding", "server"=>"cloudflare", "cf-ray"=>"6618b6123ba75ae1-IAD"} #status=401 #reason_phrase="Unauthorized" #response_body="{\"message\":\"Invalid API Key\"}">>
I've been plugging away at this for days and I just can't seem to get it to not return Invalid API Key. I feel like I'm so very close.. but no cigar..
Thoughts?
NOTE: On a whim before submitting this I tried /currencies and it worked fine.
It took me some trial and error with this too, but I was hitting invalid signature errors rather than invalid API key errors. Maybe this will help anyway:
Working example:
Gemfile
source 'https://rubygems.org'
ruby '2.6.7'
gem 'httparty'
coinbase.rb
require 'base64'
require 'httparty'
API_KEY = ''
API_PASSPHRASE = ''
API_SECRET = ''
key = Base64.decode64(API_SECRET)
url = "https://api.exchange.coinbase.com"
requestPath = "/accounts"
method = "GET"
body = ""
timestamp = Time.now.to_i.to_s
message = timestamp + method + requestPath + body
hmac = OpenSSL::HMAC.digest('sha256', key, message)
signature = Base64.strict_encode64(hmac)
headers = {
'Content-Type': 'application/json',
'CB-ACCESS-SIGN': signature,
'CB-ACCESS-TIMESTAMP': timestamp,
'CB-ACCESS-KEY': API_KEY,
'CB-ACCESS-PASSPHRASE': API_PASSPHRASE
}
result = HTTParty.get(url+requestPath, headers: headers)
puts result.response.body
Run:
bundle install
bundle exec coinbase.rb
I'm a bit of newbie regarding HTTP GET/POST request. I want to use a get request that requires some kind of authorization.
I'm trying to use the following api API DOCUMENTATION.
Under "get list" it says that it wants the following parameters:
Parameters
- Accept-Language: Language prefered in the response. Note: nb and nn will return the same as no header string
- Authorization: Basic auth. The session_id should be sent as both username and password header string
I use the following code to authorize myself, but the last "GET requests" gives an error:
require 'openssl'
require 'base64'
require 'uri'
require 'net/http'
require 'json'
username = 'MYUSERNAME'
password = 'MYPASSWORD'
service = 'NEXTAPI'
# Create auth
string = Base64.encode64(username) + ':' + Base64.encode64(password) + ':' + Base64.encode64((Time.now.\
to_i * 1000).to_s)
public_key_data = File.read(service + '_TEST_public.pem')
public_key = OpenSSL::PKey::RSA.new(public_key_data)
auth = URI::escape(Base64.encode64(public_key.public_encrypt(string)),
Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
# Setup HTTPS
http = Net::HTTP.new('api.test.nordnet.se', 443)
http.use_ssl = true
# Get status of server
response = http.get('/next/2/', {'Accept' => 'application/json'})
puts response.body
# POST login
response = http.post('/next/2/login', "auth=#{auth}&service=#{service}", {'Accept' => 'application/json'})
puts response.body
data = JSON.parse(response.body)
session_key = data['session_key']
auth_string = "Basic " + session_key + ":" + session_key
response = http.get('/next/2/lists', {'Authorization' => auth_string })
puts response
Not sure what is going wrong here. Or what I need to do. I get the following error.
#<Net::HTTPNotAcceptable:0x007fac74276d20>
Question 1: How do I properly send my session key as both username and password?
Question 2: How would I actually send parameters and headers, and what are the differences?
Question 3: Is there a difference in what will be needed in regards to headers/parameters depending on if I send a GET or POST request?
Thanks
Was able to solve it. Below is the OK code...
require 'openssl'
require 'base64'
require 'uri'
require 'net/https'
require 'json'
require 'cgi'
username = 'USERNAME'
password = 'PASSWORD'
service = 'NEXTAPI'
def http_get(path,params)
http = Net::HTTP.new('api.test.nordnet.se', 443)
http.use_ssl = true
#return http.get("#{path}?", params)
return http.get("#{path}?")
#return Net::HTTP.get(path)
end
# Create auth
string = Base64.encode64(username) + ':' + Base64.encode64(password) + ':' + Base64.encode64((Time.now.\
to_i * 1000).to_s)
public_key_data = File.read(service + '_TEST_public.pem')
public_key = OpenSSL::PKey::RSA.new(public_key_data)
auth = URI::escape(Base64.encode64(public_key.public_encrypt(string)),
Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
# Setup HTTPS
http = Net::HTTP.new('api.test.nordnet.se', 443)
http.use_ssl = true
# Get status of server
response = http.get('/next/2/', {'Accept' => 'application/json'})
puts response.body
# POST login
response = http.post('/next/2/login', "auth=#{auth}&service=#{service}", {'Accept' => 'application/json'})
puts response.body
data = JSON.parse(response.body)
session_key = data['session_key']
uri = URI('https://api.test.nordnet.se:443/next/2/lists')
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https',
:verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
request = Net::HTTP::Get.new uri.request_uri
request.add_field('Accept', 'application/json')
request.basic_auth session_key, session_key
response = http.request request # Net::HTTPResponse object
puts response.body# puts response.body
end
I'm struggling with getting results from the team city api in JSON
require 'open-uri'
url = ".../app/rest/buildQueue/"
c = Curl::Easy.new(url) do |curl|
curl.headers["Content-type"] = "application/json"
curl.http_auth_types = :basic
curl.username = 'user'
curl.password = 'password'
end
c.perform
puts c.body_str
I get a bunch of xml text
You need to use the Accept header to control the response type:
e.g (command line)
curl --url http://xxx/app/rest/buildQueue/ -H Accept:"application/json"
Documentation Reference
also you can use "net/http"
require 'net/http'
require 'uri'
url = URI('http://localhost:8111/httpAuth/app/rest/agents')
req = Net::HTTP::Get.new(url)
req['Accept'] = 'application/json'
req.basic_auth 'admin', 'admin'
res = Net::HTTP.start(url.hostname, url.port) {|http|
http.request(req)
}
puts res.body
require 'net/http'
require 'rubygems'
require 'json'
url = URI.parse('http://www.xyxx/abc/pqr')
resp = Net::HTTP.get_response(url) # get_response takes an URI object
data = resp.body
puts data
this is my code in ruby, resp.data is giving me data in xml form.
rest api return xml data by default , and json if header content-type is application/json.
but i want data in json form.for this i have to set header['content-type']='application/json'.
but i do not know , how to set header with get_response method.to get json data.
def post_test
require 'net/http'
require 'json'
#host = '23.23.xxx.xx'
#port = '8080'
#path = "/restxxx/abc/xyz"
request = Net::HTTP::Get.new(#path, initheader = {'Content-Type' =>'application/json'})
response = Net::HTTP.new(#host, #port).start {|http| http.request(request) }
puts "Response #{response.code} #{response.message}: #{response.body}"
end
Use instance method Net::HTTP#get to modify the header of a GET request.
require 'net/http'
url = URI.parse('http://www.xyxx/abc/pqr')
http = Net::HTTP.new url.host
resp = http.get("#{url.path}?#{url.query.to_s}", {'Content-Type' => 'application/json'})
data = resp.body
puts data
You can simply do this:
uri = URI.parse('http://www.xyxx/abc/pqr')
req = Net::HTTP::Get.new(uri.path, 'Content-Type' => 'application/json')
res = Net::HTTP.new(uri.host, uri.port).request(req)
I want to make oAuth request in Ruby. I skimmed some examples but none of them used oauth_token_secret and oauth_token to make a request, they only used consumer_key and consumer_secret to get oauth_token_secret and oauth_token. But I already have oauth_token_secret and oauth_token.
For example, this one I tried to use
require 'rubygems'
require 'oauth'
consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
{
:site=> "https://www.google.com",
:scheme=> :header,
:http_method=> :post,
:request_token_path => "/accounts/OAuthGetRequestToken",
:access_token_path => "/accounts/OAuthGetAccessToken",
:authorize_path=> "/accounts/OAuthAuthorizeToken",
:signature_method=>"RSA-SHA1"},
# :private_key_file=>PATH_TO_PRIVATE_KEY
)
request_token = consumer.get_request_token()
puts "Visit the following URL, log in if you need to, and authorize the app"
puts request_token.authorize_url
puts "When you've authorized that token, enter the verifier code you are assigned:"
verifier = gets.strip
puts "Converting request token into access token..."
access_token=request_token.get_access_token(:oauth_verifier => verifier)
puts "access_token.token --> #{access_token.token}" # But I initially have it
puts "access_token.secret --> #{access_token.secret}" # But I initially have it
In my case, there are 4 secret keys:
consumer_key = "anonymous"
consumer_secret = "anonymous"
oauth_token_secret = "fdsfdsfdfdsfds"
oauth_token = "fdsfdsfdfdsfdsdsdsdsdsdsds"
So what I need to do is, to make a API request to the certain url with some additional get parameters and oAuth token and to get the answer.
How do I do that in Ruby?
#!/usr/bin/env ruby
require 'rubygems'
require 'oauth'
require 'json'
You need to get your access_token (OAuth::AccessToken).
# Initialisation based on string values:
consumer_key = 'AVff2raXvhMUxFnif06g'
consumer_secret = 'u0zg77R1bQqbzutAusJYmTxqeUpWVt7U2TjWlzbVZkA'
access_token = 'R1bQqbzYm0zg77tAusJzbVZkAVt7U2T'
access_token_secret = 'sVbVZkAt7U2TjWlJYmTxqR1bQqbzutAuWzeUpu0zg77'
#consumer = OAuth::Consumer.new(consumer_key, consumer_secret, {:site=>'http://my.site'})
accesstoken = OAuth::AccessToken.new(#consumer, access_token, access_token_secret)
Once you have your OAuth::AccessToken object, you do :
json_response = accesstoken.get('/photos.xml')
# or
json_response = accesstoken.post(url, params_hash)
etc.
The response is a json object. To read it, you can do :
response = JSON.parse(json_response.body)
# which is a hash
# you just access content like
id = response["id"]