Redirecting To Dynamic Page Using Javascript

So I recently had a consulting opportunity where the client needed to be sent to a dynamic page after a controller action in rails.  That is easy in the normal rails context, however this all had to be done in a javascript content due to it being a javascript based subscription form for sign up.  I ended up with a nice little parlor trick that is attached below.

A little background, this client used recurly to do recurring billing and recurly uses a javascript system to securely handle creditcard data.  On submit, javascript sends recurly the credit card data and they send you back a token representing the data in their system or you get back errors that you can display to the browser.

Once you have the token there are a couple ways you can approach charging it to add a subscription.  The way that I do it is by setting up a subscription/order controller in rails, that then takes care of creating the subscription through an Ajax request. That allows us to catch any errors (i.e. not enough funds) without forcing the user to re-enter any non-credit card data on the site.

Normally after a successful subscription, you will let the form continue to a subscription/registrations controller and that will take care of the setup.

In this app, there were multiple paths that the user could go based on what they order and their progress in the system. So i needed to redirect them dynamically. The way that i did that is on success instead of allowing the form to continue using javascript, i called the function below.

function redirectOrder(url){
    var plan = $('#recurly_plan_code').val();
    var form = $('<form action="' + url + '" method="get">' +
      '<input type="text" name="recurly_plan_code" value="' + plan + '" />' +
      '</form>');
    $('body').append(form);
    form.submit();
  }

Setup Phonegap on Ubuntu 14.04

Worlds succinctest guide to setting up a phone gap project.

  • -> npm install -g phonegap
  • -> npm install -g ripple-emulator
  • MAKE A PROJECT
  • CD to the project
  • -> phonegap build browser
  • ripple emulate

Then open a browser

http://localhost:4400/platforms/browser/www/index.html?enableripple=cordova-3.0.0

Thats it!  Your cordova version may be different, the important part is the URI, which is the path between / and ?

Pundit and Rolify Testing with Rails

Just ran into an oddity that I didn’t expect (due to a false assumptions) when testing permissions and wanted to send it out to the world.

I have an app with two types of roles; :admin or :user. I am using Rolify in combination with Pundit to perform the role based authorization of REST actions.

I mixin a module containing general purpose authorization classes. I do it this way because permissions schemes tend to change alot and centralization makes it easier to change. You could easily just add these to your pundit policy classes.

def is_admin?
  user.has_role?(:admin)
end

def is_user?
  user.has_role?(:user)
end

def is_allowed?
  user.has_role?(:user, record)
end

Pretty straight-forward. An administrator has the role of :admin, a user has a role of :user and a :user is only allowed to access records that they are explicitly granted permission on.

My error was the assumption that user.has_role?(:user) would return true if a user had a role of :user explicitly set on any object in the system. In a pundit action it would look something like this.

def index?
  is_admin? || is_user?
end

The problem is that this was returning false unless someone had a :user role set in general, not on a specific instance of a record.

I think code clears this up further, here is the error.

#Assign the user role of :user on a specific object instance
User.first.add_role(:user, SomeObject.first)
User.first.has_role?(:user) #= false

#Assign the user a role of :user
User.first.add_role(:user)
User.first.has_role?(:user) #= true

So i had to alter this to use see if the User had the role of :user on any object in the system.

#Old definition, broken
def is_user?
  user.has_role?(:user)
end

#New definition, fixed!
def is_user?
  SomeObject.find_roles(:user, user).any?
end

The new is_user? returns true when the user has a role of :user on any SomeObject in the system. Which is exactly what we need.

Lesson learned, I assumed that the method worked a certain way and lost several hours of debugging in my unit tests. I normally will go straight to IRB when i run into anomalies but because i strongly help my assumption I didn’t.

Rails 4.2 truncate_words method

Rails 4.2 added a new feature called truncate words. It allows you to do things like this.

"In a world where everything is awesome".truncate_words(3)
"In a world..."

I wanted to step through this method to look at a few things I found in the code. Here is the full code

def truncate_words(words_count, options = {})
  sep = options[:separator] || /\s+/
  sep = Regexp.escape(sep.to_s) unless Regexp === sep
  if self =~ /\A((?:.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
    $1 + (options[:omission] || '...')
  else
    dup
  end
end

The first thing that I noticed is that it recognizes two additional options
:separator allows you to change the thing that splits up words. For instance, you could do something like cut off the string at the third i. That would look like this.

"Once i went to india and ate ice".truncate_words(3, {separator: 'i'})
"Once i went to india and ate ..."

There is also :omission, which allows you to add something besides … at the end of the truncation.

Now that we know the options, lets look at the code.

The first two lines setup the separator that is used to count the number of words. The first line either takes it from the options hash passed in or defaults it to a space. The second line converts the separator into regular expression language by escaping it (i.e. adding 1 or more \) UNLESS the separator is already of class Regexp. I suspect the unless is so that we don’t get double escaping that isn’t handled already in the Regexp library.

sep = options[:separator] || /\s+/
sep = Regexp.escape(sep.to_s) unless Regexp === sep

Now that we have our separator Regex’ed out, we check the string for it’s match. Self is going to be some sort of string that responds to matching a regex. If it finds a match the truncate_words will return the match (which is stored in the $1 global variable) along with either the specified omission or ‘…’ at the end. If we don’t get enough matches, then the string is just duplicated out.

if self =~ /\A((?:.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
  $1 + (options[:omission] || '...')
else
  dup
end

Something I’m wondering about is why do they duplicate the string at the end if no match is found? Wouldn’t just sending out self work and not eat up a tiny bit more memory?

In my next post I analyze the regex that is used to do matching on this string.

Thoughts on my first EmberJS project

Just cooked up an EmberJS project and wanted to share some thoughts on the framework as a whole and also throw some gotchas.

1. Many things work out of the box. However, when you need to do something that is not out of the box, you will find few resources to help. Worse yet, things change so much that found resources may not.

2. Some things are shockingly easy to do. Some of those things include data validations, 2 way binding and active record (rails) integration with active model serializer.

3. Some things are shockingly hard to do. For instance, looking over a javascript object is pretty simple in javascript or jQuery. However, in ember (with handlebars) you have to convert it into an ARRAY first, then it will loop pretty easily. This surprised me because EmberJS is javascript… looping over and displaying JSON should be pretty easy.

If I had one recommendation, it is to not use templating languages or extensions like emblem. I used this during my first project. It is similar to slim or haml and makes it super easy to see how the markup will be. But the downside is that whenever you need to do something unique, you will fight with it in order to get it implemented.

Javascript frameworks look like they will be the way of the future so good luck if you get started!

Adding Nested Image Attributes to Rails 4 App using Paperclip

So have a new web application where users will be able to upload images along with a post. I haven’t used the ruby gem Paperclip from ThoughtBot since rails 3.2 (which seems like it was only a couple months ago) so I thought I would write up a post on how I got it working.

The background of the app

  • Post have many images
  • Image is polymophic and can belong to either Post or Comment

So first step is to add the gem ‘paperclip’ to your gem file and then run bundle install.

Next, configure paperclip in development/production.rb   For this app we will be doing file storage locally until it is live

config/enviornments/development.rb

Paperclip.options[:command_path] = "/usr/local/bin"

After that we need to setup our models for Image and Post. Image is polymorphically related to Post as imageable and also contains content through the paperclip gem. Post has images and can accept nested attributes for images.

app/models/image.rb

class Image < ActiveRecord::Base
  belongs_to :imageable, :polymorphic => true
  has_attached_file :content, :styles=>{:medium => "300x300>", :thumb => "100x100>"}
  validates_attachment_content_type :content, :content_type => %w(image/jpeg image/jpg image/png)
end

app/models/post.rb

class Post < ActiveRecord::Base
  belongs_to :user
  has_many :images, :as => :imageable, dependent: :destroy
  accepts_nested_attributes_for :images
end

Now that the models are good, we have to code around the strong parameters that were added in rails 4. Notice that in the private section we are adding ‘images_attributes: [:content]’ to prevent the image upload from being filtered and adding @post.images.build to the new action so that our view can render out the file tag properly.

app/controllers/posts_controller.rb

class PostsController < ApplicationController
  
  def new
    @post = Post.new
    @post.images.build
  end  

  def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: 'Post was successfully created.' }
        format.json { render action: 'show', status: :created, location: @post }
      else
        format.html { render action: 'new' }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  private
    #strong parameters
    def post_params
      params.require(:post).permit(:title, :description, images_attributes: [:content])
    end
end

Last part is the view, now that it is wired up it will just be adding a couple lines to our form. I removed the code that will spit out the errors that come through for succinctness here. Note that the upload image part has :images in fields_for which corresponds to our has_many :images in Post model and that the file_file :content corresponds to the has_attached_file :content in our Image mode.

Also, in order for the html field to accept images, make sure you add the multipart to the html.

app/views/posts/_form.html.erb

<%= form_for @post, :html => { :multipart => true } do |f| %>
  <div class="field">
    <%= f.label :title %><br>
    <%= f.text_field :title %>
  </div>
  <div class="field">
    <%= f.label :description %><br>
    <%= f.text_field :description %>
  </div>
  <div>
    Upload Image
    <%= f.fields_for :images do |ph| %>
      <%= ph.file_field :content %>
    <% end%>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

That about does it. If you put this together and it doesn’t work, restart your server and it should start singing.

Exporting Data to CSV in Ruby on Rails

So in our application we have a list of clients that our users are tracking (called trackers). One of our clients needed the ability to quickly export this data. In ruby this is super easy. We just add a few lines to our controller and model. In our controller, we already have an instance of their active trackers (@trackers_enabled )and it just grabs the trackers that are enabled.

trackers_controller.rb

respond_to do |format|
  format.html
  format.csv { send_data @trackers_enabled.to_csv}
end

This allows us to export the data by just appending .csv to the url, so to access this we just add a link in the view. In the model we just add.

tracker.rb

  
def self.to_csv(options = {})
  CSV.generate(options) do |csv|
    csv << column_names
    all.each do |row|
      csv << row.attributes.values_at(*column_names)
    end
  end
end

This is a quick solution and can be found in about 20 places around the internet, but it adds some unnecessary fields like created_at, updated_at and user_id to the csv.

To limit that data we just have to do some investigation on the column_names and see what type of data it returns in IRB.

In irb

Tracker.column_names
=>  ["id", "user_id", "address", "first_name", "last_name", "enabled", "created_at", "updated_at"]

So now we know that column names is just an array of the columns. To grab just the ones we are interested in we edit tracker.to_csv to have the columns we want or we could edit column_names to just specify the columns we want. I opted with the first because it won’t have any unintended consequences.

tracker.rb

  
def self.to_csv(options = {})
  CSV.generate(options) do |csv|
    columns = %w(first_name last_name age address description)
    csv << columns
    all.each do |row|
      csv << row.attributes.values_at(*columns)
    end
  end
end

Then in the view code you can add something like this if you are using bootstrap.

<div class="container-fluid padded">
  <%= link_to "Export #{@trackers_enabled.count} Trackers to CSV", params.merge(:format => :csv), :class => "btn btn-green" %>
</div>

Lockerware Part 2: Combatting the Threat Using Email Best Practices

In my last post I explained how lockerware was a new type of virus that encrypts a users data and gives them an option to pay a ransom to get it back. This post will be dedicated to the three options that this new persistent threat presents: ignore it, cure it or pro-actively avoid it.

I will combine ignoring and curing together because they are related and simple. Ignoring the threat can be done by just doing business as usual; continue to download all or most attachments from email, click on internet and email links without scrutiny and install random software from the internet. Following this route will surely get some form of Lockerware on your system. Once infected you can either just erase all your data and start fresh or pay several hundred or thousand dollars for the criminals to unlock your data so that you can use it.

A pro-active strategy is probably where most people want to be, however it will involve sacrificing some convenience for the extra security.

First, have a solid backup strategy in place. This strategy will be different for consumers vs businesses, however the common element is to have 3 copies of your data. The first is the data itself. The second is a backup copy that is stored onsite on a separate drive, preferably in a separate area of the building. The third is a backup copy that is stored far enough away that a local/regional disaster would not whipe out all data.

Second, be critical of the things you receive in email. Email is similar to a postcards because the sender could easily forge where it is coming from. So in email, it is trivial for a hacker to set their email as being from “Bank of America”. This trick is particularly bad because users have a tenancy to grant trust to email from respected sources like Bank of America or the FBI that they would not to other sources. This trust usually causes users to ignore the common preventative steps that I recommend at the end of this article.

Hackers also use email content to trick people. The most common method is through clickable links. People get links all the time that may say something like “watch this super cute cat video” but the truth is that the link that is sent can be programmed to say one thing but send users who clicks it to a completely different site. In English, that means that if you click cat video link, it could actually send you to a malicious website. Even worse that site could contain a virus that your phone or computer could download and run automatically.

A great real world example of these email tricks is from a friend that is paid to test banking security. During his last test he was able to hack a Bank President through email links. He was able to do this by researching the President on facebook. He discovered the the President was a member of a quilting club. Using that knowledge, he crafted an email that appeared to be from the quilting organization that had a link to a new membership information file. By clicking the seemingly trusted link, the President unintentionally put her entire organization at risk. Luckily though, it was just a drill and an opportunity to improve security.

So how do you avoid being fooled through email? Here are the guidelines that I recommend.

1. If you did not ask for or expect the file, don’t open it, ever
2. Don’t believe the return address…just because it says it is from your bank or friend does not mean that is who actually sent it
3. Even if the email is from your friend, assume that the contents are malicious and scrutinize the content
4. If you have to visit an email link, copy it to your clipboard and past it into your browser
5. If you have to download something from email, scan it with you anti-virus before opening it

By following the steps above you will avoid a good portion of the bad things that are sent through email.

Lockerware: The New Era of Viruses and Ransomware

Over the past several years we have saw the evolution of bad software that can get on people’s computers.  When these things were first created they were mostly malignant and the result of curious people that were just wanting to poke around at the internet.

Over time this type of activity has evolved into crime syndicates using software that will spy on users, send spam email, collect banking credentials and grant bad guys access to computers so that they can use it hack other computers.   The more techsavvy of you will recognize these systems as Botnets, Zombie Farms, Zues Banking Trojans and Spambots.

However, we recently experienced a game changer.   A new set of software is making criminal upwards of millions of dollars per month in a completely untraceable way.   This software is called Lockerware.  The pioneer of Lockerware is called Cryptolocker and was first detected in early 2013.  It works by using military grade security to scramble the files, documents, pictures and other data on a computer using a key, this is called encryption.  It then sends the key off of your computer and will only release the key to undo the damage if a ransom of 300-2000 so dollars is paid using untraceable virtual currency.   Users know they have it when they get a popup that says “Your files are encrypted, pay us $1000 in 96 hours or we will delete the key.”  A timer then begins to count down to zero.  If you pay the random they give you the key and you get your documents back, otherwise they are gone forever unless you had a solid backup in place.

These guys have made a TON of money.  An estimated 3% of users pay the ransom and around 12,000 new infections are reported per week ( that would amount to 360,000 dollars at 1000 per paid infection).  At hundreds of thousands of dollars in profit per week, it is probably not a surprise that a half dozen variations of Lockerware have been reported.  What you wouldn’t expect is that a 23 year old developer has recently released a $100 toolkit that people can buy that includes the code to create Lockerware.   Furthermore, the next logical step in the evolution of this type of software will be for the software to be smart enough to spread on its own across the internet.  This is the equivalent of some aweful virus like ebola becoming air-borne and WHEN it happens there will be alot of people and companies that lose access to their data.

To prepare for this upcoming evolution in virus software people have a 3 choices going forward.  They can Ignore & Cure it or Prevent it.

In my next article I will address steps that the every day computer user can take to prevent Lockerware from getting on their computers.