I had uploads to Amazon s3 working with AngularJS and NodeJS but now am using Rails as the backend. So I figured all I'd have to do is translade NodeJS code to Rails. Source: https://github.com/nukulb/s3-angular-file-upload/blob/master/lib/controllers/aws.js
and my conversion:
def aws_signature
mime_type = "image/jpeg"
expiration = Date.new(Time.now.year + 1, 01, 01) #Time.now.utc.strftime('%Y/%m/%d %H:%M:%S+00:00')
s3_policy = {
expiration: expiration,
conditions: [
['starts-with', '$key', '/'],
{bucket: ENV["BUCKET"] },
{acl: 'public-read'},
['starts-with', '$Content-Type', mime_type],
{success_action_status: '201'}
]
}
puts s3_policy.inspect
string_policy = s3_policy.to_json
puts string_policy.inspect
base64_policy = URI.escape(Base64.encode64(string_policy).strip)
puts base64_policy.inspect
digest = OpenSSL::Digest::Digest.new('sha1')
signature = OpenSSL::HMAC.digest(digest, ENV["S3_SECRET"], base64_policy)
puts signature.inspect
s3_credentials = {
s3Policy: base64_policy,
s3Signature: signature,
AWSAccessKeyId: ENV["S3_KEY"]
}
render json: s3_credentials
end
Now I am getting a 304 response from Amazon with SignatureDoesNotMatch in xml.
Did I miss something in the conversion to rails code?
Is there a way to compare the unencrypted params received in amazon?
Related
I am trying to connect to Binance api from my Rails application. But every time I am getting 401 unauthorized error message from Binance. Below is my code.
class Binance
END_POINT = 'https://api.binance.com'.freeze
KEY = 'my-binance-key'
SECRET = 'my-binance-secret'
def self.account_info
url = "#{END_POINT}/api/v3/account"
query_string = "timestamp=#{DateTime.now.strftime('%Q')}"
digest = OpenSSL::Digest.new('sha256')
signature = OpenSSL::HMAC.hexdigest(digest, SECRET, query_string)
url = "#{END_POINT}/api/v3/account?#{query_string}&signature=#{signature}"
response = RestClient.get(url, headers: { 'X-MBX-APIKEY': KEY })
end
end
Here is a link from Binance api with example:
https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#signed-endpoint-examples-for-post-apiv3order
I'm trying to integrate AWS Rekognition into my Rails app. After the user uploads his avatar via Active Storage, Rekognition should show some info about it.
def update
respond_to do |format|
if #user.update(user_params)
if #user.images.attached?
Aws.config.update({
region: 'us-west-2',
credentials: Aws::Credentials.new('ACCESS_KEY', 'SECRET_KEY')
})
rekognition = Aws::Rekognition::Client.new(region: Aws.config[:region], credentials: Aws.config[:credentials])
img = #user.images.first. # original was: File.read(ARGV.first)
#detect faces
resp = rekognition.detect_faces({
image: { bytes: img },
attributes: ["ALL"], # What attributes to return
})
resp.face_details[0].emotions.each do |emo|
puts emo.type + " " + emo.confidence.to_i.to_s #=> Strings "HAPPY", "SAD", "ANGRY"
end
end
end
end
However, I get the error
expected params[:image][:bytes] to be a String or IO object, got value #<ActiveStorage::Attachment id: 4, name: "images", record_type: "User", record_id: 47, blob_id: 9, created_at: ""> (class: ActiveStorage::Attachment) instead.
How can I get the image file property into AWS Rekognition?
There is two way to pass image to Aws::Rekognition.
AWS S3 image url and name
resp = rekognition.detect_faces(
{image:
{s3_object:
{bucket: `bucket name`,
name: `pull path of file`,
},
}, attributes: ['ALL'],
}
)
Via Image object
rekognition.detect_faces({
image: { bytes: File.read(`path of file`) }
})
in your case you are passing ActiveStorage object that can't parse by AWS. that's why it throw error.
I am trying to get Paperclip to upload an image to s3 from my festival model on form submit but am receiving the Unpermitted parameter: image. error
I have checked the strong params, the model content validation and read through the paperclip documents with no avail.
I think I have narrowed the problem down to my post request to the DB cannot handle the File object that gets assigned to festival.image, but can't figure out how I would represent this in the post request.
I am capturing the data in rails using react on rails on the front end with Rails as the backend. I was following along with this sample code https://github.com/carlbaron/react-file-upload-demo
I also use React-dropzone to capture the uploaded file and it adds the preview attribute for the image preview.
Been stuck on this for some time now, any help greatly appreciated!
Beginning of the post request printed to console
Processing by FestivalsController#create as JSON
Parameters: {"festival"=>{"fest_name"=>"Test Festival", "image"=>{"preview"=>"blob:http://localhost:5000/76b95cb5-45bf-46a9-ba7b-f5b9ad127521"}}}
| Unpermitted parameter: image
Festival object printed to the console
Post Request to the DB via axios
postFestival(festival) {
let config = {
responseType: 'json',
processData: false,
contentType: false,
headers: ReactOnRails.authenticityHeaders(),
};
let str = JSON.stringify(festival);
console.log("ENTITY IS " + str);
//returns
//ENTITY IS {"fest_name":"Test Festival","image":{"preview":"blob:http://localhost:5000/76b95cb5-45bf-46a9-ba7b-f5b9ad127521"}}
return(
request.post('/festivals/create', {festival}, config)
);
},
Festival.rb
class Festival < ApplicationRecord
has_attached_file :image, default_url: "/assets/ASOT-COVER.png"
validates_attachment :image,
content_type: { content_type: ["image/jpeg", "image/gif", "image/png"] }
end
Festivals Controller
def create
#festival = Festival.create(festival_params)
puts "festival.image =" + #festival.image.inspect
#returns = festival.image =#<Paperclip::Attachment:0x007fc288868bf0 #name=:image, #name_string="image", #instance=#
if #festival.save
puts "Festival SAved = + " + #festival.inspect
#returns the festival object saved to the DB minus the image param
else
respond_to do |format|
format.json { render json: #festival.errors, status: :unprocessable_entity}
puts "ERROR = " + #festival.errors.inspect
end
end
private
def festival_params
params.require(:festival).permit(:fest_name, :fest_organizer, :fest_location,
:fest_date, :fest_url, :fest_venue, :fest_description,
:image)
end
end
As the image parameter in your request is a hash "image"=>{"preview"=>"blob:http://localhost:5000/76b95cb5-45bf-46a9-ba7b-f5b9ad127521"}, you will need to modify your festival_params method like this:
def festival_params
params.require(:festival).permit(:fest_name, :fest_organizer, :fest_location,
:fest_date, :fest_url, :fest_venue, :fest_description,
{ image: :preview })
end
Let me know if it solves the error.
I am trying to use the bitbucket API. I have successfully got the flow working where I am able to retrieve the access token and access token secret. After that, I have not been able to get anything to work. I can't find any example on to get this to work with Ruby. The closest I think I've found is this link:
https://gist.github.com/erikeldridge/383159
However in this example, he doesn't add the user's token and token secret, so I've updated it, here's his utility code:
# A utility for signing an url using OAuth in a way that's convenient for debugging
# Note: the standard Ruby OAuth lib is here http://github.com/mojodna/oauth
# License: http://gist.github.com/375593
# Usage: see example.rb below
require 'uri'
require 'cgi'
require 'openssl'
require 'base64'
class OauthUtil
attr_accessor :consumer_key, :consumer_secret, :token, :token_secret, :req_method,
:sig_method, :oauth_version, :callback_url, :params, :req_url, :base_str
def initialize
#consumer_key = ''
#consumer_secret = ''
#token = ''
#token_secret = ''
#req_method = 'GET'
#sig_method = 'HMAC-SHA1'
#oauth_version = '1.0'
#callback_url = ''
end
# openssl::random_bytes returns non-word chars, which need to be removed. using alt method to get length
# ref http://snippets.dzone.com/posts/show/491
def nonce
Array.new( 5 ) { rand(256) }.pack('C*').unpack('H*').first
end
def percent_encode( string )
# ref http://snippets.dzone.com/posts/show/1260
return URI.escape( string, Regexp.new("[^# {URI::PATTERN::UNRESERVED}]") ).gsub('*', '%2A')
end
# #ref http://oauth.net/core/1.0/#rfc.section.9.2
def signature
key = percent_encode( #consumer_secret ) + '&' + percent_encode( #token_secret )
# ref: http://blog.nathanielbibler.com/post/63031273/openssl-hmac-vs-ruby-hmac-benchmarks
digest = OpenSSL::Digest::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, key, #base_str )
# ref http://groups.google.com/group/oauth-ruby/browse_thread/thread/9110ed8c8f3cae81
Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
end
# sort (very important as it affects the signature), concat, and percent encode
# #ref http://oauth.net/core/1.0/#rfc.section.9.1.1
# #ref http://oauth.net/core/1.0/#9.2.1
# #ref http://oauth.net/core/1.0/#rfc.section.A.5.1
def query_string
pairs = []
#params.sort.each { | key, val |
pairs.push( "#{ percent_encode( key ) }=#{ percent_encode( val.to_s ) }" )
}
pairs.join '&'
end
# organize params & create signature
def sign( parsed_url )
#params = {
'oauth_consumer_key' => #consumer_key,
'oauth_nonce' => nonce,
'oauth_signature_method' => #sig_method,
'oauth_timestamp' => Time.now.to_i.to_s,
'oauth_version' => #oauth_version
}
# if url has query, merge key/values into params obj overwriting defaults
if parsed_url.query
#params.merge! CGI.parse( parsed_url.query )
end
# #ref http://oauth.net/core/1.0/#rfc.section.9.1.2
#req_url = parsed_url.scheme + '://' + parsed_url.host + parsed_url.path
# create base str. make it an object attr for ez debugging
# ref http://oauth.net/core/1.0/#anchor14
#base_str = [
#req_method,
percent_encode( req_url ),
# normalization is just x-www-form-urlencoded
percent_encode( query_string )
].join( '&' )
# add signature
#params[ 'oauth_signature' ] = signature
return self
end
end
and here's my modified code:
require 'oauth_util.rb'
require 'net/http'
o = OauthUtil.new
o.consumer_key = MY_CONSUMER_KEY
o.consumer_secret = MY_SECRET
o.token = ACCESS_TOKEN_RETURNED_FROM_BB
o.token_secret = ACCESS_TOKEN_SECRET_RETURNED_FROM_BB
url = 'https://bitbucket.org/api/1.0/user'
parsed_url = URI.parse( url )
Net::HTTP.start( parsed_url.host ) { | http |
req = Net::HTTP::Get.new "#{ parsed_url.path }?#{ o.sign(parsed_url).query_string }"
response = http.request(req)
print response.read_body
}
Sadly, all I get is
301 Moved Permanently
301 Moved Permanently
nginx/1.5.10
Anyone have any luck using the BB API in Ruby after getting an access token back? Thanks for any help,
Kevin
EDIT:
There is a bitbucket API wrapper gem that has authentication built-in.
ORIGINAL:
I'm wondering if the "301 moved permanently" error is caused by the code making an http request instead of https.
without ssl:
result = Net::HTTP.get(URI.parse('http://bitbucket.org/api/1.0/user'))
# this returns 301 Moved Permanently
But when I used ssl instead (without the oauth headers/params) I got 401 Unauthorized.
with ssl:
1.9.3-p194 :063 > uri = URI.parse('https://bitbucket.org/api/1.0/user')
=> #<URI::HTTPS:0x007f846c5822d8 URL:https://bitbucket.org/api/1.0/user>
1.9.3-p194 :064 > http = Net::HTTP.new(uri.host, uri.port)
=> #<Net::HTTP bitbucket.org:443 open=false>
1.9.3-p194 :065 > http.use_ssl = true
=> true
1.9.3-p194 :066 > request = Net::HTTP::Get.new(uri.request_uri)
=> #<Net::HTTP::Get GET>
1.9.3-p194 :067 > response = http.request(request)
=> #<Net::HTTPUnauthorized 401 UNAUTHORIZED readbody=true>
I am creating a ruby script and it should do the above. Over the day I was trying to crack I way to send an HTML email to a selected number of emails addresses. There is no clear documentation on how I should do, So please I will appreciate you helping.
Here is my code, The script is successfully authorizing a user and picking the code to access his/her gmail account. Now I want to send the HTML email on behalf of that user.
require 'rubygems'
require 'google/api_client'
require 'launchy'
CLIENT_ID = 'my_app_Id_on_gmail_developers_console'
CLIENT_SECRET = 'the_secret_key'
OAUTH_SCOPE = 'https://mail.google.com/'
REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
# Create a new API client & load the Google Drive API
client = Google::APIClient.new(:application_name => 'Ruby Gmail sample',
:application_version => '1.0.0')
gmail = client.discovered_api('gmail', "v1")
# Request authorization
client.authorization.client_id = CLIENT_ID
client.authorization.client_secret = CLIENT_SECRET
client.authorization.scope = OAUTH_SCOPE
client.authorization.redirect_uri = REDIRECT_URI
uri = client.authorization.authorization_uri
Launchy.open(uri)
# Exchange authorization code for access token
$stdout.write "Enter authorization code: "
client.authorization.code = gets.chomp
client.authorization.fetch_access_token!
#testing if it is working well by counting the emails.
#emails = client.execute(
api_method: gmail.users.messages.list,
parameters: {
userId: "me"},
headers: {'Content-Type' => 'application/json'}
)
count = #emails.data.messages.count
puts "you have #{count} emails "
# Pretty print the API result
jj #emails.data.messages
how can I do this? is there a way I can an external html file which is the email file to be sent. then I can sent this file using the script?
I partially accept the answer above since you can send an email through STMP pretty easily but with the gmail API it's even easier. According your code it should looks like this:
message = Mail.new
message.date = Time.now
message.subject = 'Supertramp'
message.body = "<p>Hi Alex, how's life?</p>"
message.content_type = 'text/html'
message.from = "Michal Macejko <michal#macejko.sk>"
message.to = 'supetramp#alex.com'
service = client.discovered_api('gmail', 'v1')
result = client.execute(
api_method: service.users.messages.to_h['gmail.users.messages.send'],
body_object: {
raw: Base64.urlsafe_encode64(message.to_s)
},
parameters: {
userId: 'michal#macejko.sk'
},
headers: { 'Content-Type' => 'application/json' }
)
response = JSON.parse(result.body)
For multi-part email with the attachment:
message = Mail.new
message.date = Time.now
message.subject = 'Supertramp'
message.from = "Michal Macejko <michal#macejko.sk>"
message.to = 'supetramp#alex.com'
message.part content_type: 'multipart/alternative' do |part|
part.html_part = Mail::Part.new(body: "<p>Hi Alex, how's life?</p>", content_type: 'text/html; charset=UTF-8')
part.text_part = Mail::Part.new(body: "Hi Alex, how's life?")
end
open('http://google.com/image.jpg') do |file|
message.attachments['image.jpg'] = file.read
end
Just my input. I was able to create a script that emailed html to multiple users in about 100 lines. Without using an api. You need to look into using smtp. It is very simple. You define a server for it to use and then you use it's "send_message" method. Here's a link to a good site! GOOD SITE
I can't post my whole code here for security reasons however this should get you started
class Email_Client
attr_accessor :message_contents, :subject
def initialize(sender_name, receiver_name, sender_email, receiver_email)
#sender_name = sender_name
#receiver_name = receiver_name
#sender_email = sender_email
#receiver_email = receiver_email
end
def send_html
message = <<MESSAGE
From: #{#sender_name} <#{#sender_email}>
To: #{#receiver_name} <#{#receiver_email}>
MIME-Version: 1.0
Content-type: text/html
Subject: #{subject}
#{message_contents}
MESSAGE
Net::SMTP.start('SeRvEr_HeRe') do |smtp|
smtp.send_message message,
#sender_email,
#receiver_email
end
end