• CORS woes on Heroku

    ,

    After spending the past 4 hours attempting to solve what boiled down to a rather simple problem, I figure I’d better blog about it to save someone else the time and effort.

    If you’ve been leveraging Passenger’s new –nginx-config-template command line option to add CORS headers to static assets served from a Rails app hosted on Heroku, and the CORS headers recently disappeared under mysterious circumstances… read on.

    I’ve been using the method described here to add CORS headers to custom fonts served from a Heroku-hosted Rails app that’s proxied by Nginx which handles serving static files. I recently updated to Rails 4.2.2 and suddenly, my custom fonts (.woff and .woff2 files) no longer had CORS headers on them.

    After the aforementioned hours spent scratching my head, I discovered that the latest version of the sprockets gem is generating asset digests that are 64 chars in length, where previously they had been 32. Nginx’s default regexp for identifying requests for static assets assumes the digest will be 32 chars long, like so:

    # Rails asset pipeline support.
    location ~ "^/assets/.+-[0-9a-f]{32}\..+" {
      error_page 490 = @static_asset;
      error_page 491 = @dynamic_request;
      recursive_error_pages on;</code>
    
      if (-f $request_filename) {
        return 490;
      }
      if (!-f $request_filename) {
        return 491;
      }
    }
    

    Changing the regexp to recognize digests that are 64 chars in length immediately solved the problem:

    location ~ "^/assets/.+-[0-9a-f]{64}\..+" {
       ...
    }
    

    I had to laugh after something so stupid and silly cost me a good chunk of my Saturday to debug. But at least it’s working now. My statically served custom fonts have the correct CORS headers and Chrome and Firefox are happy again.


Need help?

I’m an independent software developer available for consulting, contract work, or training. Contact me if you’re interested.


  • Create a mesh network in your neighborhood

    Creating mesh networks sounds like a really cool idea. The free software released by CUWiN is supposed to make it easy to do just that. Theoretically, if enough people were doing this, I could drop my Road Runner service. I wonder how long it will take for wireless networking to become so ubiquitous that we no longer need to use ISPs?

    Hmm. Probably quite a while, come to think of it!

  • Infinite loop while configuring SVK on Mac OS X

    I attempted to install SVK on my Mac using DarwinPorts yesterday and ran into a strange problem. SVK appeared to compile just fine, but the installer eventually got to a step where it said “Configuring SVK…” and then it just froze. I could still do things on the system, but both my processor cores were maxed out. I let the computer sit there for a while, but the installer never recovered. It looked something like this:

    matt@matthew:~/ sudo port install svk
    --->  Configuring svk
    

    After hitting Ctrl-C to get out, the cores went back to normal.

    Some research on Google turned up this ticket that appeared to document exactly what was going on. According to the ticket, SVK needed the latest copy of p5-pathtools or else it would enter an infinite loop while configuring itself.

    First I uninstalled my current copy of p5-pathtools with:

    sudo port uninstall p5-pathtools

    I also cleaned up any leftover files from p5-pathtools and the previous attempt to install SVK:

    sudo port clean svk
    sudo port clean p5-pathtools
    

    I then installed a new copy of p5-pathtools, making sure to pass the -f flag to force an overwrite of any existing files:

    sudo port install -f p5-pathtools

    Finally, I ran the SVK install again, passing the -f flag just in case:

    sudo port install -f svk

    It worked this time. The configuration proceeded normally and finishing within about a minute. I was then able to access the SVK tool from the command line without any difficulty.

    Update: I recently purchased a MacBook and discovered that following the steps above did not fully solve the infinite loop problem for me. I also had to configure CPAN for my system, after which the SVK installation proceeded normally. This is something to keep in mind if the procedure above doesn’t work for you.

  • Using protected attributes in your Rails models

    Let’s say we’ve created a simple profile page to allow our users to update their e-mail address, locale, time zone, and various other settings. This profile page exposes only those model attributes that we want the user to be able to update. Other attributes on the model should not be updateable by the user.

    We opt to surface the updateable attributes on the profile page and assume that the user won’t be able to update the remaining attributes since they won’t even appear on the page. But does that really provide enough protection?

    Our model and database schema are defined as follows:

    class User < ActiveRecord::Base
    end
    
    create_table :user |t|
      t.column :username, :string  t.column :password, :string
      t.column :fname, :string
      t.column :lname, :string
      t.column :email, :string
      t.column :permission, :string
    end
    

    Our model can store a username, password, first and last name, e-mail address, and permission level. The permission level is used to determine what the user is allowed to do on the site. A permission level might be "Moderator" or "Admin."

    Our profile form surfaces the attributes that we want to be updateable:

    <%= start_form_tag %>
      <%= text_field :user, :fname %> First Name
    <%= text_field :user, :lname %> Last Name
    <%= text_field :user, :email %> E-mail Address
    <%= submit_tag %> <%= end_form_tag %>

    It's obvious that we only want the user to update his first and last name and e-mail address. Now let's examine the action being called when we submit the profile form:

    def update
      @user = User.find(params[:id])
      if @user.update_attributes(params[:user])
        redirect_to :action => "success"
      end
    end
    

    Our action looks up a user, updates its attributes with the new values passed on the request, and redirects to a new action if the update was successful. Simple enough, yet the code above could allow a malicious user to update the permission level of his account... something we certainly don't want him doing! Assuming the action is not protected against GET requests, we could simply visit the following URL in our browser to give the user a different permission level:

    http://localhost:3000/user/update/1?user[permission]=Admin
    

    Protecting the action against GET requests would prevent the attack from occuring via a URL, but the attacker could easily generate a POST request through other means. Rails provides a way to protect against such attacks: the #attr_protected class method:

    class User < ActiveRecord::Base
      attr_protected :permission
    end
    

    Now if we attempt our attack again, the permission level simply doesn't get updated. The other attributes sent on the request are assigned correctly, but the permission level isn't. Why not?

    It turns out that #attr_protected makes it impossible to update the permission attribute through the #update_attributes method (or any other mass assignment method for that matter). The only way we can update the permission level now is by using single-assignment techniques such as:

    @user.update_attribute(:permission, "Admin")
    

    It's generally a good idea to protect attributes that could cause a security breach in your system. These might include usernames, passwords, software keys, and even product prices. While by no means a silver bullet, #attr_protected is still a good tool to use as you begin locking down sensitive parts of your application.

    #attr_protected accepts multiple attributes so we could rewrite our model again as:

    class User < ActiveRecord::Base
      attr_protected :username, :password, :permission
    end
    

    #attr_protected also has a more conservative cousin, #attr_accessible. It renders all attributes on the model unavailable for mass assignment unless they are specifically named. This differs from #attr_protected which lets you start in an "all-open" state and only restrict attributes as necessary. Both methods are handy to have in your toolbox.

  • I’ve made the switch (to an iMac)

    I’ve been a PC user my whole life. That all changed two weeks ago when I purchased my first Mac. Most of my friends who are software developers had already switched so I figured I’d better go forward with the grand experiment now rather than later. I haven’t looked back since.

    The model I purchased was an iMac 20″ with the Intel Core Duo processor, 2 GB of RAM, and the 256 MB Radeon video card. It’s zippy. The UI is quite responsive. I can have dozens of apps open at the same time without an appreciable slowdown, and the video editing capabilities of this little beauty have been quite impressive. The main reason I switched was because my friends were reporting a marked increase in their effeciency while using a Mac. I’m happy to report that they were 100% correct. Here are some of the reasons why I like my Mac:

    Everything can be automated. Tasks that used to take several steps in Windows can now be performed with a single click. Apps like Quicksilver make it dead simple to launch an app, perform a numeric calculation, or switch to the next song in my iTunes playlist… all with a couple of keystrokes.

    The UNIX command line rocks. The Windows command line is best described as “castrated.” There is just no comparison between it and a standard UNIX command line. Even something as simple as being able to directly execute Ruby scripts without manually calling the interpreter becomes a benefit when it’s repeated dozens of times per day.

    Tests run FAST. A typical stack of Rails tests takes about a minute to finish on my Windows box. Under OS X, the same tests take 15 seconds or so, and most of this is startup time.

    Editing videos and burning them to DVD actually works. I experimented with several different software packages on my PC and two different DVD burners, none of which gave me the results I wanted. Capturing from my VCR left minor glitches in the video when a background process was running. On my Mac, the screen saver is automatically disabled when capturing video and the Core Duo processor removes the negative effects of background processes.

    The Apple Remote. A very clever addition to the iMac is the Apple Remote, which lets me control the system at a distance. I don’t need to head downstairs to use the TV and DVD player anymore. I can just scoot my chair back and bring up a movie in Front Row.

    Nice touches. As you’ve undoubtedly heard from other Mac owners, it’s the nice little touches that count. The magnetic holder for the Apple Remote. The blinking white sleep light on the front of the bezel. The built-in mini-DVI port. The simplicity of the System Preferences pane. It all combines to make for a computing experience so much more pleasant than it used to be.

    All is not peachy keen, though. I’ve had the iMovie editing software crash on me a couple of times. I’m not sure why this happened, but the good news is it didn’t take down the rest of the system like it might have on Windows. Also, software for the Mac is quite pricey, as is hardware. You’ll definitely pay a premium for an Apple system, but if you stick with craigslist and eBay you might get away with paying much less than retail.

    In summary, I feel much more effecient on this Mac and so I think the purchase was well worth the price. This little beauty makes computing FUN again! I really suffered while I was on Thanksgiving vacation since I didn’t have my Mac around. If you’ve been thinking of making the switch to a Mac yourself, I encourage you to give it a try. You can always sell the system if it doesn’t work out for you. My bet is you won’t.