Reset Password with Rails

The always brilliant Ryan Bates from Railscasts had a recent episode: #274 Remember Me & Reset Password

I have a slightly different way of handling password resets and thought I’d share.

Ryan walks you through adding two attributes to a User model: password_reset_token and password_reset_sent_at

I am not a fan of adding extra columns to my database tables, especially if only a few records will use it temporarily.

If you follow along with episode #250 Authentication From Scratch , you should have two columns: an encrypted password column password_hash, and the salt password_salt.

What I do differently is use ActiveSupport::MessageVerifier to create self-expiring, encrypted tokens for password resets.

I encrypt a date in the future using the user’s current hashed password as the salt.

I then append the encrypted date string to the end of the user’s id and encrypt that using the secret_token that Rails generates on app creation (in config/initializers/secret_token.rb).

In the User model, I add two methods to do this:

  def generate_token
    ActiveSupport::MessageVerifier.new(Rails.configuration.secret_token).generate([id, 1.day.from_now, password_digest])
  end

  def self.find_by_token(token)
    begin
      user_id, expiration = ActiveSupport::MessageVerifier.new(Rails.configuration.secret_token).verify(token)
      if expiration.future?
        Member.find(user_id)
      end
    rescue
      nil
    end
  end

Example:

the_user = User.first
reset_token = the_user.generate_token
# Mail reset_token to the_user

# … verify token and reset password:

if the_user = User.find_by_token(reset_token)
  # reset_token is valid, OK to change password
  the_user.password = new_password
end

Pros:

  • No extra, unused columns in your database tables.
  • An attacker needs two keys ( user’s password digest and your apps secret_token) to compromise a user account.
  • Once a password is changed on a user account, all tokens for that user are immediately invalid

Con:

  • If an attacker gains access to a copy of your users table and codebase you’ll have to regenerate your secret_token to prevent them from being able to reset *all* the user passwords

protect your servers with fail2ban

Fail2ban is server software that watches your log files for multiple failed login attempts, then uses iptables to temporarily ban the source ip address.

I’m surprised it took me this long to find this.

With apt-get, it’s as simple as:

 apt-get install fail2ban

The default configuration ( /etc/fail2ban/jail.conf ) is pretty good out of the box.

mysql memory tables and sessions

If you absolutely need to store session data in your database, don’t use memory tables to store session data, InnoDB works just fine.

If you need performance use something like memcached.

Memory tables are fast, but you’ll most likely run out of table space before enjoying any benefits.

Cache busting with Rails and Cloudfront

My colleague and I ran into a problem with deploying a Rails app that utilized a custom origin on Amazon Cloudfront.

The default Rails cache-busting technique appends a timestamp query string to the end of an asset’s source ( ex. all.css?1302137895 ), which works great in most cases but will not trigger an origin-fetch from Cloudfront, which can cause deprecated files to be served out for up to 24 hours.

There is a good work around that’s outlined in this article: CloudFront custom origin server with Rails, Jammit, and Apache, which dynamically rewrites the asset_path using the REVISION file that Capistrano creates for you when deploying.

While this technique works well, it’s not compatible with the built-in Rails action_controller caching ( combining javascript and stylesheet files into one to reduce HTTP requests )

Building off the opengovernment article, I modified the asset_path to only version the path for images:

environments/production.rb:

  config.action_controller.perform_caching = true

  REVISION = File.exists?('REVISION') ? %x{cat REVISION | cut -c -7}.rstrip : false

  config.action_controller.asset_path = proc do |asset_path|
   if asset_path =~ /^\/images\//
    "/release-#{REVISION}#{asset_path}"
   else
      asset_path
   end
  end

For the asset helper methods ( stylesheet/javascript_link_tag ) I created an application helper to include the revision number in the filename that is passed to the :cache parameter:

def cache_name(name = 'all')
  return false unless File.exists?('REVISION')
  name + '-r' + %x{cat REVISION | cut -c -7}.rstrip
end

In the application layout:

<%= stylesheet_link_tag :all, :cache => cache_name %>
<%= javascript_include_tag :all, :cache => cache_name %>

This way, all the image paths will be versioned and trigger an origin-fetch from Cloudfront immediately upon deployment.

The javascript and css files are combined into a single, versioned filename which will also trigger an origin-fetch.

I also threw in the smurf gem to automatically minify the unified css and javascript files for extra goodness.

Now, the application servers only spit out 5-8k chunks of HTML and Cloudfront handles the rest of the assets.

Your own private git remotes

As much as I am a fan of the githubs, if you only intend to host your private git repositories, you don’t need to pay them a monthly fee as long as you have SSH access to a server.

Here’s how:

Make sure you’ve initialized your project first:

git init && git add . && git commit -m 'my first commit'

Copy the .git directory over to the server:

scp -rp .git bryan@yourserver.com://path/to/repositories/myproject.git

Add the remote to your git config:

git remote add myremote ssh://server.com/path/to/repositories/myproject.git

And that’s all! You can now push your commits to your new remote:

git push myremote

This is a simple and quick solution for an individual developer looking to backup or make a project accessible from anywhere.

If anyone knows of a cool web interface for git that can work with this, leave a comment.

This should also work on small teams as long as you setup proper group permissions and umasks for the accounts on the server. That very well could be my next post ….

PC vs. Mac

Microsoft is keeping the fight going with a new webpage:

http://www.microsoft.com/windows/windows-7/compare/pc-vs-mac.aspx

First of all, Apple Computers are PCs. The title should probably be Windows vs. Mac OS X, but maybe not. This site does not actually claim Windows is better, rather why you should buy a PC instead. Let’s go through some of their points.

You can’t get a Mac that ships with a Blu-ray player, TV tuner, Memory Stick reader, or built-in 3G wireless. You can with PCs running Windows 7.

While this may be technically true, you can buy these things for Apple Computers. It is a merit of PC manufacturers, not Microsoft Windows 7.

Most of the world’s most popular computer games aren’t available for Macs. And Macs can’t connect to an Xbox 360. PCs are ready to play.

Again, this is not a technical merit for Windows, this is due only to their ubiquity. The inability to connect to Xbox 360, I would bet is because of Microsoft preventing it. More and more game developers are releasing Mac versions of their games, and with the advent of Steam for Mac, this trend will pick up very quickly.

Most Macs can’t hook up to your TV unless you buy a converter dongle. Many PCs runningWindows 7 are designed to connect directly to TVs, so you can watch movies and see photos on the big screen.

Weak and misleading statement. It all depends on the inputs available on your TV and which outputs are on your computer. All current Macs can connect to a TV that has DVI, VGA, or HDMI inputs with the right cable (not a ‘converter dongle’). Many PCs are designed to connect to TVs, and many are not.

Things just don’t work the same way on Macs if you’re used to a PC. For example, the mouse works differently. And many of the shortcuts you’re familiar with don’t work the same way on a Mac.

Why would you spend time learning how to use a superior system when you are so used to our crappy one?

Windows 7 was designed to make it simpler to do the tasks you do every day, with features that the Mac doesn’t have. For example, the new Snap feature makes it easy to view two documents side by side.

No, Macs do not have Microsoft’s Snap, and Toyota’s do not have Subaru Boxer engines. Macs do have Exposé, QuickLook, Spotlight and Cover Flow, which are much better, in my opinion, for finding and comparing documents.

Unlike Macs, many PCs running Windows 7 support Touch, so you can browse online newspapers, flick through photo albums, and shuffle files and folders—using nothing but your fingers. PCs with a fingerprint reader even let you log in with just a swipe of your finger.

Some PCs running Windows 7 support Touch. ALL Macs support Multi-touch with a trackpad (and all MacBooks have a trackpad), that does the same thing.

If you use Apple’s productivity suite, sharing files with PC users can be tricky. Your documents might not look right and your spreadsheets might not calculate correctly.

Can be tricky, might not look right, and possibly, maybe, probably not, most likely, may or may not work. I’ve had just as much, if not more trouble sharing files between Windows PCs as I have had between Mac and Windows.

You’ll have to buy a separate hardware dongle to plug your Mac into a standard VGA projector. Most PCs with Windows 7 hook up easily.

There are so many different Windows PCs on the market, how can anyone claim that ‘Most’ PCs with Windows 7 hook up easily? Some PCs have VGA adapters, some have proprietary video connectors, while some have nothing.

On a Mac, out of the box, you can only encrypt your home folder. With Windows 7 Ultimate, you can encrypt your entire hard drive and even USB drives. So your stuff can be safer wherever you go.

This is true, but why would you want to encrypt the OS X system files and applications? You really have to go out of your way (and provide an admin password) to put any of “your stuff” in places outside of your home folder anyhow.

With a Mac, it’s harder to set up secure sharing for your photos, music & movies, documents, and even printers with other computers on your home network. With HomeGroup, it’s easy to connect all the computers in your house running Windows 7.

On a Mac, you have to manually set up photo sharing, manually set up music and movie sharing, manually set up file sharing, and manually set up printer sharing. It’s easy to automatically and securely network with all the computers in your house when they’re running Windows 7.

This is very subjective. I have rarely had a problem sharing anything on my home network with Macs.

Apple’s productivity suite file formats won’t open in Microsoft Office on PCs. This can be a real hassle for Mac users sharing work documents with PC users.

If there’s a Mac version of a program you need, you’ll have to buy it again and relearn how to use it on a Mac.

Apple’s productivity suite does offer the ability to read and save files in a format that will open in Microsoft Office on PCs, or you can purchase Microsoft Office for the Mac, which I hear is actually very good. Having to buy and relearn software, again, is not a compelling reason to stay on a bad system.

Why trade up your 15 year old car for a new one? You’ll have to relearn how to work the new features, your custom seat covers and floor mats aren’t going to fit, and the new safety features and higher fuel efficiency might confuse you.

Monkey Patching in Ruby

If you, or someone you know is involved with the development of web applications, chances are that you’ve heard of Ruby on Rails. I’ve recently decided to use it for a few small projects and am simply amazed at how spectacular it is. In case you don’t know, Rails is a framework written in the Ruby programming language, for developing web applications. If that doesn’t make much sense to you, then you should probably stop reading now.

There have been other web frameworks in other programming languages that closely emulate Rails, but think a lot of the magic comes from Ruby itself.

One of the things about Ruby that I recently learned was how you can ‘re-open’ a defined class ( supposedly referred to as ‘monkey patching‘ or ‘duck punching’ )

If you had the following class defined:

class Thing
 def foo
 puts 'foo!'
 end
end

You could, later on add a method to this class, at runtime:

class Thing
 def bar
 puts 'bar!'
 end
end

The interpreter will add the ‘bar’ method to the class without error or warning. This can also be applied to Ruby’s internal base classes, the following code for example adds a method named rot13 to the String class

class String
 def rot13
 self.tr! 'A-Za-z', 'N-ZA-Mn-za-m'
 end
end

puts 'Hello world!'.rot13
=> 'Uryyb Jbeyq!'

I think this is one of the reasons why Rails plug-ins to integrate so well

This would have saved me a ton of work if PHP was able to do this.

iOS apps

Here is a short list of my favorite and most used iOS applications:

Bing

Although I’m not a huge fan of Microsoft’s operating system software, their search app has a very handy feature when you’re out shopping: Using the camera to scan a barcode, the app will find the product online, and do price comparisons.

Chase

Besides being able to check your balances and whatnot, the Chase app lets you deposit a check by photographing it with your camera.

Reeder

I can’t say enough good things about this app. It’s an RSS reader that connects to your Google Reader account, with a slick, elegant and intuitive interface.

Guitar Toolkit

This is a must-have for any guitar player. It features a tuner, a strum-able, and searchable chord library, and metronome.


iPhone4

Ok, yea, so I got caught in the Reality Distortion Field and bought a new iPhone last week. In 2007 I went from using a Sony Ericsson T-610 to an iPhone, then upgraded to a 3GS, so my comparisons and impressions are going limited to other iPhones. There are already a bunch of great reviews by better writers and tech pundits than I, so this simply my initial thoughts and feelings rather than an in-depth analysis.

The display is fantastic, it’s like watching HDTV for the first time. It’s got a nice solid hefty feeling to it. My old iPhone 3GS’ screen almost looks blurry and feels like a cheap plastic toy.

Camera takes much better shots and the LED flash works out really well in very low light. The video is a major improvement, but unless the scene is very well lit, there is some  noticeable compression artifacting going on.

Had a single Facetime call, it worked awesomely. When someone requests a Facetime chat, the front-camera turns on while it’s ringing, so you see a live video of yourself trying to figure out who is calling, which was very, very startling.

The reception problem is kind of real. I can drop a call consistently, within about 20 seconds by holding the tip of my finger on that black band on the lower left corner. This only happens at home, where my reception is normally marginal at best. I can duplicate this on the 3GS only if I wrap my entire hand around the bottom of the phone. I cannot reproduce this problem at work, with either phone.

With the rumors of a future antennae fix, and a Verizon iPhone, I considered returning the thing and waiting until the dust clears and the rumors are laid to rest. My wife, who inherited my 3GS (at least until the white iPhone 4 is available) refuses to go back to using her old phone (my old 1st generation iPhone) so it looks like I’m going to hold on to this fancy new phone for a while.

There and back again

For the longtest time, Cablevision’s Optimum was the only game in town when it came to TV, and high speed internet, then FiOS arrived and seems to be giving Cablevision a run for their money, literally.

We switched to FiOS shortly before buying our house last December, and it was an entertainment upgrade in nearly every regard. The picture quality was noticeably better, and the tuner/receiver was far more advanced. Optimum’s internet download speeds (with ‘boost’) typically varied between 20 and 30 Mb/s and around 5Mb/s upload, FiOS was able to give me a solid 25/25 Mb connection.

A few weeks ago, a charismatic young man from Cablevision rang our bell, and had some compelling arguments for switching back, so we invited him inside. He took a look at our Verizon bill and claimed he could provide the same service for less money, port our number from Vonage, install extra lines upstairs, and in the office and even pay the termination charge from Verizon all without any contract agreement. It would be around $50/month less, for pretty much the same thing. Sure, why not? We don’t watch a whole lot of television, or make many phone calls and there’s isn’t a whole lot different when it comes to internet service.

A few weeks later, the Cablevison installer comes to the house and connects the modem next to the TV, so Saturday afternoon I reconnected it into the new line he ran in the office. Sunday afternoon, both televisions stopped working. Tess calls Cablevision and they tell her that there ‘might’ an outage in the area, but she should try connecting the component cables instead of the HDMI cables and call back. Doesn’t work. I call next time and they do some kind of diagnostics and inform me that the signal strength to the box is too low, and they’ll have a service person come by before 8p that night. Great, alright. After waiting around until 8p, and not hearing anything from Cablevision, we call tofind out what’s going on. Cablevision claims that we had canceled the repair call earlier that afternoon, which was flat-out wrong. I’m pretty sure we’re switching back to FiOS as soon as we can, even if there’s a $360 termination fee.