eXpand yOur cReativity by Bhushan G Ahire

17Feb/100

Setup Capistrano to deploy Rails application on Amazon EC2 with Git

1: Create a new Rails app - we'll call is 'deploytest'

$ rails deploytest
$ cd deploytest

2: Create a local Git repository for it

$ git init
$ git add *
$ git commit -a -m 'initial commit'
$ git status

3: Create a couple of Capistrano files

$ capify .

4: Edit config/deploy.rb

# The name of your app
set :application, "deploytest"
# The directory on the EC2 node that will be deployed to
set :deploy_to, "/var/www/apps/#{application}"
# The type of Source Code Management system you are using
set :scm, :git
# The location of the LOCAL repository relative to the current app
set :repository,  "."
# The way in which files will be transferred from repository to remote host
# If you were using a hosted github repository this would be slightly different
set :deploy_via, :copy

# The address of the remote host on EC2 (the Public DNS address)
set :location, "ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com"
# setup some Capistrano roles
role :app, location
role :web, location
role :db,  location, :primary => true

# Set up SSH so it can connect to the EC2 node - assumes your SSH key is in ~/.ssh/id_rsa
set :user, "root"
ssh_options[:keys] = [File.join(ENV["HOME"], ".ssh", "id_rsa")]

The only account on a default EC2 instance is root. You probably want to create a second user that is responsible for your application.

5: Copy your SSH public key to your EC2 node

$ scp -i ~/my-ec2-keypair ~/.ssh/id_rsa.pub root@ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com:/root/.ssh/authorized_keys2

NOTE the filename authorized_keys2 - not authorized_keys!!

6: Setup the EC2 node for Capistrano deployment.
From your LOCAL machine, not the EC2 node:

$ cap deploy:setup

7: Finally, deploy your application

$ cap deploy

You will see lots of output and with this dummy application some of those will report errors/warnings. Don't worry about that for now.

8: Check that the Deployment was successful
Connect to the EC2 node with SSH the regular way, cd to the app directory and check that everything is there. If that is all working then you are ready to deploy a real application and add custom tasks for managing the database, restarting the server etc.

Bear in mind that Capistrano add new 'releases' of your software in separate directories and symlinks the 'current' directory to the latest. So the root of your deployed application is the 'current' subdirectory.

Hope this will help you setting up your ec2 instance with capistrano.

15Jan/100

Send SMS from Ruby On Rails application using web service, SOAP API

SOAP4R is a Ruby library for accessing Web Services via SOAP. Recently I had a chance to explore SOAP4R. Here's how to get started with it.

Installation

Although Ruby 1.8.x comes with SOAP4R in its standard library, it is an old, buggy version. I highly recommend using the latest gem (1.5.8 as of the this update). It has one dependency, httpclient.

gem install soap4r --include-dependencies

Service

There are many services available to send SMS but I prefer to use,

MailServe-SMS

MailServe-SMS, text messaging service, is everything you need for fast, no-frills, no-fuss text messaging. A quick and easy way to send SMS.

Let’s explore these further.

Method 1: Read the WSDL at run-time

 

require "soap/wsdlDriver"
wsdl = "http://sms.qlc.co.in/smsapi.wsdl"
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_drive

 

A single call to a driver factory reads the WSDL file, and creates a driver class for you to use, complete with the methods defined by the service. What if your service requires authentication? The driver inherits methods from httpclient, so you can specify its options as you would for httpclient:

Once driver is get initialised you need to call SMS sending API i.e. SendSMSRequest.

driver.SendSMSRequest("username", "password", "sender_no", "from_no", "message")

 

Once This will return you response 200 SMS sent successfully on success else if the information submitted was wrong then 500 Information submitted was incomplete.

 

Method 2: Generate classes from WSDL

SOAP4R installs a command-line utility called 'wsdl2ruby' which can generate a client or server.

Coming soon…..

20May/090

Get location from IP address in Ruby On Rails for free….

Find below the code for finding location from IP address using IP location tools.

require 'net/http'
require 'rexml/document'
include REXML

class MapsController < ApplicationController
	def index
		@location = locateIp()

	end

	def locateIp
		ip = request.remote_ip
		ips = ip.to_s
		url = "http://iplocationtools.com/ip_query.php?ip="+ips

		xml_data = Net::HTTP.get_response(URI.parse(url)).body

                xmldoc = REXML::Document.new(xml_data)

		# Now get the root element
		root = xmldoc.root
		city = ""
		regionName = ""
		countryName = ""

		# This will take country name...
		xmldoc.elements.each("Response/CountryName") {
		|e| countryName << e.text
	    }

		# Now get city name...
		xmldoc.elements.each("Response/City") {
   		|e| city << e.text
	    }

		# This will take regionName...
		xmldoc.elements.each("Response/RegionName") {
   		|e| regionName << e.text
	    }

     	ipLocation = city +", "+regionName+", "+countryName

	 return ipLocation
   end #end of method locateIp

end
3Mar/090

Generating ZIP files via Ruby on Rails using rubyzip

gem install rubyzip

Then, in the model that I’m using to generate the zip bundles, I add a couple “require” statements:

require 'zip/zip'
require 'zip/zipfilesystem'

class Album < ActiveRecord::Base
  (...)
end

Next, I added a class method called bundle, which when called will use rubygem to generate the zip file. Note: the “permalink” attributes of Album and Artist are populated when an object of those models is created. I’m using them because it makes for nice filenames, too.

# create a zipped archive file of all the tracks in an album
def bundle(name = self.permalink, set = self.artist.permalink)
   bundle_filename = "#{RAILS_ROOT}/public/uploads/#{set}-#{name}.zip"

   # check to see if the file exists already, and if it does, delete it.
   if File.file?(bundle_filename)
     File.delete(bundle_filename)
   end

   # set the bundle_filename attribute of this object
   self.bundle_filename = "/uploads/#{set}-#{name}.zip"

   # open or create the zip file
   Zip::ZipFile.open(bundle_filename, Zip::ZipFile::CREATE) {
     |zipfile|
     # collect the album's tracks
     self.tracks.collect {
       |track|
         # add each track to the archive, names using the track's attributes
         zipfile.add( "#{set}/#{track.num}-#{track.filename}", "#{RAILS_ROOT}/public#{track.public_filename}")
       }
   }

   # set read permissions on the file
   File.chmod(0644, bundle_filename)

   # save the object
   self.save
end

Next I added a method in my controller:

def create_bundle
   album = Album.find(params[:id])
   album.bundle
   flash[:notice] = 'Album was successfully zipped.'
   redirect_to album_url(album.artist, album)
end

And edit my routes.rb accordingly:

map.create_bundle 'create_bundle/:id', :controller => 'albums', :action => 'create_bundle'

Now it’s just a matter of creating a link in the view for the admin to click whenever he/she wants to generate the zip file:

<%= link_to('Create Album Zip', create_bundle_path(@album)) %>

…and a link for the user to click to download the zip file if it exists:

<% unless @album.bundle_filename.nil? %>
<%= link_to "Download Album Zip", @album.bundle_filename %>
<% end %>

That’s it! Refer to the rubyzip documentation for more info.

Tagged as: , , No Comments
13May/080

New features in Rails 2

Today i was reading about the new features of Rails 2, there are a lot of changes, for an overview you can checkout the official rails blog announcement. Here is a little list of major changes and new features:
Tagged as: , No Comments
18Mar/080

Ruby thumbnail generator

Ruby thumbnail generator is simple script which is ideal to use in your Ruby on Rails application to quickly generate thumbnails of any proportions. Just set width and height and get the image.

1. copy following code into /controllers/thumb_controller.rb

2. edit /config/routes.rb and add this line:
map.connect "thumb/*specs", :controller => "thumb", :action => "index"

3. create directory /imagelib/ in RoR's /public/ directory and
/image_cache/ inside /imagelib/ directoory

Now you can call /thumb/photo.jpg?w=400&h=350 and you will
see resized picture "photo.jpg". photo.jpg should be stored in
/public/imagelib/ directory. Off course you can change directory
structure if you wish just don't forget to edit thumb_controller.rb
than.

visit www.cleverleap.com/ruby-thumbnail-generator/
for more information

class ThumbController < ApplicationController

  require 'gd2'
  include GD2

  def index

    path = "imagelib/"    # default image library directory

    widthx = 500          # default width of generated image
    heightx = 500         # default height of generated image

    if params[:w] then widthx = params[:w].to_i

    end

    if params[:h] then heightx = params[:h].to_i

    end

    filepath = path + params[:specs].join("/")    # Path to file

    format = filepath.split(".").last             # Format - extension

    filename = params[:specs].last.split(".").first # just file name without extension

    #require 'digest/md5'
    digest = Digest::MD5.hexdigest( filepath )      # md5 hash

    cachefile = digest + "-" + widthx.to_s + heightx.to_s + "." + format

    picfile = filepath
    cachedpicfile = path + "image_cache/" + cachefile

    if File.exists?(cachedpicfile) && (File.stat( cachedpicfile ).mtime.to_i > File.stat( picfile ).mtime.to_i)

      picsource = cachedpicfile
      cache = true
    elsif File.exists? picfile
      picsource = picfile

    end

    if cache == true    # Read from Cache
      @pic = File.new(picsource).read

    else                # Import an image
      i = Image.import(picsource)

      if i.size[0] > i.size[1]  # Horizontal proportion. width > height.

        if i.size[0] < widthx then width = i.size[0]     # preffer smaller image width

        else width = widthx
        end

        height = width * i.size[1] / i.size[0]

      else                      # Vertical proportions
        if i.size[1] < heightx then height = i.size[1]

        else height = heightx
        end

        width = i.size[0] /(i.size[1] / height)
      end

      i.resize! width, height

      if format == "gif" then @pic = i.gif

      elsif format == "png" then @pic = i.png

      else @pic = i.jpeg 80
      end

      i.export(path + 'image_cache/' + cachefile ) # export cache file

    end

    cgi = CGI.new
  	cgi.out("type"=>"image/jpeg") { @pic }

  	render :nothing => true

  end
end
Tagged as: , No Comments
18Mar/080

god Server process monitoring and notifying tool written in ruby

Progress on god is moving along as quick as ever. Most interestingly you'll find several useful new command line functions:

  • god status prints out the status of each Watch
  • god log shows realtime logs for a specific Watch (even if you don't have god logging to file)
  • god load loads or reloads a config file into a running god instance
  • god terminate stops all Watches and then stops god (useful when testing your setup)

The logging system has been beefed up with proper timestamps and criticality levels. Log messages are more complete overall. You can also get the STDOUT/STDERR of a god-daemonized process written to a log file by specify 'w.log = ' in your Watch config.

If you let god daemonize your process for you, there's no need to provide a stop command. A default killing lambda will take care of gracefully (or not so gracefully if necessary) stopping your god-daemonized process.

The validity of your config file is checked better than previous versions to point you to the problem area of your config.

The bug that prevented group control from working has been fixed so you can now start/stop/etc groups of Watches.

Updated documentation is now available on the website:

http://god.rubyforge.org/

WHAT IS GOD?

God is an easy to configure, easy to extend monitoring framework written in Ruby.

Keeping your server processes and tasks running should be a simple part of your deployment process. God aims to be the simplest, most powerful monitoring application available.

INSTALL

sudo gem install god

FEATURES

  • Config file is written in Ruby
  • Easily write your own custom conditions in Ruby
  • Supports both poll and event based conditions
  • Different poll conditions can have different intervals
  • Easily control non-daemonized processes

EXAMPLE

The easiest way to understand how god will make your life better is by looking at a sample config file. The following configuration file is to keep the mongrels running:

# file:      application_name.god
# run with:  god -c /path/to/application_name.god
# 
# This is the actual config file used to keep the mongrels of
# application.com running.
RAILS_ROOT = "/var/www/application_name/current"
%w{8001 8002 8003}.each do |port|
  God.watch do |w|
    w.name = "application_name-mongrel-#{port}"
    w.interval = 30.seconds # default
    w.start = "mongrel_rails cluster::start --only #{port} \
      -C #{RAILS_ROOT}/config/mongrel_cluster.yml"
    w.stop = "mongrel_rails cluster::stop --only #{port} \
      -C #{RAILS_ROOT}/config/mongrel_cluster.yml"
    w.grace = 10.seconds
    w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")    
    w.behavior(:clean_pid_file)
    w.start_if do |start|
      start.condition(:process_running) do |c|
        c.interval = 5.seconds
        c.running = false
      end
    end 
    w.restart_if do |restart|
      restart.condition(:memory_usage) do |c|
        c.above = 150.megabytes
        c.times = [3, 5] # 3 out of 5 intervals
      end    
      restart.condition(:cpu_usage) do |c|
        c.above = 50.percent
        c.times = 5
      end
    end
  end
end

Configuration for nginx and mysql
I found a gr8 post for sample configuration here

DOCS

Detailed documentation is available at http://god.rubyforge.org/

Original Source...

8Feb/081

Ruby On Rails Security Guide

Ruby on Rails does a decent job in handling security concerns in the background. You will have to configure your application to avoid few security attacks while plugins would be required for many security concerns which are not at all or poorly managed by rails.

Authentication

Authentication is the foremost requirement of most of the web applications to authenticate and give privileges to their users. Apart from normal authentication mechanism rails have plugins for OpenID, CAS and Access Control. Build your own authentication system only if your requirements are very unique or you do not trust other implementations.

Plugin - Restful Authentication (recommended) - easy to use and you can tweak it according to your requirements.

Build your own authentication. You should rarely need to do this ... Restful Authentication is quite flexible.

OpenID - a universal authentication system to avoid use of multiple username and password on the Internet. OpenID is getting quite famous now-a-days.

Access Control : To easily proivde different priviliges to your users. There are a lot of cool plugins available for access control.

Centralized Authentication Server - is used to implement single login/password for your users across multiple application. It can also be used for a single sign-on system. For example, Gmail and Google Reader have a single sign-on between them.

Use Google Authentication API to let your users login using their google username and password.

More Plugins :

- Model -

SQL Injection

The problem arises when metacharacters are injected into your queries to database. Rails has a very good support to avoid SQL injection if you follow conventions in issuing queries to your database.

Description :

Alternate Solution - use hash for specifying conditions in #find

Activerecord Validation

To validate the contents of model object before records are created/modified in the database. Activerecord validations are very useful over database data-type constraints to ensure values entered into the database follow your rules. You might have javascript validations for forms but javascript can easily be switched off. Use javascript validations only for better user experience.

Description :

Conditional validation using :o n and :if options. Checkout this cool video

Be careful using validates_uniqueness_of, it has problems when used with :scope option. Open bug tickets :

Use :allow_blank to pass validations if value is nil or empty string

Testing Validations - do read the comments in this article

Useful Tips

  • Its easy to manage 'nil' values using :allow_nil, its quite handy. For ex: set :allow_nil => true in validates_uniqueness_of to check uniqueness of non-nil values and ignore nil values
  • validates_presence_of is not required if you are using validates_format_of, unless regular expression accepts empty string.

Creating records directly from parameters

While creating database records directly from form params, a malicious user can add extra fields into the params and manually submit the web page which will set values of fields which you do not want user to set.

Description :

Alternate Solution - Trim the parameters to keep the required keys and remove the others.

- Controller -

Exposing methods

Use private and protected in controller for methods which should not be actions. Actions are pubic methods and can be invoked from the browser.

hide_action : If non-action controller methods must be public, hide them using hide_action.

Be careful of bypassing private and protected using meta-programming

Authorize parameters

Always authorize user request. By tweaking form parameters or url a user can send request to view/modify other users information if there is no proper authorization of parameters.

For example :

## To find information of an order which belongs to a particular user.

#Incorrect :
@order = Order.find(order_id)

#Correct :
@order = @user.orders.find(order_id)

Do not ignore hidden fields - a user can easily modify their value, so suspect them similar to params[:id]

Filter sensitive logs

Prevent logs of sensitive unencrypted data using #filter_parameter_logging in controller. The default behavior is to log request parameters in production as well as development environment, and you would not like logging of password, credit card number, etc.

Video Tutorial

Cross Site Reference(or Request) Forgery (CSRF)

In a CSRF attack, the attacker makes victim click on a link of his choice which would contain a GET/POST request and causes web application to take malicious action. The link could be embedded in a iframe or an img tag. Its recommended to use secret token while communicating with user to avoid this attack.

Its little complex to understand this attack. So, only those readers who are very enthusiastic to know about it, please read the Description below. Rest can directly move ahead to use the plugin.

Description :

Use Get and Post appropiately (note : Both get and post are vulnerable to CSRF)

Example - Gmail CSRF security flaw

Plugin - CSRF Killer (recommended) - it requires edge rails

Minimize session attacks

If an attacker has session-id of your user, he can create HTTP requests to access user account. An attacker can get session-id by direct access to user machine or is able to successfully run malicious scripts at user machine. In this section we will talk about how to avoid or minimize the risk if attacker has user session-id. Following steps are helpful:

  1. Store IP Address, but creates problem if user moves from one network to another.
  2. Create a new session everytime someone logs in.
  3. Expire session on user logout, user is idle for a time period or on closing of browser/tab. For maximum security expire sessions on all the three conditions.

Code for session expiry on timeout

## Timeout after inactivity of one hour.
MAX_SESSION_PERIOD = 3600
before_filter :session_expiry
def session_expiry
   reset_session if session[:expiry_time] and session[:expiry_time] < Time.now
   session[:expiry_time] = MAX_SESSION_PERIOD.seconds.from_now
   return true
end

Plugin - Session Expiration for session expiry on timeout

Do not put expiry time in the cookie unless your cookie information is properly encrypted. If not, use server side session expiry.

Persistent session / login in rails - global setting in enviornment.rb


ActionController::Base.session_options[:session_expires] = <i>say after two years</i>

Persistent session / login in rails - to give your users a feature - remember me

Stop spam on your website from DNS Blacklist

Avoid access to your website from IP addresses which are present in DNS Blacklist(DNSBL).

Plugin - DNSBL check

Caching authenticated pages

Page caching does bypass any security filters in your application. So avoid caching authenticated pages and use action or fragment caching instead.

- View -

Cross site scripting(XSS) attack

Cross Site Scripting is a technique found in web applications which allow code injection by malicious web users into the web pages viewed by other users. An attacker can steal login of your user by stealing his cookie. The most common method of attack is to place javascript code on a website that can receive the session cookie. To avoid the attack, escape HTML meta characters which will avoid execution of malicious Javascript code. Ruby on Rails has inbuilt methods like escape_html() (h()), url_encode(), sanatize(), etc to escape HTML meta characters.

Description

Can we avoid tedious use of h() in views?

Sanitize() is used to escape script tags and other malicious content other than html tags. Avoid using it ... its unsecure. Use white_list instead.

White_list plugin

Anti-spam form protection

Use Captcha or Javascript based form protection techniques to ensure only human can submit forms successfully.

When using Captcha do ensure the following :

  1. Images are rendered on webpage using send_data and are not stored at the server, because its not required to store images and are redundant.
  2. Avoid using algorithm used by standard Catpcha plugins as they can easily be hacked, instead tweak an existing algorithm or write your own.
  3. Use a Captcha which does not store secret code or images in filesystem, as you will have trouble using Captcha with multiple servers.

Tutorial - a nice article on concepts of captcha

Plugin - ReCaptcha (recommended)

Plugin - BrainBuster - a logic captcha based on simple puzzles, math and word problems. By default, it has limited set of problems and you would have to come up with large set of your own problems.

Plugin - Simple Captcha (not recommended) as it breaks all the must have features of a good Captcha implementation.

For less critical systems like blogs, a more user-friendly option can be use of CSS based technique or JavaScript based plugin unlike Captcha. Both JavaScript and CSS based techniques can only avoid spam from dumb or general bots. If an hacker specifically targets your site or bot is smart enough, you are dead, so be careful.

Captcha with Multiple Servers

Hide mailto links

Mailto links in a webpage can be attacked by e-mail harvesting bots. Use the plugin CipherMail to generate a 1024 bit random key and obfuscate the mailto link.

Plugin - CipherMail

Use password strength evaluators

A lot of people have used password strength evaluators simply because its used by google in their registration form. You can use it to help your users register with strong password. But I don't think its a must have security addon. Uptill now I have not found a good algorithm to assess strength of a password, but some of them are reasonable.

Also, if there is an open source tool or algorithm for evaluating password strength, it can easily be broken. So, you might consider tweaking the algorithm or building one from scratch.

Tools

- Miscellaneous -

Transmission of Sensitive information

Use SSL to encrypt sensitive data between transfer from client to server. SSL hits server performace, so you might consider using SSL only for few pages which transfer sensitive data to and fro.

Plugin ssl_requirement

Mongrel, rails, apache and SSL

Controller in SSL subdomain

Sample SSL code in rails

File upload

Be very careful when you allow your users to upload files and make them available for other users to download.

Description

Must read - Section 26.7 of Agile web development with rails - 2nd edition

In place file upload

3 plugins for file upload reviewed at :

Secure your setup / environment

Proper Mysql configuration

Use good passwords

Security plugins directory

Original Source http://www.quarkruby.com/2007/9/20/ruby-on-rails-security-guide

Tagged as: , , 1 Comment
5Feb/080

Reading An Excel File With Ruby

This tutorial will cover how to read (or parse) an excel file with ruby. Here's how you can do the same thing.

Installing Parseexcel

Parseexcel is a ruby port of the perl parseexcel module.

It's installable via a nice gem like so:

 

 

gem install parseexcel

That's that, now remember since it's a gem library we have to tell our script to use the gem libs when we run the script from the console using the -rubygems switch.

Using Parseexcel

Parseexcel is a very straight forward library, you can't do too much with it, but it gets the job done.

Getting a Workbook

 

 

Spreadsheet::ParseExcel.parse(filenameandpath)

This returns the actual excel file's workbook, from there we need to determine what worksheet we're on.

Getting a Worksheet

 

 

worksheet = workbook.worksheet(0)

Will return the first worksheet, you could also use the each method on the workbook to iterate over all the worksheets.

Iterating over rows and columns

The worksheet object has a very nice each method that will allow us to iterate over the rows like so

 

 

worksheet.each { |row|
j=0 i=0
if row != nil
row.each { |cell|

        if cell != nil
contents = cell.to_s('latin1')
puts "Row: #{j} Cell: #{i} #{contents}"

        end
i = i+1
    }
j = j +1
end

}

Getting Cell Data

  • Getting a String: cell.to_s('latin1')
  • Getting a Float: cell.to_s('latin1')
  • Getting a Int: cell.to_i
  • Getting a Date: cell.date

Getting A Specific Cell

 

 

cell = row.at(3) #returns cell at column 3

A basic script for dumping an excel file

 

 

require 'parseexcel'
#Open the excel file passed in from the commandline
workbook = Spreadsheet::ParseExcel.parse(ARGV[0])

#Get the first worksheet
worksheet = workbook.worksheet(0)

#cycle over every row
worksheet.each { |row|

j=0
i=0
if row != nil
#cycle over each cell in this row if it's not an empty row

row.each { |cell|
if cell != nil
#Get the contents of the cell as a string

contents = cell.to_s('latin1')
puts "Row: #{j} Cell: #{i}> #{contents}"

        end
i = i+1
}
end
}

To run the script, remember to use the -rubygems switch so that you can find the parsexcel library.

 

 

ruby -rubygems excelparse.rb myfile.xls

Tagged as: , No Comments
3Sep/070

Directory Listing in Ruby On Rails

The code displays all the subdirectories and files listed in the the main directory, and also displays these items as a link so that the following subdirectories can become the directories and diaplay the corresponding elements

IN CONTROLLER...............

DEF listing

   if (params[:dir] !=nil)      @path   = params[:path]+"/"+params[:dir]

   else      @path ="D:/Folder_name"   end

      @dirEntries = Dir.entries(@path)

      @dirEntries.reject! { |filename| filename.starts_with? '.'}

end

IN VIEWS.........<%= javascript_include_tag :defaults %>

<% for dir in @dirEntries %> <%= link_to "#{dir}", :action => 'listing', :path => @path, :dir => dir %><br/>

<% end %> 
Tagged as: , No Comments