Rails refuses to load a session from the data sent by swfupload - ruby-on-rails

I'm using swfupload's most recent version, 2.2.0 and rails 2.3.3. Having seen a number of statements to the effect that I would have to replace CGI::Session.initialize with a chunk of code to extract the session from key-value pairs injected into my form url, I incorporated the code segment into my environment.rb:
require 'cgi'
class CGI::Session
alias original_initialize initialize
def initialize(request, option = {})
session_key = option['session_key'] || '_session_id'
query_string = if (qs = request.env_table["QUERY_STRING"]) and qs != ""
qs
elsif (ru = request.env_table["REQUEST_URI"][0..-1]).include?("?")
ru[(ru.index("?") + 1)..-1]
end
if query_string and query_string.include?(session_key)
option['session_id'] = query_string.scan(/#{session_key}=(.*?)(&.*?)*$/).flatten.first
end
original_initialize(request, option)
end
end
I do see the session info being correctly packed into the form parameters as files are uploaded, but the above code is never firing to bring the session info out of the database.
What's the secret sauce to get from params-packed session id and authenticity tokens (they're not being picked up from the params, either)?

Rack middleware to the rescue

Related

How to get a list of website (url) cookies with Ruby

I'd like to know if there's a clean way of getting a list of cookies that website (URL) uses?
Scenario: User writes down URL of his website, and Ruby on Rails application checks for all cookies that website uses and returns them. For now, let's think that's only one URL.
I've tried with these code snippets below, but I'm only getting back one or no cookies:
url = 'http://www.google.com'
r = HTTParty.get(url)
puts r.request.options[:headers].inspect
puts r.code
or
uri = URI('https://www.google.com')
res = Net::HTTP.get_response(uri)
puts "cookies: " + res.get_fields("set-cookie").inspect
puts res.request.options[:headers]["Cookie"].inspect
or with Mechanize gem:
agent = Mechanize.new
page = agent.get("http://www.google.com")
agent.cookies.each do |cooky| puts cooky.to_s end
It doesn't have to be strict Ruby code, just something I can add to Ruby on Rails application without too much hassle.
You should use Selenium-webdriver:
you'll be able to retrieve all the cookies for given website:
require "selenium-webdriver"
#driver = Selenium::WebDriver.for :firefox #assuming you're using firefox
#driver.get("https://www.google.com/search?q=ruby+get+cookies+from+website&ie=utf-8&oe=utf-8&client=firefox-b-ab")
#driver.manage.all_cookies.each do |cookie|
puts cookie[:name]
end
#cookie handling functions
def add_cookie(name, value)
#driver.manage.add_cookie(name: name, value: value)
end
def get_cookie(cookie_name)
#driver.manage.cookie_named(cookie_name)
end
def get_all_cookies
#driver.manage.all_cookies
end
def delete_cookie(cookie_name)
#driver.manage.delete_cookie(cookie_name)
end
def delete_all_cookies
#driver.manage.delete_all_cookies
end
With HTTParty you can do this:
puts HTTParty.get(url).headers["set-cookie"]
Get them as an array with:
puts HTTParty.get(url).headers["set-cookie"].split("; ")

Is there any way to move Devise's headers response to body?

In my Rails-api app I'am using Devise gem which when authenticating returns all crucial info (Access-Token, UID, Client etc) in Headers, like this:
Access-Token →DIbgreortZbCYKqzC8HdNg
Client →Y6J5oTIqS7Gc_-h9xynBQ
Uid →email2#example.com
I want those to be in the response Body. Is there any way to achieve this?
Rails provides you with a request object so you can grab whatever you need out of the headers in your controller.
def some_action
#mime_type = request.headers["Content-Type"] # => "text/plain"
#token = request.headers["key-for-your-token-here"]
end
You can then either pass it to your view or you can insert it into the response body via request.bodyas you would insert any key/value pair into a hash.
Documentation for ActionDispatch::Request found here:
http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers
UPDATE:
Make a custom method and see how long it has to run to navigate the header hash. If long you can use it to find the exact nesting of what you're looking for and change it.
def find_token(parent, request.headers)
request.headers.each {|key, value|
if value.is_a?(Hash)
find_token(key, value)
elsif key == 'THE TOKEN KEY HERE'
return value
else
next
end
}
end

Problems with MailChimp API in Ruby Error Code: -90

I am using the following code in my MailChimp Controller to submit simple newsletter data. When It is sent I receive the following error as a "Method is not exported by this server -90" I have attached my controller code below. I am using this controller for a simple newsletter signup form. (Name, Email)
class MailchimpController < ApplicationController
require "net/http"
require "uri"
def subscribe
if request.post?
mailchimp = {}
mailchimp['apikey'] = 'f72328d1de9cc76092casdfsd425e467b6641-us2'
mailchimp['id'] = '8037342dd1874'
mailchimp['email_address'] = "email#gmail.com"
mailchimp['merge_vars[FNAME]'] = "FirstName"
mailchimp['output'] = 'json'
uri = URI.parse("http://us2.api.mailchimp.com/1.3/?method=listSubscribe")
response = Net::HTTP.post_form(uri, mailchimp)
mailchimp = ActiveSupport::JSON.decode(response.body)
if mailchimp['error']
render :text => mailchimp['error'] + "code:" + mailchimp['code'].to_s
elsif mailchimp == 'true'
render :text => 'ok'
else
render :text => 'error'
end
end
end
end
I highly recommend the Hominid gem: https://github.com/tatemae-consultancy/hominid
The problem is that Net::HTTP.post_form is not passing the "method" GET parameter. Not being a big ruby user, I'm not certain what the actual proper way to do that with Net::HTTP is, but this works:
require "net/http"
data="apikey=blahblahblah"
response = nil
Net::HTTP.start('us2.api.mailchimp.com', 80) {|http|
response = http.post('/1.3/?method=lists', data)
}
p response.body
That's the lists() method (for simplicity) and you'd have to build up (and urlencode your values!) your the full POST params rather than simply providing the hash.
Did you take a look at the many gems already available for ruby?
http://apidocs.mailchimp.com/downloads/#ruby
The bigger problem, and main reason I'm replying to this, is that your API Key is not obfuscated nearly well enough. Granted I'm used to working with them, but I was able to guess it very quickly. I would suggest immediately going and disabling that key in your account and then editing the post to actually have completely bogus data rather than anything close to the correct key. The list id on the other hand, doesn't matter at all.
You'll be able to use your hash if you convert it to json before passing it to Net::HTTP. The combined code would look something like:
mailchimp = {}
mailchimp['apikey'] = 'APIKEYAPIKEYAPIKEYAPIKEY'
mailchimp['id'] = '8037342dd1874'
mailchimp['email_address'] = "email#gmail.com"
mailchimp['merge_vars[FNAME]'] = "FirstName"
mailchimp['output'] = 'json'
response = nil
Net::HTTP.start('us2.api.mailchimp.com', 80) {|http|
response = http.post('/1.3/?method=listSubscribe', mailchimp.to_json)
}

Using OpenUri, how can I get the contents of a redirecting page?

I want to get data from this page:
http://www.canadapost.ca/cpotools/apps/track/personal/findByTrackNumber?trackingNumber=0656887000494793
But that page forwards to:
http://www.canadapost.ca/cpotools/apps/track/personal/findByTrackNumber?execution=eXs1
So, when I use open, from OpenUri, to try and fetch the data, it throws a RuntimeError error saying HTTP redirection loop:
I'm not really sure how to get that data after it redirects and throws that error.
You need a tool like Mechanize. From it's description:
The Mechanize library is used for
automating interaction with websites.
Mechanize automatically stores and
sends cookies, follows redirects, can
follow links, and submit forms. Form
fields can be populated and submitted.
Mechanize also keeps track of the
sites that you have visited as a
history.
which is exactly what you need. So,
sudo gem install mechanize
then
require 'mechanize'
agent = WWW::Mechanize.new
page = agent.get "http://www.canadapost.ca/cpotools/apps/track/personal/findByTrackNumber trackingNumber=0656887000494793"
page.content # Get the resulting page as a string
page.body # Get the body content of the resulting page as a string
page.search(".somecss") # Search for specific elements by XPath/CSS using nokogiri
and you're ready to rock 'n' roll.
The site seems to be doing some of the redirection logic with sessions. If you don't send back the session cookies they are sending on the first request you will end up in a redirect loop. IMHO it's a crappy implementation on their part.
However, I tried to pass the cookies back to them, but I didn't get it to work, so I can't be completely sure that that is all that's going on here.
While mechanize is a wonderful tool I prefer to "cook" my own thing.
If you are serious about parsing you can take a look at this code. It serves to crawl thousands of site on an international level everyday and as far as I have researched and tweaked there isn't a more stable approach to this that also allows you to highly customize later on your needs.
require "open-uri"
require "zlib"
require "nokogiri"
require "sanitize"
require "htmlentities"
require "readability"
def crawl(url_address)
self.errors = Array.new
begin
begin
url_address = URI.parse(url_address)
rescue URI::InvalidURIError
url_address = URI.decode(url_address)
url_address = URI.encode(url_address)
url_address = URI.parse(url_address)
end
url_address.normalize!
stream = ""
timeout(8) { stream = url_address.open(SHINSO_HEADERS) }
if stream.size > 0
url_crawled = URI.parse(stream.base_uri.to_s)
else
self.errors << "Server said status 200 OK but document file is zero bytes."
return
end
rescue Exception => exception
self.errors << exception
return
end
# extract information before html parsing
self.url_posted = url_address.to_s
self.url_parsed = url_crawled.to_s
self.url_host = url_crawled.host
self.status = stream.status
self.content_type = stream.content_type
self.content_encoding = stream.content_encoding
self.charset = stream.charset
if stream.content_encoding.include?('gzip')
document = Zlib::GzipReader.new(stream).read
elsif stream.content_encoding.include?('deflate')
document = Zlib::Deflate.new().deflate(stream).read
#elsif stream.content_encoding.include?('x-gzip') or
#elsif stream.content_encoding.include?('compress')
else
document = stream.read
end
self.charset_guess = CharGuess.guess(document)
if not self.charset_guess.blank? and (not self.charset_guess.downcase == 'utf-8' or not self.charset_guess.downcase == 'utf8')
document = Iconv.iconv("UTF-8", self.charset_guess, document).to_s
end
document = Nokogiri::HTML.parse(document,nil,"utf8")
document.xpath('//script').remove
document.xpath('//SCRIPT').remove
for item in document.xpath('//*[translate(#src, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")]')
item.set_attribute('src',make_absolute_address(item['src']))
end
document = document.to_s.gsub(/<!--(.|\s)*?-->/,'')
self.content = Nokogiri::HTML.parse(document,nil,"utf8")
end

SimpleDB to ActiveResource. Rails

Im looking for a way to map an ActiveResource to SimpleDB
I want to avoid plugins/gems as all I have used are outdated/buggy/not mantained
It doesnt seem hard, I wonder if any of you have succesfully implemented a rails app with simpleDB as an Active Resource. How did you do it? Thanks.
I haven't worked with SimpleDB, but I have mapped ActiveResource to Amazon's Flexible Payments Service REST api and just skimming the docs they seem similar so here's basically what I did, maybe you can use this as a starting point.
require 'base64'
require 'openssl'
class AmazonFlexiblePaymentResource < ActiveResource::Base
self.site = AMZ_CONFIG['flexible_api_url']
def self.rest_api(options = {})
params = common_request_params.update(options)
sig = compute_signature(AMZ_CONFIG['secret_access_key'], 'get', site, params)
rest_req = {'Signature' => sig}.update(params)
# make the http get call
connection.get("/#{query_string(rest_req)}", headers)
end
protected
# these are the params are common to all rest api calls
def self.common_request_params
{ 'AWSAccessKeyId' => AMZ_CONFIG['access_key_id'],
'SignatureVersion' => 2,
'SignatureMethod' => 'HmacSHA256',
'Timestamp' => Time.now.utc.iso8601,
'Version' => '2008-09-17'}
end
def self.compute_signature(key, method, end_point_url, params)
query_str = parameters.sort.collect {|k, v| v.to_query(k)}.join '&'
# cannot use plus for space, and tilde needs to be reversed
query_str.gsub!('+', '%20')
query_str.gsub!('%7E', '~')
to_sign = [method.upcase, end_point_uri.host.downcase,
end_point_uri.request_uri, query_str].join "\n"
digest = OpenSSL::Digest::Digest.new('sha256')
hmac = OpenSSL::HMAC.digest(digest, key, to_sign)
Base64.encode64(hmac).chomp
end
end
Then I just make calls like this
res = AmazonFlexiblePaymentResource.rest_api({ 'Action' => 'GetTransactionStatus', 'TransactionId' => '1234567890ABCDEFGHIJ' })
And the response is a hash of the parsed xml. Again this works for Amazon Flexible Payments Service, so you may need to make adjustments to match the SimpleDB REST API.
Does it need to be ActiveResource? If you want it like ActiveRecord, check out SimpleRecord.
http://github.com/appoxy/simple_record
It's very actively maintained.

Resources