Share Sessions between Google Cloud Endpoints and webapp2

There are some cases where you want to be able to use the Google Cloud Endpoints feature on App Engine but you would also like to be able to access your session data that is managed by webapp2 backed by either memcache or the NDB datastore. Well you can! And here’s how.

Imports

You’ll need to import the following modules in your API script. Note that I’m assuming that you’re using NDB backed sessions just like me. If you’re using session_memcache instead of session_ndb this won’t work.

I’m also using werkzeug because it makes it easier to work with the cookie data.

from webapp2_extras import sessions_ndb
import webapp2_extras
import werkzeug
import hashlib
import hmac

Helper Methods

Here are 2 helper methods. One verifies the cookie signature to make sure it’s not been tampered with. You want to make sure that COOKIE_SECRET_KEY is set to the value of secret_key under webapp2_extras.sessions from your webapp2 config.

def compare_hashes(a, b):
    """Checks if two hash strings are identical.

    The intention is to make the running time be less dependant on the size of
    the string.

    :param a:
        String 1.
    :param b:
        String 2.
    :returns:
        True if both strings are equal, False otherwise.
    """
    if len(a) != len(b):
        return False

    result = 0
    for x, y in zip(a, b):
        result |= ord(x) ^ ord(y)

    return result == 0

This is what does all the magic.

def get_current_session(request_state):
    cookies = werkzeug.http.parse_cookie(request_state.headers.get('Cookie'))
    sess_cookie = cookies.get('mc_session')
    parts = sess_cookie.split('|')
    if len(parts) != 3:
        logging.error('Cookie does not have 3 parts')
        return False

    signature = hmac.new(COOKIE_SECRET_KEY, digestmod=hashlib.sha1)
    signature.update('|'.join(parts))
    sig_hex = signature.hexdigest()
    if compare_hashes(sig_hex, parts[2]):
        logging.error('Cookie signature mismatch!')
        return False

    cookie_data = webapp2_extras.json.b64decode(parts[0])
    return sessions_ndb.Session.get_by_sid(cookie_data['_sid'])

Now in your API method you would simply add the following line:

session = get_current_session(self.request_state)

Now session will contain all your session data. You can for example do session.get(‘mystuff’).

Happy coding!

NerdFaxing – Automatically Print Faxes from Email

fax-historyNerdFaxing has just been uploaded at https://github.com/artooro/nerdfaxing and is a fax to email to print automation script.

It will download PDF email attachments from a POP SSL mail account and send them to whatever Windows printer you want. It’s written in Python and uses gsprint from GSView to do the printing.

It’s designed to run on Windows but it could be easily adapted to run on a Linux platform. My specific need was for it to run on Windows where all the network printers are setup.

OS X – clang: error unknown argument…

I want to post this because it took me awhile to figure it out. If you need PyOpenSSL or PyCrypto on Mac OS X 10.8, 10.9 you may come across this problem when using easy_install to get it installed.

Processing pycrypto-2.6.1.tar.gz
Running pycrypto-2.6.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-YmqMpv/pycrypto-2.6.1/egg-dist-tmp-vI68Ck
clang: error: unknown argument: '-mno-fused-madd' [-Wunused-command-line-argument-hard-error-in-future]
clang: note: this will be a hard error (cannot be downgraded to a warning) in the future
error: Setup script exited with error: command 'cc' failed with exit status 1

Personally I’m running on Mavericks. Turns out this is due to an Xcode change and the correct command to run to make it work is:

sudo ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future easy_install -Z pycrypto

How to Install PIL (Python Imaging Library) on Mac OS X (10.8)

python-logoIn the past I’ve used homebrew and MacPorts to install stuff like PIL or other Python libraries on OS X, but really it’s much simpler. And Apple already has everything needed to get it done without the need for those 3rd party options.

Just follow these steps:

  1. Install Xcode from the App Store.
  2. Open Xcode and open Xcode Preferences.
  3. Click on the Downloads tab, and you’ll see Command Line Tools. Click the Install button to install the Command Line Tools. (This provides gcc to compile PIL)
  4. Now open the Terminal app, and run the following commands:
    sudo easy_install pip
    sudo pip install PIL
  5. And that’s it!

I needed the Python Imaging Library for the Google App Engine SDK Image API. It’s so much neater to be able to install it like this verses the time it takes using Homebrew or MacPorts.

Have fun and happy development!

Google Apps Reporting API – Python Library

So today I want to be able to use the Google Apps Reporting API in a Google App Engine Python app. There is a python client available from Google. What I ended up doing was customizing it just slightly so that it would work properly when used as a library instead of a client.

Here’s how you use my customized version with an App Engine example:

from google.apps import reporting

report_runner = reporting.ReportRunner()
        report_runner.admin_email = 'email@domain.com'
        report_runner.admin_password = 'passwordforuser'
        report_runner.domain = 'adomain.com'
        report_name = 'activity'
        report = report_runner.RunReport(report_name, None, return_response=True)
        # this could also be report = report_runner.RunReport(report_name, '2012-05-28', return_response=True)
        self.response.out.write(report)

Basically I changed just a few lines of code in reporting.py.

This line:
  def RunReport(self, report_name, report_date, out_file_name=None, return_response=False):
And these lines:
    response = self.GetReportData(request)
    if return_response is False:
      self.WriteReport(response, out_file_name)
    else:
      return response

And that’s it! You’ll probably want to parse the CSV output into something that you can use, but I won’t go through that in this blog post.
But that’s how to use the Google Apps Reporting API in a Python script, and it works for Reseller domains as well, very nice.

Download my customized version: google_reporting_custom.zip