Adding OAuth2 to OpenSelfie

As in most things Internet, when you make them more secure, things get more complicated. A little while ago, photo uploads from OpenSelfie (our OpenSource Raspberry Pi AlaMode Photobooth) stopped working. It turns out that Google disabled “programmatic login” (e.g. with a username and password) from most of their apis, including the picasaweb api that we use to upload photos. Now the only thing that works is OAuth2, and it requires a little dance between a web browser signed into your google account, and granting of credentials for your application.

Diagram from the google developers site

Diagram from the google developers site

I had a real hard time figuring out how it all works until I found this link:

https://groups.google.com/forum/#!topic/google-picasa-data-api/4meiAJ40l3E

There were bits of information missing, and a couple of errors but I eventually figured it out. The new code is in boothcam.py in a procedure called OAuth2Login, which takes a pointer to a secrets json file (more on this below), a credentials store file (where the authenticated credentials are cached for you, and the user’s email address.

There’s also a standalone version for listing Album ids (useful for configuring a new album for an event in listalbums.py

You’ll need to install the latest google python api:

$ sudo pip install --upgrade google-api-python-client

If this is your first time, or you are looking to steal this code for another project, you’ll need some other python libraries, most notably

$ sudo apt-get install python-gdata

[code]

def OAuth2Login(client_secrets, credential_store, email):
 scope='https://picasaweb.google.com/data/'
 user_agent='picasawebuploader'

 storage = Storage(credential_store)
 credentials = storage.get()
 if credentials is None or credentials.invalid:
   flow = flow_from_clientsecrets(client_secrets, scope=scope, redirect_uri='urn:ietf:wg:oauth:2.0:oob')
   uri = flow.step1_get_authorize_url()
   webbrowser.open(uri)
   code = raw_input('Enter the authentication code: ').strip()
   credentials = flow.step2_exchange(code)

 if (credentials.token_expiry - datetime.utcnow()) < timedelta(minutes=5):
   http = httplib2.Http()
   http = credentials.authorize(http)
   credentials.refresh(http)

 storage.put(credentials)

 gd_client = gdata.photos.service.PhotosService(source=user_agent,
 email=email,

 additional_headers={'Authorization' : 'Bearer %s' % credentials.access_token})

[/code]

You can see it creates a flow and asks google for credentials using your secrets file. (note that this is not checked in as you could use up my api credits. You;ll need to create your own.) It then spins up a web browser, makes sure you are logged in to your google account (the email address you configured OpenSelfie with) and asks your permission.

It will then give you a code to enter into OpenSelfie. I had troiuble cutting and pasting from the default web browser so I installed luakit, and made it the default browser

$ sudo update-alternatives --config x-www-browser

Creating your own API keys with the Google Developer console

Head on over to the Google Developer console and create a project for your OpenSelfie

Google-dev-step1

The name here doesn’t really matter. I just used OpenSelfie.

Next, click on your project and click on Credentials under API’s and auth.

If you haven’t already, you;ll need to configure the OAuth consent screen.

The only thing you really need to do is specify the  Product Name.

OAuth Consent screenYou’ll want to “Add Credentials/OAuth 2.0 client ID” Note: you don’t have to explicitely enable any additional APIs, as we are dealing with basic authentication and authorization here which is used by every API, and the photo apis haven’t been explicitly added to the console.

google-dev-step3

Next you specify the type “Other” and I named it Installed. Most of the instructions I saw seemed to imply there used to be a type called Installed. I’m not sure it’s critical that this name be here, but I used it to be safe. Click Create.

google-dev-step4

Now you’ll see it in your list of credentials for this app.

google-dev-step5

Click OK, and then click on the “Installed” credential. When that’s open, click on Download JSON. It will download a file with a name like client_secret_90328409238409238……json

google-dev-step6-download

rename this file OpenSelfie.json and put it in the OpenSelfie/scripts directory.

Configuring OpenSelfie

Start up OpenSelfie in a terminal window:

cd OpenSelfie/scripts
python ./photobooth_gui.py

If you’ve already configured your OpenSelfie, when it tries to login to google, it will find it doesn’t have credentials and then start the flow to create them. Your web browser will pop up, you should sign in to google, (with the same email address you configured.) and then it will ask you if OpenSelfie  can manipulate your photos.

Permission

Click on Allow, and then it will display a box with a long string of numbers and letters. Cut and paste that into the console window where it says “Enter the Authentication Code.” hit enter, and if all is well it will snap a photo and upload it to the album you have previously configured (or fail if you haven’t set it yet.)

paste-code

Fortunately, you only have to do this once! After this it will remember the credentials and periodically refresh them. The cached credentials are stored in a file called credentials.dat, so if you delete it, you’ll have to do the web dance again, as long as your json file is still there.

Conclusion?

Well, it seems to me that Google is trying to be a good security player, at the cost of ease of use. It seems that it’s very difficult to interact with devices with a limited UI (they suggest printing URLs and having them typed into another device). Fortunately we’re working with a full Raspberry Pi so it can all be done on the same machine. I’m sure the UI can be finessed, and if you do fork the project and make improvements, please make pull requests!

When an image comes along, you must wifit…

Screenshot from 2013-08-08 07:44:17

Wifit is a program to create images for E-Paper Displays (available at Adafruit).  It is written in Python using the amazing Python Image Library.

Features:

Download: Right now wifit.py is only available as a source zip file (or Fork me on GitHub!)  The py2exe build has one quirk right now that prevents you from writing text.  Hopefully we will get that worked out soon. Wifit.py requires python2.7, PIL, and numpy.

CommandsAfter you download the entire directory as a zip file, start EPD/libraries/EReader/examples/Album/wifit.py from the command line or by double clicking the file icon from windows explorer.

The default image will be displayed.  Familiarize yourself with the controls:

  • left-mouse-click: select image or text
  • left-mouse-drag: translate image or text
  • right-mouse-drag: scale image or text
  • ctrl-c: copy selected image or text
  • ctrl-v: paste selected image centered under mouse, or paste image at web url
  • type “I”: insert BigAscii text box
  • type “i”: insert Unifont text box (normal ascii)
  • <RETURN>: Exit text mode
  • <ESC>: Exit text mode
  • <DELETE>: Delete selected image or text
  • <CTRL>-i: Invert an image (black/white)
  • <CTRL>-c: Copy selected image
  • <CTRL>-v: Paste copied image (or paste image from url)
  • <CTRL>-r: Rotate image 90 degrees counter-clockwise
  • <CTRL>-h: Flip image horizontally
  • <CTRL>-u: Flip image vertically
  • <SHIFT>-<UP>: Nudge image up
  • <SHIFT>-<DOWN>: Nudge image  down
  • <SHIFT>-<LEFT>: Nudge image left
  • <SHIFT>-<RIGHT>: Nudge image right

Menus:

  • File–>Open: Open a new image file (close current image)
  • File–>Save: Save current view port image in WIF or png
  • File–>Exit: Quit the program
  • Size–>EPD_LARGE, _MED, _SMALL: Set view port size to EPD standard sizes.
  • Size–>Headshot: Set view port to standard headshot size for badges.
  • Insert–>Image: Open new image on top of old image.  Images can be edited independently.
  • Insert–>Big ASCII Text: Start typing in 16×16 pixel font
  • Insert–>Unifont Text: Start typing in (mostly) 16×8 pixel font
  • Insert–>5×7 Text: Start typing in 5×7 pixel font
  • Insert–>4×4 Text: Not implemented

Use it! 
This example will work with any Arduino compatible with an SD card (like AlaMode).

Now lets use wifit.py to make our badge for the Open Hardware Summit.  The badges will come pre-loaded with the information you provided at registration.  But you will want to customize it.

1. Start wifit.py and delete the default image after you have played around with it.

2. Select a photo from the web by right clicking in your browser and selecting “copy image url” and pressing ctrl-v to paste in wifit.  A Google image seach of “wyolum” produces a lot of cool pix.Screenshot from 2013-08-09 22:33:13

Screenshot from 2013-08-09 22:33:55

3. Adjust the image: move the image to the desired location (right-drag) and scale it (left-drag).  Use the sliders on the bottom to control contrast and brightness.

4. Add text: Insert–>Big ASCII Text. Type text and left-drag into position.  You can also rescale text with right-drag.

Screenshot from 2013-08-09 22:48:56

5. If your computer has an SD slot, you can save it directly to the SD card in the primary image location: “/ALBUM/A/A.WIF”.  Now insert the SD card back into BADGEr and hit reset (far right button).  Walla!

Have fun!

P.S.  You can thank my office mate for getting DEVO stuck in your head.

UPDATE!

I’ve added some more features: invert, rotate, flip, and nudge your images.  Tkinter allows you to detach menus from the menu bar.  This is handy if you don’t like keyboard shortcuts.