Previously…

Last time, I ranted a bit, and pointed at the Firefox Addon SDK to download.

Let’s unpack.

I mentioned that Firefox addons are built using a javascript framework. But this addon SDK we just unpacked is a Python project. What’s that all about?

  1. Don’t worry: Python is good for you.
  2. The SDK is just a bunch of tools to assist bootstrapping, testing, and packaging your addons. The addons will use the javascript frameworky stuff. The sdk is a separate beast.

Environment tweaks

To begin using the sdk, drop down to a command prompt, head to the wherever you unpacked it, and get going with:

$ source bin/activate

This will setup some environment variables, and allow the sdk tools to find the sdk libraries [1].

If all goes well, you should be able to run this:

$ cfx --help

The top level stuff gives us:

Usage: cfx [options] command [command-specific options]

Supported Commands:
  docs       - view web-based documentation
  init       - create a sample addon in an empty directory
  test       - run tests
  run        - run program
  xpi        - generate an xpi

Bootstrapping

Project create time! Head to whatever directory you like, to save your new addon.

$ cfx init

* lib directory created
* data directory created
* test directory created
* doc directory created
* README.md written
* generated jID automatically: jid1-vEka7zFaULYaEA
* package.json written
* test/test-main.js written
* lib/main.js written
* doc/main.md written

Your sample add-on is now ready.
Do "cfx test" to test it and "cfx run" to try it.  Have fun!

So far, so good. Give it a run, and it’ll launch a firefox instance with your (currently) useless addon loaded up. Useless, but always nifty to open up the extensions page and see something to say, “We woz ‘ere”:

That’s enough of the cfx intro. If you’d like more, go check out the Getting started with cfx guide.

Addon prototype

Basic plan this time around: get something addon-ish summoning and running pccipher successfully.

I’m going to begin with an addon that lets me:

  1. Select a bunch of text,
  2. Launch Pccipher encrypt/decrypt via context menu entries,
  3. Prompt for the key, and
  4. Replace the selected text with pccipher’s results.

Note

Remember - this is a test run! I’m totally ignoring many problems, such as keystrokes being posted as you type, or key storage. For now, don’t care. Just playing.

Our code will be launched from the lib/main.js file, which cfx init created for us already. Right now it’s a blank file.

Cheating a little more (for now)

The addon sdk expects our javascript modules to comply with CommonJS module format. As of right now, the published version of Pccipher isn’t in this format. Plus, it depends on Phpjs, which also expects to be loaded via <script> tags, and not by this sdk.

Essentially, CommonJS modules create namespaces. The current codebase assumes standard global-namespace javascript.

This time round, I’m going to concatenate the phpjs.js and pccipher.js files, and add a small exports line at the bottom, treating this as one module to import.

if (typeof exports != 'undefined') {
    exports.pccipher_encrypt = pccipher_encrypt;
    exports.pccipher_decrypt = pccipher_decrypt;
    exports.pccipher_get_cookie = pccipher_get_cookie;
}

A good follow-up to all this will be to submit a patch to each project, enabling these libraries to play more nicely with CommonJS frameworks.

In the meantime, we can now import the encrypt/decrypt functions, in our main.js file, like so:

var {pccipher_encrypt, pccipher_decrypt} = require('phpjs-pccipher');

The Context Menu

The sdk’s context menu api does a lot of the work for us.

In our main.js, we’ll create a context menu instance, which listens for selection events.

Let’s go garble some text (we’ll just stick with a hardcoded key for now, while we get everything else in place).

var {pccipher_encrypt, pccipher_decrypt} = require('phpjs-pccipher');
var pccipher_context_menu = require("sdk/context-menu");
var selection = require("sdk/selection");

pccipher_context_menu.Item({
  label: "Encrypt",
  context: pccipher_context_menu.SelectionContext(),
  contentScript: 'self.on("context", function() {' +
                 '    self.postMessage(window.getSelection().toString());' +
                 '});',
  onMessage: function(text) {
    if (selection.text) {
        selection.text = pccipher_encrypt(text, 'foobar!'); // FIXME: hardcoded key!!!
    }
  }
});

Now launch cfx run, to give it a whirl. Open some page, and select some text.

Bam! Hang on. Not quite right. No menu entries appeared, and the selected text changed as soon as it was selected!

Oops. What went wrong?

Yep. Wrong event. I set the menu item’s contentScript to listen for “context” events. In our case, we’ve set the context to SelectionContext, so shit will happen as soon as something is selected.

Close, but no cigar.

Instead, this should be:

contentScript: 'self.on("click", function() {' +
               '    self.postMessage(window.getSelection().toString());' +
               '});',

Listen for click events. As in: menu clicks.

That’s better. Now the context menu has two new entries down the bottom: “Encrypt” and “Decrypt”.

Also, it waits politely for us to pick one or the other before calling on Pccipher.

Next time

This has tackled a few aims of our little prototype, but there are still plenty of things to do.

Up next, the obvious one: get rid of the ‘foobar!’ key, and maybe integrate with Firefox’s password manager.

At the moment, I’ve a vague idea of where I’m going with this. If you’ve any thoughts on what to do, sing out.

The code, as it stands so far (sans the sdk itself) can be found here:

https://bitbucket.org/otherchirps/pccipher-firefox-addon

[1]For pythonistas out there, it turns out the sdk comes bundled with its own customised version of virtualenv.

Comments

comments powered by Disqus