How to pass Json parameter for blockchain-wallet ruby api methods - ruby-on-rails

Trying to work on blockchain-wallet ruby api methods as in doc https://github.com/Tolsi/blockchain-wallet-ruby/blob/master/lib/blockchain/wallet.rb where am stuck with passing Json parameters for payment and sendmany methods.
recipients = {"1H8fsmAgVhUt567I65hGJPkMbnCCy5": "1000000"}
wallet = Blockchain::Wallet.new("b14d36af-2fa6-4d76-91b5-ff70b8370ec7", "n$grJ74hAshfggnb6864%j78##^hChttp://ya.ru#contentpurl", nil)
wallet.sendmany(recipients, from = nil, shared = nil, fee = nil, note = nil)
Got error despite substituting the required,
Invalid Recipients JSON. Please make sure it is url encoded and consult the docs. (WebAPI::WebApiException)
How to solve the problem ?

In the Blockchain::Wallet gem code, I found this:
def build_url(operation_name, params)
#url + operation_name + "?" + params.map { |param, value| "#{param}=#{value}" if value }.join("&")
end
I believe the way it's being built, you will need to transform in JSON and also encode your recipients string:
require 'json'
require 'uri'
recipients = {"1H8fsmAgVhUt567I65hGJPkMbnCCy5" => "1000000"}
wallet = Blockchain::Wallet.new("b14d36af-2fa6-4d76-91b5-ff70b8370ec7", "n$grJ74hAshfggnb6864%j78##^hChttp://ya.ru#contentpurl", nil)
wallet.sendmany(URI.encode(JSON.generate(recipients)))
The recipient will be "%7B%221H8fsmAgVhUt567I65hGJPkMbnCCy5%22:%221000000%22%7D".
References:
https://github.com/Tolsi/blockchain-wallet-ruby/blob/master/lib/blockchain/web_api.rb
https://blockchain.info/api/blockchain_wallet_api
UPDATE: Try remove the URI.encode if this does not work.

Related

How to verify a webhook with Ruby?

I'm using Ruby 2.5.5 and Rails 5.2. I'm trying to verify a Paddle webhook, but can't get the verification to work. I tried various ways, here is one of them. I'll go through it on my console:
Here is the data:
data = {
"alert_id"=>"1",
"alert_name"=>"alert_created",
"cancel_url"=>"https://...",
"checkout_id"=>"1",
"user_id"=>"1",
"p_signature"=>"fwWXqR9C..."
}
public_key = "-----BEGIN PUBLIC KEY-----
FAKEdfsdfsdfsdfsdfsdfsdf23423423423423KCAgEAnyBxU0cUW9NGQU1Ur0MD
/M+VxdMsv7PMXsZFAKEKEYlskdfjlskdjflsjlskdj8i7+D9xZT57VhIfv8hInGy
IQFmJRrWxgmHjSW4cKbjg6Qg0NgOEuPdEIixsQZ/AfIar4KNObDul0EXL92B6ru/
...
-----END PUBLIC KEY-----"
Then I do the following:
signature = Base64.decode64(data['p_signature'])
data.delete('p_signature')
data.each {|key, value|data[key] = String(value)}
data_sorted = data.sort_by{|key, value| key}
data_serialized = data_sorted.to_json
digest = OpenSSL::Digest::SHA1.new
pub_key = OpenSSL::PKey::RSA.new(public_key)
verified = pub_key.verify(digest, signature, data_serialized)
In the end verified is always false. What am I doing wrong? I asked a related question here, but couldn't get it yet to work.
Example in paddle documentation that you've linked to suggests serializing data to PHP format before verification using php-serialize gem, that differs from regular json:
# ... data = ...
data_sorted.to_json
=> "[[\"alert_id\",\"1\"],[\"alert_name\",\"alert_created\"],[\"cancel_url\",\"https://...\"],[\"checkout_id\",\"1\"],[\"user_id\",\"1\"]]"
PHP.serialize(data_sorted, true)
=> "a:5:{s:8:\"alert_id\";s:1:\"1\";s:10:\"alert_name\";s:13:\"alert_created\";s:10:\"cancel_url\";s:11:\"https://...\";s:11:\"checkout_id\";s:1:\"1\";s:7:\"user_id\";s:1:\"1\";}"
as you can see - it gives different result, so obviously signature will not match.
Actually, you can take their whole ruby example:
require 'base64'
require 'php_serialize' # https://github.com/jqr/php-serialize
require 'openssl'
public_key = '-----BEGIN PUBLIC KEY-----
MIICIjANBgkqh...'
# 'data' represents all of the POST fields sent with the request.
signature = Base64.decode64(data['p_signature'])
data.delete('p_signature')
data.each {|key, value|data[key] = String(value)}
data_sorted = data.sort_by{|key, value| key}
data_serialized = PHP.serialize(data_sorted, true)
digest = OpenSSL::Digest::SHA1.new
pub_key = OpenSSL::PKey::RSA.new(public_key).public_key
verified = pub_key.verify(digest, signature, data_serialized)
I can't explain it completely but I think the false is related to your signature or data_serialized parameter, I use the same digest. Another difference is that sign is called on the key in the example below:
verify(digest, signature, data)
from: https://ruby-doc.org/stdlib-2.6.3/libdoc/openssl/rdoc/OpenSSL/PKey/PKey.html
To verify the String signature, digest, an instance of OpenSSL::Digest, must be provided to re-compute the message digest of the original data, also a String. The return value is true if the signature is valid, false otherwise. A PKeyError is raised should errors occur. Any previous state of the Digest instance is irrelevant to the validation outcome, the digest instance is reset to its initial state during the operation.
Example:
data = 'Sign me!'
digest = OpenSSL::Digest::SHA256.new
pkey = OpenSSL::PKey::RSA.new(2048)
signature = pkey.sign(digest, data)
pub_key = pkey.public_key
puts pub_key.verify(digest, signature, data) # => true`

Converting python to ruby params issue

I'm converting some python code to ruby. It's going ok so far, except I'm running into some issues with parameters. The python code is:
def sign_policy(policy):
signed_policy = base64.b64encode(policy)
signature = base64.b64encode(hmac.new(
app.config.get('AWS_CLIENT_SECRET_KEY'), signed_policy, hashlib.sha1).
digest())
return { 'policy': signed_policy, 'signature': signature }
def sign_headers(headers):
headers = bytearray(headers, 'utf-8') # hmac doesn't want unicode
return {
'signature': base64.b64encode(hmac.new(
app.config.get('AWS_CLIENT_SECRET_KEY'), headers, hashlib.sha1).
digest())
}
def s3_signature():
request_payload = request.get_json()
if request_payload.get('headers'):
response_data = sign_headers(request_payload['headers'])
else:
response_data = sign_policy(request.data)
return jsonify(response_data)
My ruby version so far is:
def create
puts params[:headers]
if params[:headers].present?
response_data = sign_headers(params[:headers])
else
response_data = sign_policy(params)
end
render json: response_data
end
private
def sign_policy(policy)
signed_policy = Base64.encode64(policy).gsub("\n","")
signature = Base64.encode64(
OpenSSL::HMAC.digest(
OpenSSL::Digest.new('sha1'),
AWS_SECRET_KEY, signed_policy)
).gsub("\n","")
return { 'policy': signed_policy, 'signature': signature }
end
def sign_headers(headers)
#headers = bytearray(headers, 'utf-8')
return {
'signature': Base64.encode64(
OpenSSL::HMAC.digest(
AWS_SECRET_KEY, headers, OpenSSL::Digest.new('sha1')
))
}
end
I'm running into the following issue: no implicit conversion of ActionController::Parameters into String, which makes it obvious whats wrong (Params is a hash and it needs to be a string)..However, what is being passed in the python code? I'm missing what I should be passing?
Most probably you need to pass a single value, String or any other, it depends on the data type you need to pass to use Base64.encode64(policy).
As you're passing params[:headers] in the sign_headers method call, in the case of the sign_policy call, you're passing params which is the whole ActionController::Parameters, try debugging the values you sent on params to send the needed value.

Rails String Replace URL Parameters

Let's say I have a string like:
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
I want to update the cmp_id=344 to be say cmp_id=44553. What's the best way to accomplish this? I can't gsub per say because I don't know what cmp_id might be equal, only that it will be a URL parameter in the string.
It seems like I want to do something like
uri = URI.parse(url)
params = CGI.parse(uri.query)
But then, how do I re-build the string swapping out the cmp_id parameter to be 44553?
Thanks!
If you are dealing with a web application (and/or Rails as the tag seems to indicate), then you certainly have Rack available. Rack::Utils has methods to parse and build a query.
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
uri = URI.parse(url)
query = Rack::Utils.parse_query(uri.query)
# => {"key"=>"34432", "cmp_id"=>"344", "tr_id"=>"{user_id}"}
# Replace the value
query["cmp_id"] = 44553
uri.query = Rack::Utils.build_query(query)
uri.to_s
# => "https://example.com/user/tr_auth.php?key=34432&cmp_id=44553&tr_id=%7Buser_id%7D"
Also note that Rack, by default, escapes the query.
url = "https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}"
uri = URI.parse(url)
params = CGI.parse(uri.query)
params['cmp_id'] = 44553
new_str = uri.host + uri.path + '?' + params.to_query
First, you can parse the url for params:
require 'cgi'
url = 'https://example.com/user/tr_auth.php?key=34432&cmp_id=344&tr_id={user_id}'
string_params = url.split('?')[1]
hash = CGI::parse(string_params)
Then you can iterate the hash by keys and change values:
hash.keys.each {|key| hash[key]='new value'}
url_params = hash.to_param

Sending multiple string parameters to post request in Rails

I am using Net::HTTP::Post to send a request to a pre-determined url, like so:
my_url = '/path/to/static/url'
my_string_parameter = 'objectName=objectInfo'
my_other_string_parameter = 'otherObjectName=otherObjectInfo'
request = Net::HTTP::Post.new(my_url)
request.body = my_string_parameter
However, I know that my_url expects two string parameters. I have both parameters ready (they're statically generated) to be passed in. Is there a way to pass in multiple strings - both my_string_parameter as well as my_other_string_parameter to a post request via Ruby on Rails?
EDIT: for clarity's sake, I'm going to re-explain everything in a more organized fashion. Basically, what I have is
my_url = 'path/to/static/url'
# POST requests made to this url require 2 string parameters,
# required_1 and required_2
param1 = 'required_1=' + 'param1_value'
param2 = 'requred_2=' + 'param2_value'
request = request.NET::HTTP::Post.new(my_url)
If I try request.body = param1, then as expected I get an error saying "Required String parameter 'required_2' is not present". Same with request.body=param2, the same error pops up saying 'required_1' is not present. I'm wondering if there is a way to pass in BOTH parameters to request.body? Or something similar?
Try this.
uri = URI('http://www.example.com')
req = Net::HTTP::Post.new(uri)
req.set_form_data('param1' => 'data1', 'param2' => 'data2')
Alternative
uri = URI('http://www.example.com/')
res = Net::HTTP.post_form(uri, 'param1' => 'data1', 'param2' => 'data2')
puts res.body
For more request like Get or Patch you can refer This offical doc.
You can send it like this.
data = {'params' => ['parameter1', 'parameter2']}
request = Net::HTTP::Post.new(my_url)
request.set_form_data(data)
If your params are string:
url = '/path/to/controller_method'
my_string_parameter = 'objectName=objectInfo'
my_other_string_parameter = 'otherObjectName=otherObjectInfo'
url_with_params = "#{url}?#{[my_string_parameter, my_other_string_parameter].join('&')}"
request = Net::HTTP::Post.new(url_with_params)
If your params are hash It would be easier
your_params = {
'objectName' => 'objectInfo',
'otherObjectName' => 'otherObjectInfo'
}
url = '/path/to/controller_method'
url_with_params = "#{url}?#{your_params.to_query}"
request = Net::HTTP::Post.new(url_with_params)

Ruby, forming API request without implicitly stating each parameter

I'm trying to make a request to a web service (fwix), and in my rails app I've created the following initializer, which works... sorta, I have two problems however:
For some reason the values of the parameters need to have +'s as the spaces, is this a standard thing that I can accomplish with ruby? Additionally is this a standard way to form a url? I thought that spaces were %20.
In my code how can I take any of the options sent in and just use them instead of having to state each one like query_items << "api_key=#{options[:api_key]}" if options[:api_key]
The following is my code, the trouble area I'm having are the lines starting with query_items for each parameter in the last method, any ideas would be awesome!
require 'httparty'
module Fwix
class API
include HTTParty
class JSONParser < HTTParty::Parser
def json
JSON.parse(body)
end
end
parser JSONParser
base_uri "http://geoapi.fwix.com"
def self.query(options = {})
begin
query_url = query_url(options)
puts "querying: #{base_uri}#{query_url}"
response = get( query_url )
rescue
raise "Connection to Fwix API failed" if response.nil?
end
end
def self.query_url(input_options = {})
#defaults ||= {
:api_key => "my_api_key",
}
options = #defaults.merge(input_options)
query_url = "/content.json?"
query_items = []
query_items << "api_key=#{options[:api_key]}" if options[:api_key]
query_items << "province=#{options[:province]}" if options[:province]
query_items << "city=#{options[:city]}" if options[:city]
query_items << "address=#{options[:address]}" if options[:address]
query_url += query_items.join('&')
query_url
end
end
end
For 1)
You API provider is expecting '+' because the API is expecting in a CGI formatted string instead of URL formatted string.
require 'cgi'
my_query = "hel lo"
CGI.escape(my_query)
this should give you
"hel+lo"
as you expect
for Question 2) I would do something like
query_items = options.keys.collect { |key| "#{key.to_s}=#{options[key]}" }
def self.query_url(input_options = {})
options = {
:api_key => "my_api_key",
}.merge(input_options)
query_url = "/content.json?"
query_items = []
options.each { |k, v| query_items << "#{k}=#{v.gsub(/\s/, '+')}" }
query_url += query_items.join('&')
end
I'm a developer at Fwix and wanted to help you with your url escaping issue. However, escaping with %20 works for me:
wget 'http://geoapi.fwix.com/content.xml?api_key=mark&province=ca&city=san%20francisco&query=gavin%20newsom'
I was hoping you could provide me with the specific request you're making that you're unable to escape with %20.

Resources