Sunday, March 22, 2015

Implementing "run on login" for your (node-webkit) app in OS X




I spent a good chunk of today trying to figure out how to implement a "run on login" option for my pet project, sleep.  It's a little node-webkit application with a toolbar/statusbar tray icon UI which attempts to answer the age-old question of "ugh, when did I fall asleep last night?" by telling you when your MacBook went to sleep, presumably because you closed the lid, or because it was idle for a while.  As a person who often finds myself waking up with my face planted in my laptop or with my laptop on my chest, lid closed, this is handy for determining whether or not I got enough sleep the night before.

A quick Google search reveals some ways to achieve this with the Cocoa framework.  One of the answers to a StackOverflow thread (incidentally authored by the then-lead-developer of Growl) talks about using the LSSharedFileList API.

Not wishing to wrap a Cocoa API, I found an easier solution: using launchd / launchctl.  It turns out, you can easily create a launchd LaunchAgent which will run your app when the user logs in.  I was pleasantly surprised that launch jobs can be created by a user, rather than requiring root.  I haven't run into any permissions issues yet.

our gameplan

On a high level, here's our approach:

  1. Write a simple launchd job, which comes in the form of a .plist (XML) file. 
  2. Then, run some command line arguments to move it to ~/Library/LaunchAgents/, and use launchctl to "load" the job.  
  3. (optionally) We can easily disable the job by running `launchctl unload` at a later point.  
  4. (optionally) We can also check to see if our job is currently active by doing `launchctl list` and grep-ing our job name (technically, we see if it's "loaded", which doesn't necessarily mean it's not disabled, but for our purposes).

let's write some XML (it won't hurt, I promise)

It's always lovely to find a website dedicated to explaining and documenting things for developers like strftime.org, a site dedicated simply to presenting a table of Python's strftime placeholders. I was thrilled to come across this super helpful guide to launchd.  Skimming through quickly, we learn what launchd is, what a daemon and agent are, and that all we need is a file as simple as this:


defining a launchd job

First, we need to give our job a label.  According to the guide, the convention is to use reverse domain notation, so I'm using "com.capablemonkey.sleepApp".   I've chosen my handle as the 'vendor' name which typically follows the domain ('com' in this case).  sleepApp is the name of my application.

Next, we'll describe the program to be run.  In my case, I want to run a .app package, so I'll be using the nifty `open` OS X command which knows how to execute .app packages.  To set this in our config file, we'll specify a new field called ProgramArguments which is an array of strings: the command/program, followed by any arguments.  The last argument is the location of the .app package: /Applications/sleep.app.

Lastly, we'll include the RunAtLoad flag which will cause the job to be "run" when it's "loaded" (a job can be loaded, but not run immediately).

putting things in motion

'enabling' the job

Now that we've described the job, we need to place the file in ~/Library/LaunchAgents in order for the job to be run when the user logs in:

cp com.capablemonkey.sleepApp.plist ~/Library/LaunchAgents/

Then, we'll ask launchctl to load the job:

launchctl load ~/Library/LaunchAgents/com.capablemonkey.sleepApp.plist

In my node-webkit app, I can accomplish this by running those commands with `child_process.exec`:



disabling the job

Should the user decide to disable running on login, our application can do:

launchctl unload ~/Library/LaunchAgents/com.capablemonkey.sleepApp.plist



checking to see if job is enabled

Our application can check to see if running on login is enabled:

launchctl list | grep com.capablemonkey.sleepApp



grep will return an error code of 1 and stdout will be empty if the job is not loaded.  Otherwise, we'll see our job and some information in stdout.

that's all, folks!

Pretty straightforward stuff.  Not sure if this is the best way to accomplish this, but it works well.  I didn't find any good resources on programmatically implementing "run on login", short of asking the user to add the app to their Login Items list or writing an AppleScript that does that.  Hope this comes in handy for someone!

Saturday, March 29, 2014

Leveraging Dwolla OAuth for User Authentication

Dwolla Forms, a Dwolla Labs project, uses Dwolla’s OAuth API to authenticate users rather than the standard email / password login scheme most web applications use today. Your app can too!

By relying on a third party like Dwolla to authenticate your users, you outsource the responsibility of username and password storage, retrieval, and verification. This lets you leverage all the hard work we’ve put into building a secure login system, for free! Of course, relying on a third party requires trust and faith in the accuracy and security of this third party authority. Rest assured, we’ve got our data locked down. (read more about security at Dwolla)

By lowering the amount of sensitive information you hold, you become a less tasty target for attackers. As another consequence, you’ll save your users from having to remember yet another username and password combination.

Overview

We can implement authentication via Dwolla OAuth in three easy steps:

  1. Obtain authorization to access a Dwolla user’s account information via OAuth
  2. Retrieve the user’s unique Dwolla ID using the Dwolla REST API’s Account Information endpoint
  3. Authenticate the user based on their Dwolla ID.

When a user signs up via OAuth for the first time, we retrieve and store their Dwolla ID with their user data. In the future, when that user attempts to sign in again, we point them to OAuth with Dwolla, and then we ask, in effect, “Hey Dwolla, what’s the Dwolla ID of the user I just redirected to you?” From there, we look up the corresponding user by their Dwolla ID and generate a login session for them.

Sample code!

Let’s look at how that works with some sample Node.js code. We’re using the express.js web application framework and nanek's node-dwolla package.

First, we’ll start off by creating a route which initiating OAuth:
    app.get('/auth/dwolla', function(req, res) {
      var authUrl = Dwolla.authUrl(redirectUri, "AccountInfoFull");
      return res.redirect(authUrl);
    })
After the user logs in and authorizes our Application, they’ll be returned to /auth/return, which is handled here:
    app.get('/auth/return', function(req, res) {
    var code = req.query['code'];
    $.waterfall(
      [
        // Exchange code for token
        function(callback) {
          Dwolla.requestToken(code, redirectUri, callback);
        }
        // Get user info
        , function(token, callback) {
          Dwolla.setToken(token);
          Dwolla.fullAccountInfo(function(err, user) {
            if(err) { return callback(err); }
            return callback(null, user);
          });
        }
        // If user is new, create a new user with Name and Dwolla ID returned by fullAccountInfo
        // otherwise, if they already exist, return the existing user object.
        , function(user, callback) {
          db.User
            .findOrCreate(
              {
                dwolla_id: user['Id']
              }
              , {
                name: user['Name']
                , dwolla_id: user['Id']
              }
            )
            .complete(function(err, user) {
              if(err) { return callback(err); }

              // log user in:
              req.session._user = user;
              return callback(null, user);
              }
            })
        }
      ]
      , function(err, results) {
        if(err) {
          return res.send('oh no!');
        }
        return res.render('nextpage');
      }
    )
  })
In this route, we first extract the verification code we get upon user redirect and exchange it for an OAuth token, thus completing the OAuth process. Then, we retrieve the user’s Dwolla account information with Dwolla.fullAccountInfo().

From the user object we get back, we’ll find an existing user account based on the user’s Dwolla ID, or create a new one, with the given user’s name and Dwolla ID. Finally, we’ll log the user in by attaching their user object to the current session and send them off to the next page.

Tuesday, March 25, 2014

Do the weaknesses of SHA-1 weaken the security of Dwolla’s API?

I'd like to share our answer to an interesting question regarding SHA-1 and the authentication scheme implemented by Dwolla's Off-Site Gateway Submit Directly flow:
"I'm looking at the developer stuff on checkout workflow, and see that the "signature" being transmitted between Dwolla and a business website is specified to use the SHA1 hash system. It is my understanding that that method is becoming vulnerable to an attack that has adequate computing power behind it. So, what other hash methods are allowable, for a business interacting with Dwolla? Thanks in advance!"
Though there are some weaknesses with SHA-1, they relate only to hash collisions. This means the weaknesses aren't helpful to attackers who are trying to determine the underlying input(s) of the hash. The only way to obtain the input(s) is by brute force.
In our case, the input of the signature hash is a concatenation of the Application Key, timestamp, and OrderID. These are all provided in the checkout form, so the attacker knows what the input is. What the attacker doesn't have is the Application Secret, which is a 50 character string used as the key in this key-based hash.
In order to forge a signature, the attacker would need to obtain the App Secret by way of brute force. If we assume the search space per character is all alphanumeric characters and 3 symbols ("+", "/", and "="), that leaves us with 65 possible characters. Since the secret is 50 characters long, we can say that an attacker would need to make
or
attempts to exhaust all possibilities.

Let's say an attacker can hash 10 million candidates per second on a single CPU. To exhaust all possibilities, it would take roughly:

Even if he has a large farm of machines running, say 1000 machines, with a collective power of 10 billion hashes/sec, it'd still take roughly:

The sheer size of the Secret string renders brute force an infeasible way to obtain it.  I would recommend reading Jeff Atwood's write up about hashes.

Sunday, March 16, 2014

Spotflux doesn't play nice with Tunnelblick

I recently gave Spotflux, a free VPN tunneling service, a try on my Mac.  I loved the experience -- extremely high speed and unlimited bandwidth, but I noticed that I could no longer use my beloved Tunnelblick VPN client.  When attempting to connect to a network with Tunnelblick, it errored out:

  openvpnstart returned with status #226

and left this in the log:

*Tunnelblick: openvpnstart log:
 Loading tun-signed.kext
 stderr from kextload: /Applications/Tunnelblick.app/Contents/Resources/tun-signed.kext failed to load - (libkern/kext) kext (kmod) start/stop routine failed; check the system/kernel logs for errors or try kextutil(8).
 stderr from kextload: /Applications/Tunnelblick.app/Contents/Resources/tun-signed.kext failed to load - (libkern/kext) kext (kmod) start/stop routine failed; check the system/kernel logs for errors or try kextutil(8).
 stderr from kextload: /Applications/Tunnelblick.app/Contents/Resources/tun-signed.kext failed to load - (libkern/kext) kext (kmod) start/stop routine failed; check the system/kernel logs for errors or try kextutil(8).
 stderr from kextload: /Applications/Tunnelblick.app/Contents/Resources/tun-signed.kext failed to load - (libkern/kext) kext (kmod) start/stop routine failed; check the system/kernel logs for errors or try kextutil(8).
 stderr from kextload: /Applications/Tunnelblick.app/Contents/Resources/tun-signed.kext failed to load - (libkern/kext) kext (kmod) start/stop routine failed; check the system/kernel logs for errors or try kextutil(8).
 Error: Unable to load net.tunnelblick.tun and/or net.tunnelblick.tap kexts in 5 tries. Status = 71

Apparently, the kext (driver) that Spotflux loads is incompatible with Tunnelblick and prevents Tunnelblick from loading its own kext. The solution is to unload Spotflux's kext and try connecting via Tunnelblick again.

Let's first run kextstat in Terminal to ensure we've got the offending kext loaded:
 
kextstat | grep spotflux
  121    0 0xffffff7f82231000 0x6000     0x6000     com.spotflux.Spotflux.tun

Then, let's unload it via kextunload.  This requires sudo.

sudo kextunload -b com.spotflux.Spotflux.tun

Once unloaded, Tunnelblick will be able to load its kext and connect as usual!  This will need to be done every time Spotflux is launched and you wish to use Tunnelblick afterwards, unfortunately.

Saturday, January 25, 2014

Graph Search: Facebook is Finally Useful

Facebook's Graph Search feature is amazing. I wanted to know which of my new acquaintances and friends from high school go to the university I'll be visiting for a hackathon next week. So, I just started typing my query in a natural way, "my friends who go to Carnegie Melon University", and bam -- I got exactly what I was looking for. No fumbling with drop down menu filters or long advanced search forms. It's like Wolfram Alpha for your intricate network of friends, family and acquaintances.




Of course, not everyone feels the same way about this feature.  Moreover, not everyone feels the same way about Facebook itself.  There's the highly debated issue of users being overly reliant on the online platform, to the point where it's unhealthy.  Critics of Facebook mock it as a tool for narcissists who couldn't care to remember who their friends are.

While I'm cautious of Facebook's potential to be used in a socially unhealthy way, I'm a firm believer that the data amassed by the network can be used to improve social life off the web.  I've made many acquaintances who I haven't yet had the luxury of learning everything about them.  I will probably remember them and the moments we shared together, but easily forget their name and the school they go to or their hometown. Facebook solves this problem.


However, the fact that Facebook wields so much power, that it single-handedly controls personal, and sometimes private information about nearly everyone, coupled with the perceived lack of transparency about what Facebook does with that data gives rise to the suspicion that they may have a nefarious agenda --  they may be exploiting this data by selling it to nosy corporations or giving direct access to snooping intelligence agencies like the NSA.  

By building Graph Search, Facebook has given me a reason to believe that the data it amassed doesn't have to be used for "evil" -- it can be used for good. Its collection, aggregation, and analysis of social data undoubtedly comes at the cost of privacy, but the insights gained are powerful and beneficial.

At the end of the day, Facebook is solving a complex problem: digesting the massive amount of data submitted voluntarily by hundreds of millions of people around the world, and making it useful.  They've done just that with Graph Search.

Thursday, November 21, 2013

Morpheus

The following is an excerpt from my blog post in the Dwolla Blog where I recounted my experience at the largest hackathon in Texas, HackTX.
A screenshot from Morpheus.
A screenshot from Morpheus.
Morpheus, whose name bears no relation to the well known leader in the human fight against dystopian robot overlords from The Matrix, but instead is named after the Greek god of dreams and sleep, is a platform that brings distributed computing to mobile devices.  Mobile devices, such as Apple and Android smartphones and tablets, are exponentially increasing in processing power.  If we consider the fact that in my pocket lies an HTC One which contains a 1.7 GHz quad-core Snapdragon processor, (which truly is mind-blowing, because the last time I shopped for computer components, a few years ago, Intel was just rolling out their first Quad Core processors and the world was going nuts over it) and we also consider that 80% of the time, my phone is resting idly in my pocket or missing underneath my bed, we realize that the true potential of its is being wasted 90% of the time.  The other 10% is wasted because I use my phone to check my Facebook news feed and text my buddies.  Now, imagine if your phone could instead be used to work in a cluster of other computing devices to tackle large computational problems, like those being solved by [email protected], a project that takes advantage of the powerful Playstation 3's gamers have sitting in their homes to simulate protein folding, design medical drugs, and understand molecular dynamics to save human lives.  The true power of Morpheus is realized when you consider that smartphones and tablets are growing in their ubiquity.  Think about the impact that billions of super-quick devices could have if they were used for a purpose greater than taking selfies and tweeting about what you're about to buy from the supermarket.

"But do you really think people will drain their battery just because of the philanthropic goodness of their hearts?"  you may be inclined to ask.  Morpheus answers this in two ways: a) participants only leave their phone to compute when charging at night, and b) researchers will pay participants, using Dwolla, for the work their phone does.  This brings an interesting twist to the Folding @ Home model, which relies on gamers to rack up their energy bill and subject their PS3 to computational slavery for nothing except the knowledge that they're doing good in this world.  With Morpheus, researchers and even commercial enterprises can leverage the immense power hidden away in everyone's pockets to solve their problems.  Imagine IBM renting your phone for the night so it can compute the Answer to Life, The Universe, and Everything in just a fraction of the 7.5 million years it took Deep Thought to do so.
The Morpheus team!
The Morpheus team! 
So, in essence, you get paid while you sleep just for running a simple app on your phone during the night. This simple idea is mind-bogglingly cool and has a ton of potential to do good for the world. I'm hopeful that the Morpheus team, uTexas students Eduardo Saenz, Bulat Bazarbayev, Comyar Zaheri Brandon Lee, and Sudheesh Katkam, will take this beyond HackTX and launch this in the wild, real world. Very well done, gentlemen.

Monday, June 25, 2012

Python: Glide, instead of move, mouse cursor from one point to another

I couldn't find a function in pywin32 to smoothly glide a pointer from one point to another, instead of simply "moving" the cursor by making it jump from its current position to a given position.  I needed a way to make the mouse sort of "glide" from point A to point B at a seemingly natural pace, so here's my solution:

import time
import win32api

MOUSE_SPEED = .4 #seconds

def mouse_glide_to(x,y):
    """Smooth glides mouse from current position to point x,y with default timing and speed"""
    x1,y1 = win32api.GetCursorPos()
    smooth_glide_mouse(x1,y1, x, y, MOUSE_SPEED)

def smooth_glide_mouse(x1,y1,x2,y2, t, intervals):
    """Smoothly glides mouse from x1,y1, to x2,y2 in time t using intervals amount of intervals"""
    distance_x = x2-x1
    distance_y = y2-y1
    for n in range(0, intervals+1):
        move_mouse(x1 + n * (distance_x/intervals), y1 + n * (distance_y/intervals))
        time.sleep(t*1.0/intervals)

def move_mouse(x, y):
    win32api.SetCursorPos((x,y))
mouse_glide_to(x,y) will move the cursor from its current position to point (x,y) in MOUSE_SPEED seconds. It works perfectly!