Spark Me Up

So for the second year in a row, I spent the first half of March in Portland, Oregon, USA, for EmberConf. The PN gang and I met Jeff Eiden of Spark, who gifted me with a Spark Core dev kit.

This little device is super cool. It takes 5VDC from a USB, and gives you both analog and digital in/out. It’s like an Arduino, but wi-fi connected, cloud-manageable, and API-interactable. All in this tiny little package… did I mention that you configure it without ever connecting anything USB except for power? Even on a WPA-passworded wifi network?

So the first thing I did (over lunch at EmberConf) was to make der blinkenlights: syncing the Core with the network, claiming it with the cloud web admin tools, and writing and uploading a program ALL WITHOUT EVER TOUCHING THE CORE. Seriously, this is cool. Painfully cool.

Anyway, it sat for the past few weeks until I thought of a project to do with it.

Lockify

I’ve had a Morning Industry deadbolt on one of my doors for a while now. It’s great when I rent my place on Airbnb, because I can have a guest choose a code before they come and they won’t need a key.

Last weekend I was doing a spring cleaning and I found an old RF remote that I bought with the lock: one of these little guys that looks like a keychain garage remote:

91yueI+DuhL._SL1500_

It can be paired with the deadbolt to lock and unlock it from the remote. That’s not useful to me, so I figured I could h4x0r this remote, connect it to a Spark Core, and use it to lock and unlock the door from a computer, phone, or tablet. Yep!

My friend and fellow Hacklabber Alex is a far more accomplished home automation hacker than I am. He has similar locks and can control them over Insteon. He uses a Morning Industry device that does the same thing I wanted to do. (I admire a company who will release a product that is basically a total hack.) Alex let me pop off the cover on the remote to figure out which switch connections did what:

2015-04-11 16.47.23 2015-04-11 16.47.35

… so I soldered the same number of wires to the same places on my own remote, choosing different colours so it would be easier to follow:

2015-04-11 17.26.51

 

Then I came home and quickly figured out that I didn’t need all of those wires. (I didn’t need the green or the blue wire: turns out they were there because Morning’s solution to controlling two buttons was to have each button connected to its own Insteon bridge.) To power the remote, I needed to connect red to a +5VDC source and black to ground. If I supply current to the orange and yellow wires (even the 3.3V out on the spark’s digital pins is fine), it’s like pressing the button on the remote.

Since I wanted to do this on a prototyping board and not have lots of wires, I stopped by Creatron, our local nerdshop, and grabbed a both USB port and a barrel connector that I could use to power it. (I have them both on the board in the photo, but I’m only using the USB now because that’s the cable I have handy.)

How to do it

So now I have everything I need:

  1. Spark Core
  2. Prototyping board
  3. Prototyping-mountable USB port (or barrel connector; your choice, but not both if you wire it up the way I have!)
  4. Morning Industry RF remote with wires soldered as pictured above (green/blue unnecessary)
  5. Wire for patching

What I did:

  1. Place the Spark in the centre of the bread board so all of its pins are in one of the center rows.
  2. Get power to the board, Option A: Place the barrel connector into the side rails for + and – power (taking care to match up the + and – on the board and on the connector).
  3. Get Power to the board, Option B: place the USB port into four of the centre rows that are NOT shared with the Spark Core. Connect a short red wire from the USB pin labelled VBUS (or +5V or something) to the + row in the power rail, and a short black wire from the USB pin labelled GND to the – row in the power rail. (Or if you have a USB connector that lets you connect directly to the +/- power rails, do that.)
  4. Connect the red wire from the remote into the + power rail.
  5. Connect the black wire from the remote into the – power rail.
  6. Connect the VIN port on the Spark Core to the + power rail with a red wire.
  7. Connect the GND port on the Spark Core to the – power rail with a red wire.
  8. Connect the orange wire from the remote to port D2 on the Core.
  9. Connect the yellow wire from the remote to port D3 on the Core.
  10. Double-check your connections. Here’s my picture again. I think the colours should make it clear. Remember, you only need the USB port OR the barrel connector, not both.

2015-04-13 15.07.52

Then I uploaded this code to the Core, powered it all on, and it worked! Here is the dashboard I wrote using Dashing, a nice little Sinatra/batman.js Ruby/Javascript dashboard framework from Shopify. [Github repo for Roombot, my dashboard.] With it, I can receive click/touch events and can lock and unlock the door from anywhere within wifi range. (The other cards in the bottom row are TTC arrival times, and the image off the screen is one of my security cams.)

Screenshot 2015-04-15 13.59.07

All in all, a fun, fast little project.

I really like this little Core. A remotely-manageable, wifi-connected computer with digital and analog in/out pins? For that price… wow. I see more projects (and more Cores) in my future.

Logging Out of a Rails App That Uses session_store = :cookie_store

TL;DR

If you want to be able to destroy a Rails session_store = :cookie_store session from the client, you have to tell Rails not to use an HttpOnly cookie. In Rails 4, add this to your config/initializers/session_store.rb:

YourApp::Application.config.session_store :cookie_store, key: 'your_key_name', httponly: false

…and then destroy the session cookie in JavaScript, e.g.,

deleteCookie = function(name) { document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC"; }

deleteCookie('your_key_name');

TL;RA:

So we’ve been dealing with this problem for about a year now. Our application’s back-end REST API is written in Ruby on Rails, with Devise as our authentication mechanism, and our user-facing EmberJS (Javascript) apps consume the API.

We have been using the Rails :cookie_store, which lets you store all of the session data in an encrypted cookie. The good news about this is that you don’t have to make a database request for the session data every time the user makes a call; the bad news is that it’s very hard to log out, because the only way to destroy the session data is by sending an update from the server itself. In fact this is a widely recognized issue; for more information you can see this blog post.

Now, what we really should do is switch to something like a Redis store or the built-in :active_record_store, just like that blog post recommends. We actually did that in our app, but we experienced problems with users being asked to log in over and over again. Session persistence was an issue, so we had to make a (very Agile) decision to switch back to something that worked. While switching back to a :cookie_store means they users don’t have to log in again and again, it also means that they can’t log out. And we have extra complexity because we have a special Rails controller that handles launching into multiple apps based on user permissions. It’s going to need to be re-written at some point, but in the meantime we needed a fix.

Here’s the background: Rails uses a session cookie with the HttpOnly flag set. HttpOnly is a security feature that means a client (e.g. with Javascript) cannot directly update the contents of a cookie; updates can only come from the server. So you’d think it would be easy to destroy a cookie in Javascript and get around this whole problem of not being able to log out (because deleting the session cookie definitely logs you out). Except we can’t do that because of HttpOnly. Javascript can simply not write to an HttpOnly cookie. This is generally A Good Thing for security, so it’s hard to criticize Rails for making this choice (though I’m sure that won’t stop people from criticizing anyway). There was some discussion about using expiring cookies, etc., for cookie stores at https://github.com/rails/rails/pull/11168, but this comment from the pull request’s author is very telling:

Giving up. The inheritance and mixins approach in the chained and legacy cookie jar code is absurd beyond my patience.

Someone else is free to run with this code as a start and take the credit.

The proper solution is to use something like the :active_record_store or a :redis_store, where your authentication and authorization can just destroy the session in the database or Redis store. Maybe you’re in the situation we are, though, where that isn’t feasible. Well, I has solution.

The good news is that you can tell Rails not to make cookies HttpOnly, and it requires a single change in your initializer. You just need to add httponly: false to the session_store initializer. In Rails 4, add this to your config/initializers/session_store.rb:

YourApp::Application.config.session_store :cookie_store, key: 'your_key_name', httponly: false

Of course, you’ll have to manually destroy the cookie in the browser, or use something like Devise to sign out all users so they can pick up the new non-HttpOnly key. Once you do that, though, you can use any number of Javascript libraries to fiddle with cookies. There are several good ones, but I just wrote a little helper because all I needed to do was delete a cookie, and I didn’t want to import an entirely new library for a function I could write in one line:

deleteCookie = function(name) { document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC"; }

deleteCookie('your_key_name');

Well, mine is in CoffeeScript:

deleteCookie = (name) -> document.cookie = "#{name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC";

Now, when the user logs out, the Javascript app sends a request to the Rails API to log them out, and once the Ajax callback is complete, I destroy the session cookie. Now when the app tries to redirect them to another page, their session cookie is missing, so Rails no longer knows who they are and sends them to the Devise sign in page. Here’s the CoffeeScript we’re using (I would apologize for it, but I love CoffeeScript) that removes the auth token we keep in localStorage and nukes the cookie:

deleteCookie: (name) -> document.cookie = "#{name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC";

_clearSession: ->
  @deleteCookie appSessionCookieName
  localStorage.removeItem('token_name')
  App.set 'token_name', undefined
 
 _redirectToSignin: ->
 window.location.href = '/users/sign_in'
 
actions:
    logout: ->
      Ember.$.ajax('/users/sign_out', { type: 'DELETE' }).then =>
      @_clearSession()
      @_redirectToSignin()

This was a frustrating problem with a simple solution. Keep in mind that you probably shouldn’t be using cookie stores anyway, but if you do, this is a quick fix for log out.