Packing Chrome extensions in Python

We’re just about to release our DotSpots extension for Chrome and I’ve been working on integrating the CRX packaging into our build process. CRX files are basically ZIP files with an RSA signature and public key tacked on to the front of it. Generating these files requires you to use the Chrome –pack-extension argument (which in turn requires you to deploy the 100MB+ Chrome binaries to your build machine).

The existing code to pack a Chrome extension in Python is pretty dated: it will only generated the insecure CRX version 1 format that doesn’t use a cryptographic signature. There’s some Ruby code to pack a version 2 extension, but it requires a lot of dependencies that aren’t installed by default on OSX or in Fedora.

I’ve written some code in Python that uses openssl under the hood to do the grunt work. It cuts some corners by requiring you to pre-zip your files, but you’ll get better results from 7zip -9 than Python’s internal zip code anyways. Pass it three arguments: The input ZIP file, the PEM key (generated when you manually pack the extension in Chrome for the first time) and the output file.

#!/usr/bin/python
# Cribbed from http://github.com/Constellation/crxmake/blob/master/lib/crxmake.rb
# and http://src.chromium.org/viewvc/chrome/trunk/src/chrome/tools/extensions/chromium_extension.py?revision=14872&content-type=text/plain&pathrev=14872

import sys
from array import *
from subprocess import *

arg0,input,key,output = sys.argv

# Sign the zip file with the private key in PEM format
signature = Popen(["openssl", "sha1", "-sign", key, input], stdout=PIPE).stdout.read();

# Convert the PEM key to DER (and extract the public form) for inclusion in the CRX header
derkey = Popen(["openssl", "rsa", "-pubout", "-inform", "PEM", "-outform", "DER", "-in", key], stdout=PIPE).stdout.read();

out=open(output, "wb");
out.write("Cr24")  # Extension file magic number
header = array("l");
header.append(2); # Version 2
header.append(len(derkey));
header.append(len(signature));
header.tofile(out);
out.write(derkey)
out.write(signature)
out.write(open(input).read())

print "Done."

3 Responses to “Packing Chrome extensions in Python”

  1. Ivan says:

    I’ve found this script very useful. But there is a small issue which makes it failing on Windows. I’ve fixed the issue and put new version to google code (http://code.google.com/p/crx-packaging/source/browse/trunk/packer.py). If you have any concerns about this, I’ll remove the project.

    • Matt Mastracci says:

      No worries about putting it up on Google Code. Do you mind putting a link back to this page in the source (I tried to do the same with the sources I pulled from).

      From what I can tell, the change is open(file, “rb”) when reading the ZIP?

Leave a Reply

You must be logged in to post a comment.