jBoxer

I change the directions of small pieces of metal for a living.

BostInnovation’s Seth Priebatsch Article is Childish Garbage

| Comments

Disclaimer: I was SCVNGR’s lead iOS developer for almost two years. I started a new job at GitHub last month. This is neither a critique nor a defense of the actions or words of Seth Priebatsch or SCVNGR.

Today, BostInnovation published an article called Seth Priebatsch Thinks Everyone at BostInno is Painfully Stupid… Really?. In it, they publish an internal SCVNGR email in which Seth insults them, then spend the rest of the article defending themselves from his insults and offering him advice on how to have fun and run a company.

Like most media outlets, I have mixed feelings about BostInnovation. The article in question, however, is childish garbage.

The are some points to be made here that anyone who is techy enough to read BostInnovation knows. There’s no way to prove this email is real. There’s no way to prove that the “leaker” didn’t tweak it. But those aren’t the important part.

The important part is, this was an internal email. Were it not for BostInnovation, under 100 people would’ve read it, all of whom work for SCVNGR. This email was no threat to BostInnovation’s readership. This is reminiscent of elementary school kids intercepting a passed note and reading it out loud to all their friends.

If the focus of this article was “Seth is lying to the media and investors,” that would be a different story (and would require significantly more evidence). I would still be a bit off-put by the publishing of an internal email in a private company, but at least that would be news worth reading. Instead, the focus is “CEO of company thinks we’re dumb, so here’s why he’s weird and mean.” If I were an advertiser on BostInnovation, I would be pretty upset with this.

Bash’s PS1 Syntax: The Inspiration for Brainfuck?

| Comments

I just spent way too much time struggling to get my Bash PS1 variable working right. Originally, it looked like this (parse_git_branch is a Bash function I have defined elsewhere):

Old PS1
1
PS1="\w\e[35m\$(parse_git_branch)\e[m > "

Now, it looks like this:

New PS1
1
PS1="\w\[\e[35m\]\$(parse_git_branch)\[\e[m\] > "

The difference? I wasn’t escaping my color codes correctly, which was causing Terminal to wrap long commands onto the beginning of the same line.

Let me break down Bash’s color code syntax, because it makes me so angry. A minimal Bash color code looks like this:

Minimal Bash color code
1
\e[1;30m

\e[ means “here comes a color code” I guess.

1 means “make it bold”. If you don’t want bold, leave it out.

; means “I’m finished telling you that this is bold”. If you don’t want bold, or if you want default-colored text (explained below), leave it out.

30 means “dark gray”. Here’s an exhaustive list of valid numbers (no number means default color):

  • 30 = dark gray
  • 31 = red
  • 32 = green
  • 33 = yellow
  • 34 = blue
  • 35 = purple
  • 36 = turquoise
  • 37 = light gray

0-29 don’t do anything (at least in Terminal.app on OS X 10.7.2). No idea why they start at 30.

m means “my color code is over”.

If you match that format, all subsequent characters will be that color (until you define another color code).

But that’s not all! This sequence is escaped incorrectly. If you have it in your PS1, Terminal will look correct on startup, but if you type a long command that wraps past the first line, Terminal will wrap it back to the beginning of the line you’re on and start overwriting characters.

I bet you think the fix is to match the open square bracket with a closed one, right? If so, give yourself a half pat on the back, then punch yourself in the face. Here’s how to escape it correctly.

How to escape a Bash color code
1
2
\e[1;30m     # Wrong
\[\e[1:30m\] # Right

You need to close match the open bracket (with an escaped close bracket), but also add another open (escaped) bracket to the front, also with no closer.

Anyone wanna educate me on the reason for all this madness? Right now, it just feels like some dude thought regular expression and strftime syntax were too verbose.

Using acts_as_list in a polymorphic scope

| Comments

If you’re using acts_as_list in a polymorphic scope, you need to define the scope a little bit differently to make everything work right.

Here’s the non-polymorphic example from acts_as_list’s README:

acts_as_list in a normal (non-polymorphic) scope
1
2
3
4
class TodoItem < ActiveRecord::Base
  belongs_to :todo_list
  acts_as_list scope: :todo_list # Note the single-item scope
end

We pass :todo_list as the scope (which acts_as_list converts to the todo_list_id column).

Now, let’s say we’re making a polymorphic Picture model (like in the Polymorphic Associations section of the Ruby on Rails Guides), and we want pictures to be sortable and reorderable. Here’s the right way to do it:

acts_as_list in a polymorphic scope (the RIGHT way)
1
2
3
4
class Picture < ActiveRecord::Base
  belongs_to :imageable, polymorphic: true
  acts_as_list scope: [:imageable_id, :imageable_type]
end

My pre-ARC Objective-C memory management conventions

| Comments

iOS 5 is coming soon, and introduces ARC. ARC will make Objective-C memory management significantly simpler. But, it will be a long time before iOS 5 is ubiquitous, and I’m not sold on the subset of ARC that will be available for iOS 4. So, in the meantime, I thought people might benefit from seeing the conventions I use to keep Objective-C memory management simple. Most iOS developers probably already follow something close to this, but it doesn’t hurt to have it written out.

If you follow these five simple rules, you should pretty much never get a memory leak or a crash from over-releasing.


1. Always declare @properties for your object instance variables

If you’re putting an instance variable on a class and it’s an object, declare a property for it.

Moving to Octopress

| Comments

I’m now moving all my stuff from Media Temple and Tumblr to here. All posts before this one are reposts.

My tips for an awesome WWDC

| Comments

I’ve seen a bunch of people who just got back from WWDC posting advice on how to have the best time possible. I figured I should do the same thing. Here are my tips.

Don’t get in the keynote line early

Even if you want to sit near the front, you don’t need to get in line until around 8:30am. It’s really easy to just run and push past all the submissive nerds and get an awesome seat.

Live-blog the keynote

People who aren’t at the keynote would much rather read you repeating Steve Jobs’ announcements sentence-by-sentence on Twitter than watch a live feed with pictures. Also, other people in the audience who are following you will love reliving the moment when they look through their tweets later on.

Complain about the food

You paid a lot of money for tickets, which entitles you to demand customized gourmet meals. Food should be the main concern at any tech conference, and if you aren’t absolutely overjoyed by what you’re putting in your mouth, you aren’t getting your money’s worth.

Don’t silence your phone before a session begins

I know they ask you to before every session (and you should roll your eyes and say “do they have to say this every time?” when they do), but they’re really just forced to say that by law. In reality, all the speakers helped make these devices, and it’ll make them proud to see you using them. In fact, feel free to quietly answer your phone right in the middle of a talk. No one will notice.

Code during sessions

There are very few places in the world where you will have the opportunity to write code. A conference that you paid $1600 to attend is one of these places, and you should take advantage of that. Besides, you can just watch the session videos later.

Don’t go to any parties afterwards

You’re probably better at programming than the other attendees. Meeting them is pointless, and won’t be fun (and all the parties charge lots of money for alcohol, especially at Apple’s beer bash). Also, your hotel room is another one of the aforementioned few places in the world where you can code, so you should stay there and do that instead.

These tips will guarantee you a quality WWDC 2012. Also, don’t read any other WWDC tip posts, they’re probably trying to troll you.

The misguided priorities of Twitter

| Comments

Today, Twitter announced (with some awesome spin) that they would hamstring the direct message capabilities of all 3rd-party Twitter apps.

It’s been clear for awhile that one of Twitter’s monetization strategies is to force everyone to use their mobile apps over those of third-parties. This will let them show promoted trending topics in the newly-neutered Dickbar to all mobile users. I understand that Twitter needs to find a way to make money, but this direction strikes me as extremely misguided.

I believe this lock-in strategy will never create enough revenue to cover a non-trivial portion of their operating costs (never mind the $10 billion they turned down from Google). In the meantime, it will alienate the developers who were once the lifeblood of the Twitter ecosystem. Without these developers, the 3rd party apps that Twitter does want (cool aggregations, visualizations, etc.) will not be built, and new developer-fueled uses of the service will not be able to thrive.

It seems to me that the folks making business decisions at Twitter are severely underestimating the importance of certain parts of the community, and/or severely overestimating the potential revenue from their own mobile apps.

How to reset/revert a single file with Git

| Comments

I’m making this post more for my own reference than to help anyone else, but feel free to comment if you have questions or anything.

If you’ve made a commit with git (let’s call it “commit A”), and you want to make another commit (let’s call it “commit B”) that, among other things, reverts the changes made to a single file (let’s call it file1.rb) in commit A, use the following command:

git reset commit-a -- path/to/file1.rb

That’ll create two sets of changes: a copy of the changes you made in commit A, and the inverse of the changes you made in commit A. The inverse is staged, while the copy is unstaged. Nine times out of ten, you’ll want to commit the staged changes (which, as they’re the inverse of the changes in commit A, will result in a revert of file1) and discard the unstaged ones.

My Doorbell Is Better Than Your “Please Rob Me”

| Comments

“Hey man, I know you really like Foursquare, but you should check out this new site called Please Rob Me. Foursquare is actually really dangerous, cuz now it’s easy for robbers to know when you’re not at your house!”

I’m a Foursquare user, and I’ve heard variations of this from over a dozen of my friends in the past 24 hours. For the record, I think “Please Rob Me” is a really funny and creative idea, and I love that they made it. However, anyone who is legitimately giving privacy/security advice over this is being ridiculous.

First of all, most people are out of the house from 9am to 5pm. Robbers know this, and Foursquare checkins don’t change it.

Second, there’s absolutely zero indication of whether or not anyone else is home, or how soon you’ll be getting back. These are much more crucial pieces of knowledge than “a single person was not in his house at this time”.

Last, and most important, a superior technology has existed for decades: the doorbell. Run around a neighborhood ringing doorbells of houses that look like they might be vacated, and break into the ones that no one answers.

“Oh but people don’t answer their doorbell every time, so a robber might break into an occupied house!”

Right. Just like people don’t have to actually be at a place to check into it on Foursquare, and like how checking in on Foursquare doesn’t mean no one else is home. There are potential false positives with both methods (and if there weren’t, people would be getting robbed a lot more). The point is, breaking in based on doorbell-ringing is much less dangerous than doing it based on Foursquare checkins, as it’s reasonably likely that no one is home if no one answers the doorbell

In reality, privacy via anonymity has always been a pretty shaky concept. Yes, checking into Foursquare does give robbers one more tool to make their job easier, but in the face of much better tools (like the doorbell), it’s negligible. If you chose to be a Foursquare user in the first place, Please Rob Me should have no impact on your decision.

The importance of attr_accessible in Ruby on Rails

| Comments

I’m sure this has been written about ad nauseum, but I spent some time yesterday explaining it to someone who didn’t understand, and now I feel like writing it up a bit more formally.

What is attr_accessible?

In Ruby on Rails, attr_accessible allows you to specify which attributes of a model can be altered via mass-assignment (most notably by update_attributes(attrs) and new(attrs)). Any attribute names you pass as parameters will be alterable via mass-assignment, and all others won’t be.

How does mass-assignment work normally?

By default, mass-assignment methods accept a hash of attribute values, each keyed by their associated attribute’s name. If I ran the following code:

1
User.new({ :name => 'Harry Potter', :email => 'hp@hogwarts.com' })

A new instance of the User model would be created, and the name and email attributes would be set accordingly. It can also be used to alter related models. For example:

1
2
3
4
User.new({
  :name => 'Albus Dumbledore',
  :is_teacher => true,
  :course_ids => [1, 2, 3] })

In addition to creating a user with the appropriate attributes, this will update the specified courses to be owned by this user(assuming a user has_many courses in our app).

How can this be abused?

Very easily. What if someone did this:

1
User.new({ :name => 'Draco Malfoy', :is_teacher => true })

This Draco Malfoy fellow may not actually be a teacher, but the system is none the wiser. Of course, the developer would never code this; in a real Rails app, the code is going to look like this:

1
User.new(params[:user])

The elements in params[:user] are taken from the POST/GET/PUT data passed along when the action was run. They’re thrown blindly into the mass-assignment, and any attributes whose names match the keys will be set.

“So what’s the big deal? Just don’t include an ‘is_teacher’ field in the web form, and the param won’t be there.” This is true for innocent users, but the malicious ones (and Draco Malfoy is definitely a malicious one) have an easy way around this. A web form is just a way to make it easy for users to pass data to your app. There are other ways. For example, if I wanted to register for the app via the command line instead of a browser, I could do it like this:

1
2
curl -d "user[name]=Harry Potter&user[email]=hp@hp.com" \
    http://myapp.com/users/

This sends a request to http://myapp.com/users/ and passes data in the exact format it would’ve appeared if I’d filled out a web form that asked for a name and email address. However, I could also do this:

1
2
3
curl -d \
    "user[name]=Draco Malfoy&user[email]=m@hp.com&user[is_teacher]=1" \
    http://myapp.com/users/

Since is_teacher is an attribute name in my User model, and mass-assignment methods blindly accept whatever attributes they see, Draco Malfoy has just set himself a teacher.

Even worse, I could use this to grab courses that may not be mine.

1
2
3
curl -d \
    "user[name]=Draco Malfoy&user[course_ids]=1&user[course_ids]=2" \
    http://myapp.com/users/

Draco Malfoy has now taken courses 1 and 2 away from whoever they originally belonged to (Dumbledore, if my memory serves me) and given them to himself.

How can we prevent this?

There are a few obvious but clumsy ways. We could skip mass assignment, setting each individual attribute in our controller, but this will introduce a lot of duplicate and unnecessary code. We could explicitly pull unwanted parameters out:

1
2
params.delete(:is_teacher)
params.delete(:course_ids)

This also introduces a lot of duplicate code. If we ever add new columns that we want to restrict, or decide we want to unrestrict a column, we’re going to have to go through the create and update actions, and any others that perform mass assignment.

We could factor these out into some sort of sanitize_params method on each model. This is a better solution, but you still have to call it in every action that alters the data. It’s definitely not as good as the built-in one: attr_accessible. We can add this to the top of the User model:

1
attr_accessible :name, :email

This white-lists name and email; these two attributes will be accepted from a mass-assignment method, while all others will be ignored. This is by far the safest way to do it; only attributes you’ve explicitly allowed (which hopefully means you’ve thought carefully about them) can be set by mass-assignment. This way, if some intern comes along and adds a bunch of dangerous columns or relations (payment_accepted or horcruxes, for example), no one has to think about updating the sanitize methods.

What does this not do?

I saw one person say “Why would I put anything in attr_accessible? Why would I want any of my attributes to be hackable?”

Make no mistake: attr_accessible is no substitution for proper access control. If all users have write access to all other users, attr_accessible will let one user change another’s name attribute if it’s specified. Regular authentication and access control must be used to prevent users from writing to model instances that they shouldn’t be able to write to. Once this is done correctly, attr_accessible can be used to prevent a malicious user from altering data of her own that she shouldn’t be able to alter.

To be more clear, it could be considered “hacking” if a user were able to change everyone’s name to “Voldemort”. attr_accessible can’t prevent this; you need to do proper authentication with something like Authlogic. Once you’ve set your controllers up to prevent a user from even attempting to change another user’s data, you’ve prevented this “hack”.

If the user tries to change his own name to “Voldemort”, that’s totally fine. We don’t care if he does it via the web app, curl, or anything else; users are allowed to change their own name. Including :name in attr_accessible isn’t making it “hackable”, because it’s an attribute that users should be able to change.

If the user tries to change his is_teacher attribute from false to true, that’s also considered “hacking”. We don’t want to let users do this, so we exclude :is_teacher from attr_accessible to prevent it.

Are attributes excluded from attr_accessible immutable?

No. They can still be altered, just not via mass-assignment. If I exclude is_teacher from attr_accessible, and I go:

1
2
3
hagrid = User.first(:conditions => { :name => 'Rubeus Hagrid' })
hagrid.is_teacher = true
hagrid.save

That will work just fine. The difference is, it forces you to set the attribute explicitly, so there’s no potential of accidentally setting an attribute unexpectedly passed to mass-assignment. This way, I can allow my non-dangerous attributes to be set via mass-assignment with attr_accessible, then explicitly provide or deny control over dangerous attributes in other actions.