I meet an encoding problem... No errors in the console, but the output is not well encoded.
I must use Digest::SHA1.hexdigest on a string and then must pack the result.
The below example should outputs '{´p)ODýGΗ£Iô8ü:iÀ' but it outputs '{?p)OD?GΗ?I?8?:i?' in the console and '{�p)OD�G^BΗ�I�8^D�:i�' in the log file.
So, my variable called pack equals '{?p)OD?GΗ?I?8?:i?' and not '{´p)ODýGΗ£Iô8ü:iÀ'. That's a big problem... I'm doing it in a Rails task.
Any idea guys?
Thanks
# encoding: utf-8
require 'digest/sha1'
namespace :my_app do
namespace :check do
desc "Description"
task :weather => :environment do
hexdigest = Digest::SHA1.hexdigest('29d185d98c984a359e6e6f26a0474269partner=100043982026&code=34154&profile=large&filter=movie&striptags=synopsis%2Csynopsisshort&format=json&sed=20130527')
pack = [hexdigest].pack("H*")
puts pack # => {?p)OD?GΗ?I?8?:i?
puts '{´p)ODýGΗ£Iô8ü:iÀ' # => {´p)ODýGΗ£Iô8ü:iÀ
end
end
end
This is what I did (my conversion from PHP to Ruby)
# encoding: utf-8
require 'open-uri'
require 'base64'
require 'digest/sha1'
class Allocine
$_api_url = 'http://api.allocine.fr/rest/v3'
$_partner_key
$_secret_key
$_user_agent = 'Dalvik/1.6.0 (Linux; U; Android 4.2.2; Nexus 4 Build/JDQ39E)'
def initialize (partner_key, secret_key)
$_partner_key = partner_key
$_secret_key = secret_key
end
def get(id)
# build the params
params = { 'partner' => $_partner_key,
'code' => id,
'profile' => 'large',
'filter' => 'movie',
'striptags' => 'synopsis,synopsisshort',
'format' => 'json' }
# do the request
response = _do_request('movie', params)
return response
end
private
def _do_request(method, params)
# build the URL
query_url = $_api_url + '/' + method
# new algo to build the query
http_build_query = Rack::Utils.build_query(params)
sed = DateTime.now.strftime('%Y%m%d')
sig = URI::encode(Base64.encode64(Digest::SHA1.digest($_secret_key + http_build_query + '&sed=' + sed)))
return sig
end
end
Then call
allocine = Allocine.new(ALLOCINE_PARTNER_KEY, ALLOCINE_SECRET_KEY)
puts allocine.get('any ID')
get method return 'e7RwKU9E%2FUcCzpejSfQ4BPw6acA%3D' in PHP and 'cPf6I4ZP0qHQTSVgdKTbSspivzg=%0A' in Ruby...
thanks again
I think this "encoding" issue has turned up due to debugging other parts of a conversion from PHP to Ruby. The target API that will consume a digest of params looks like it will accept a signature variable constructed in Ruby as follows (edit: well this is guess, there may also be relevant differences between Ruby and PHP in URI encoding and base64 defaults):
require 'digest/sha1'
require 'base64'
require 'uri'
sig_data = 'edhefhekjfhejk8edfefefefwjw69partne...'
sig = URI.encode( Base64.encode64( Digest::SHA1.digest( sig_data ) ) )
=> "+ZabHg22Wyf7keVGNWTc4sK1ez4=%0A"
The exact construction of sig_data from the parameters that are being signed is also important. That is generated by the PHP method http_build_query, and I do not know what order or escaping that will apply to input params. If your Ruby version gets them in a different order, or escapes differently to PHP, the signature will be wrong (edit: Actually it is possible we are looking here for a signature on the exact query string sent the API - I don't know). It is possibly an issue of that sort that has led you down the rabbit hole of how the signature is constructed?
Thank you guys for your help.
Problem is solved. With the following code I obtain exactly the same string as with PHP:
http_build_query = Rack::Utils.build_query(params)
sed = DateTime.now.strftime('%Y%m%d')
sig = CGI::escape(Base64.strict_encode64(Digest::SHA1.digest($_secret_key + http_build_query + '&sed=' + sed)))
Now I've another problem for which I opened a new question here.
thanks you very much.
Related
I'm getting a no implicit conversion of String into Integer error that has me stumped, and unable to import user records and seed my database with them.
So far I have no problem accessing the data, but receive an error referencing the '[]' on the line with User.find... on it
The code I'm using is as follows:
require 'net/http'
require 'uri'
require 'json'
require 'faker'
#this script imports APR user data from the zendesk api and populates
the database with it.
uri = URI.parse("https://blahsupport.zendesk.com/api/v2/users.json")
request = Net::HTTP::Get.new(uri)
request.content_type = "application/json"
request.basic_auth("blah#blah.com", "blahpass")
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.body
puts #response.message
puts #response.code
info = #response.body
info.force_encoding("utf-8")
File.write('blahusers1.json', info)
puts "File Created Successfully!"
file = File.read('blahusers1.json')
users = JSON.load(file)
users.each do |a|
User.find_or_create_by_zendesk_id(:zendesk_id => a['id'], :url => a['url'], :name => a['name'], :email => a['email'])
end
Any ideas on how I've gotten this error? Thank you for any help!
**Edit
Below is an example of the data being returned.
{"users":[{"id":333653859,"url":"https://blahblah.zendesk.com/api/v2/users/333653859.json","name":"Randy Blah","email":"randy#blah.com","created_at":"2014-08-06T14:31:24Z","updated_at":"2018-04-04T14:22:06Z","time_zone":"Pacific Time (US & Canada)","phone":null,"shared_phone_number":null,"photo":{"url":"https://aprtechsupport.zendesk.com/api/v2/attachments/68955389.json","id":68955389,"file_name":"Work.jpg","content_url":"https://aprtechsupport.zendesk.com/system/photos/6895/5389/Work.jpg","mapped_content_url":"https://blahblah.zendesk.com/system/photos/6895/5389/Work.jpg","content_type":"image/jpeg","size":2528,"width":80,"height":80,"inline":false,"thumbnails":[{"url":"https://blahblah.zendesk.com/api/v2/attachments/68955399.json","id":68955399,"file_name":"Work_thumb.jpg","content_url":"https://blahblah.zendesk.com/system/photos/6895/5389/Work_thumb.jpg","mapped_content_url":"https://blahblah.zendesk.com/system/photos/6895/5389/Work_thumb.jpg","content_type":"image/jpeg","size":2522,"width":32,"height":32,"inline":false}]},"locale_id":1,"locale":"en-US","organization_id":null,"role":"admin","verified":true,"external_id":null,"tags":[],"alias":"","active":true,"shared":false,"shared_agent":false,"last_login_at":"2018-04-04T14:21:44Z","two_factor_auth_enabled":null,"signature":"Thanks for contacting the helpdesk!\n-Randy","details":"","notes":"","role_type":null,"custom_role_id":null,"moderator":true,"ticket_restriction":null,"only_private_comments":false,"restricted_agent":false,"suspended":false,"chat_only":false,"default_group_id":21692179,"user_fields":{}}
The example data you posted has a root object users that contains the array of user objects. So when you loop users using users.each, a is actually an Array and not a user Hash like you expected.
When you try to access an element of an Array using a 'String' index, it gives you the exception – no implicit conversion of String into Integer
So, try changing
users = JSON.load(file)
to
users = JSON.load(file)['users']
to get it working like how you'd expect.
In the rails console:
ActionDispatch::Http::UploadedFile.new tempfile: 'tempfilefoo', original_filename: 'filename_foo.jpg', content_type: 'content_type_foo', headers: 'headers_foo'
=> #<ActionDispatch::Http::UploadedFile:0x0000000548f3a0 #tempfile="tempfilefoo", #original_filename=nil, #content_type=nil, #headers=nil>
I can write a string to #tempfile, and yet #original_filename, #content_type and #headers remain as nil
Why is this and how can I write information to these attributes?
And how can I read these attributes from a file instance?
i.e.
File.new('path/to/file.png')
It's not documented (and doesn't make much sense), but it looks like the options UploadedFile#initialize takes are :tempfile, :filename, :type and :head:
def initialize(hash) # :nodoc:
#tempfile = hash[:tempfile]
raise(ArgumentError, ':tempfile is required') unless #tempfile
#original_filename = encode_filename(hash[:filename])
#content_type = hash[:type]
#headers = hash[:head]
end
Changing your invocation to this ought to work:
ActionDispatch::Http::UploadedFile.new tempfile: 'tempfilefoo',
filename: 'filename_foo.jpg', type: 'content_type_foo', head: 'headers_foo'
Or you can set them after initialization:
file = ActionDispatch::Http::UploadedFile.new tempfile: 'tempfilefoo', filename: 'filename_foo.jpg'
file.content_type = 'content_type_foo'
file.headers = 'headers_foo'
I'm not sure I understand your second question, "And how can I read these attributes from a file instance?"
You can extract the filename (or last component) from any path with File.basename:
file = File.new('path/to/file.png')
File.basename(file.path) # => "file.png"
If you want to get the Content-Type that corresponds to a file extension, you can use Rails' Mime module:
type = Mime["png"] # => #<Mime::Type:... #synonyms=[], #symbol=:png, #string="text/png">
type.to_s # => "text/png"
You can put this together with File.extname, which gives you the extension:
ext = File.extname("path/to/file.png") # => ".png"
ext = ext.sub(/^\./, '') # => "png" (drop the leading dot)
Mime[ext].to_s # => "text/png"
You can see a list of all of the MIME types Rails knows about by typing Mime::SET in the Rails console, or looking at the source, which also shows you how to register other MIME types in case you're expecting other types of files.
the following should help you:
upload = ActionDispatch::Http::UploadedFile.new({
:tempfile => File.new("#{Rails.root}/relative_path/to/tempfilefoo") , #make sure this file exists
:filename => "filename_foo" # use this instead of original_filename
})
upload.headers = "headers_foo"
upload.content_type = "content_type_foo"
I didn't understand by "And how can I read these attributes from a file instance?", what you exactly want to do.
Perhaps if you want to read the tempfile, you can use:
upload.read # -> content of tempfile
upload.rewind # -> rewinds the pointer back so that you can read it again.
Hope it helps :) And let me know if I have misunderstood.
I'm trying to put a file on a site with WEB_DAV. (a ruby gem)
When I follow the example, I get a nil exception
#### GEMS
require 'rubygems'
begin
gem "net_dav"
rescue LoadError
system("gem install net_dav")
Gem.clear_paths
end
require 'net/dav'
uri = URI('https://staging.web.mysite');
user = "dave"
pasw = "correcthorsebatterystaple"
dav = Net::DAV.new(uri, :curl => false)
dav.verify_server = false
dav.credentials(user, pasw)
cargo = ("testing.txt")
File.open(cargo, "rb") { |stream|
dav.put(urI.path +'/'+ cargo, stream, File.size(cargo))
}
when I run this I get
`digest_auth': can't convert nil into String (TypeError)
this relates to line 197 in my nav.rb file.
request_digest << ':' << params['nonce']
So what I'm wondering is what step did I not add?
Is there a reasonable example of the correct use of this gem? Something that does something that works would be sweet :)
SIDE QUESTION: Is this the correct gem to use to do web_DAV? It seems an old unmaintained gem, perhaps there's something used by more to accomplish the task?
Try referencing the hash with a symbol rather than a string, i.e.
request_digest << ':' << params[:nonce]
In a simple test
baz = "baz"
params = {:foo => "bar"}
baz << ':' << params['foo']
results in the same error as you're getting.
I'm trying to pull a facebook avatar via auth. Here's what i'm doing:
def image_uri
require 'net/http'
image = URI.parse(params[:image]) # https://graph.facebook.com/565515262/picture
fetch = Net::HTTP.get_response(image)
based = 'data:image/jpg;base64,' << Base64.encode64(fetch)
render :text => based
end
I'm getting the following error (new error — edited):
Connection reset by peer
I've tried googling about, I can't seem to get a solution, any ideas?
I'm basically looking for the exact functioning of PHP's file_get_contents()
Try escaping the URI before parsing:
URI.parse URI.escape(params[:image])
Make sure that params[:image] does contain the uri you want to parse... I would instead pass the userid and interpolate it into the uri.
URI.parse URI.escape("https://graph.facebook.com/#{params[:image]}/picture)"
Does it throw the same error when you use a static string "https://graph.facebook.com/565515262/picture"
What does it say when you do
render :text => params[:image]
If both of the above don't answer your question then please try specifying the use of HTTPS-
uri = URI('https://secure.example.com/some_path?query=string')
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https').start do |http|
request = Net::HTTP::Get.new uri.request_uri
response = http.request request # Net::HTTPResponse object
end
Presuming you are on ruby < 1.9.3, you will also have to
require 'net/https'
If you are on ruby 1.9.3 you don't have to do anything.
Edit
If you are on the latest version, you can simply do:
open(params[:image]) # http://graph.facebook.com/#{#user.facebook_id}/picture
I got the following back from delayed_job:
[Worker(XXXXXX pid:3720)] Class#XXXXXXX failed with URI::InvalidURIError: bad URI(is not URI?): https://s3.amazonaws.com/cline-local-dev/2/attachments/542/original/mac-os-x[1].jpeg?AWSAccessKeyId=xxxxxxxx&Expires=1295403309&Signature=xxxxxxx%3D - 3 failed attempts
The way this URI comes from in my app is.
In my user_mailer I do:
#comment.attachments.each do |a|
attachments[a.attachment_file_name] = open(a.authenticated_url()) {|f| f.read }
end
Then in my attachments model:
def authenticated_url(style = nil, expires_in = 90.minutes)
AWS::S3::S3Object.url_for(attachment.path(style || attachment.default_style), attachment.bucket_name, :expires_in => expires_in, :use_ssl => attachment.s3_protocol == 'https')
end
That being said, is there some type of URI.encode or parsing I can do to prevent a valid URI (as I checked the URL works in my browser) for erroring and killing delayed_job in rails 3?
Thank you!
Ruby has (at least) two modules for dealing with URIs.
URI is part of the standard library.
Addressable::URI, is a separate gem, and more comprehensive, and claims to conform to the spec.
Parse a URL with either one, modify any parameters using the gem's methods, then convert it using to_s before passing it on, and you should be good to go.
I tried ' open( URI.parse(URI.encode( a.authenticated_url() )) ' but that errord with OpenURI::HTTPError: 403 Forbidden
If you navigated to that page via a browser and it succeeded, then later failed going to it directly via code, it's likely there is a cookie or session state that is missing. You might need to use something like Mechanize, which will maintain that state while allowing you to navigate through a site.
EDIT:
require 'addressable/uri'
url = 'http://www.example.com'
uri = Addressable::URI.parse(url)
uri.query_values = {
:foo => :bar,
:q => '"one two"'
}
uri.to_s # => "http://www.example.com?foo=bar&q=%22one%20two%22"