Archive for the ‘Firefox’ Category

Setting the Default Mail Client for Firefox

April 8th, 2005 by daryl

Until today, every time I’ve clicked a mailto link in Firefox, the clunky old Evolution email program has started churning, and I’ve smacked myself on the forehead and cursed as I waited for that behemoth of an application to load. You see, I use the lightweight Thunderbird, which loads in an instant and is as flexible and powerful as I need it to be. So I wait for Evolution to finish loading a compose window, close that down, copy the mailto link into a Thunderbird composition window, and write my email. It’s a pain every time.

One of the RSS feeds I keep an eye on is Linux Journal’s, and an article entitled “Ten Mysteries of about:config” caught my eye there today. It’s a decent little article by Nigel McFarlane, author of Firefox Hacks, which I just received in the mail this week and which looks promising. One of the mysteries Nigel explains is how to set a default mail client in Firefox on Linux (it’s easy enough in Windows because it’s governed at the system level). It takes only three steps:

  • Open about:config in your browser.
  • Set the preference named “network.protocol-handler.external.mailto” to true; if it doesn’t exist, create it and set it to true.
  • Create a preference named “network.protocol-handler.app.mailto” and set it to the path to Thunderbird. In my case, this is /usr/local/thunderbird/thunderbird.

That’s all there is to it. When I did this and clicked a mailto link, a Thunderbird composition window shot to the foreground and I was in business.

Firefox Extension Sidebar Removal

March 31st, 2005 by daryl

I’m writing a Firefox extension that includes a sidebar. Firefox conveniently remembers the status of things like sidebars and toolbars when you close the application down. So if you have a sidebar displayed when you close out of Firefox, when you restart Firefox, the sidebar is still displayed. This is handy until you uninstall the extension and shut down Firefox with the sidebar still visible, as documented in this bug. What happens in this case is that when you restart Firefox after uninstalling the plugin, it comes up with a blank sidebar. In order to get rid of the sidebar, you have two basic options:

  • Reinstall the extension, restart Firefox (the sidebar will display the extension’s data again), close the sidebar, close Firefox, open Firefox back up, and uninstall the extension.
  • As documented here, you can go to localstore.rdf in your profile, hunt for a line dictating whether or not the sidebar appears, and delete it before restarting Firefox.

Neither of these options is particularly user-friendly. So I googled around a bit and found this post by Alex Sirota, which provided some general information about writing a cleanup script for an extension. Alex also responded to a further inquiry about writing an uninstall script and pointed me to an extension of his in which he’s implemented just such a thing. His script didn’t do the sidebar fix, but it helped me get to where I could call sidebar uninstall code when the browser shuts down.

So all that was left was to figure out how to edit localstore.rdf once I had determined that a given extension was unloading and had been slated for uninstallation and then make this code run on uninstall. The code listed below is kind of wacky because I’m using two different methods for manipulating datasources. In the first part, I’m manipulating the extensions datasource directly because I scraped the code from Alex’s extension. In the second part, I’m using the RDFDS library available at XUL Planet. Eventually, I’ll probably go back and use one method or the other, but this works for now. So without further ado, here’s the code:

function unload_overlay(){
    //Get various things needed to deal with RDF.
    var RDFService = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
    var Container = Components.classes["@mozilla.org/rdf/container;1"].getService(Components.interfaces.nsIRDFContainer);
    var extensionDS= Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager).datasource;

    //Get nodes and arc needed to figure out whether the given extension is slated to be uninstalled.
    var root = RDFService.GetResource("urn:mozilla:extension:root");
    var nameArc = RDFService.GetResource("http://www.mozilla.org/2004/em-rdf#name");
    var toBeUninstalledArc = RDFService.GetResource("http://www.mozilla.org/2004/em-rdf#toBeUninstalled");

    Container.Init(extensionDS,root);

    //Now iterate over the elements to find the toBeUninstalled value for the extension in question ("Extension Name," which you should change to match your extension name).
    var found = false;
    var elements = Container.GetElements();
    while (elements.hasMoreElements()) {
        var element = elements.getNext().QueryInterface(Components.interfaces.nsIRDFResource);
        var name = "";
        var toBeUninstalled = "";

        var target = extensionDS.GetTarget(element, nameArc ,true);
        if (target) {
            name = target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
        }

        target = extensionDS.GetTarget(element, toBeUninstalledArc ,true);
        if (target) {
            toBeUninstalled=target.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
        }

        //If we find the right value, set the found flag to true.
        if (toBeUninstalled && (toBeUninstalled == "true") && (name == "Extension Name")) {
            found = true;
        }
    }

    //Ok, our extension is slated to be uninstalled, so do some more stuff.
    if(found==true){
        try{
            //Here we're using the RDFDS class, so the code for this should be pulled in at some point. 

            //Get the localstore datasource
            var ds=new RDFDataSource("rdf:local-store");

            //Get the sidebar-box node.
            var node=ds.getNode("chrome://browser/content/browser.xul#sidebar-box");

            //Get that node's properties and remove all targets, which typically include "src," "width," and "sidebarcommand"
            //Removing all properties apparently causes the node itself to be deleted, which is the result we're actually going for.
            var properties=node.getProperties();
            while(properties.hasMoreElements()){
                prop=properties.getNext();
                node.removeTarget(prop.getValue(),node.getTarget(prop.getValue()));
            }

            //Now save and refresh the datasource.
            ds.save();
            ds.refresh();
            //alert('Uninstalling sidebar');

        }
        catch(e){
            alert(e);
        }
    }
}

In order to cause this code to be run when the browser unloads, you need to add the following line somewhere in your js:

addEventListener("unload", unload_overlay, false);

So here’s essentially what goes on in this script:

  • The extension includes a browser overlay, so any unload listeners added within the extension are added to the browser as a whole.
  • Thus our unload event listener is added to the browser as a whole, causing unload_overlay() to be called any time the browser is closed.
  • The browser has to be closed in order for extensions to be installed or uninstalled.
  • Accordingly, when we uninstall the extension and shut down the browser, unload_overlay() is called.
  • Unload_overlay() checks the extensions rdf to see if our extension has been slated for uninstall (in which case its toBeUninstalled value will be set).
  • If so slated, the code finds the sidebar-box node in the localstore.rdf datasource and deletes it.
  • This prevents the sidebar from being displayed on the next load.

I should probably add code that checks for the src attribute of the sidebar-box element in localstore.rdf and deletes the node only if it’s set to the current extension’s source. Currently, the uninstall code will probably delete any sidebar that’s open upon browser close, which might not always be a valid action (say a user keeps his or her bookmarks sidebar open; this might close that, which would be a pain for the user).

At any rate, here’s a draft of a way to circumvent the Firefox sidebar bug listed above.

XUL Tree Variables

March 12th, 2005 by daryl

XUL TreePictured here is part of what I’ve been working on for the last few days. I won’t go into much detail, but it’s a Firefox extension to improve the bookmark experience (does anybody actually use bookmarks? I save them but seldom have the heart to go back to the horrible user interface to retrieve them). Essentially, the project lets you label the bookmarks and have them closer at hand (in a sidebar) while browsing. It’s similar to del.icio.us but provides a nice integrated user interface and should eventually have a lot of bells and whistles that make it just an absolute singing joy to use. But it wasn’t easy.

The picture shows a tree, which is a XUL element useful for maintaining lots of information efficiently. You’ll recognize the tree from email programs, the Windows explorer, (conceptually) Web site navigation in many cases, and other places. Trees can be a pain to work with in XUL in particular because they’re populated by data in the RDF format. And there are all sorts of weird things about using RDF with trees. For example, you use a template to do so, and this makes it so that you can’t actually directly manipulate individual tree cells as elements in the document object model. They don’t exist. If you try to iterate down the XML defining the tree, you have no access to the elements that the RDF populated the tree with, so you can’t really perform operations on the elements. Additionally, a treecell keeps only a label and a value applied to it, and there are no functions for grabbing other attributes you may wish to store for a tree cell. In my case, I need a title and a value (the link itself) for displaying and clicking on a bookmark. But I also need to know what label has been applied to a given bookmark so that I can manipulate it. And since there’s no way I can divine to store a third value associated with a given treecell, I’m kind of up the creek.

Or not. It occurred to me that I could just add another treecell to the row and not display it. So where, before, an excerpt of my template looked something like this:

            <action>
                 <treechildren>
                    <treeitem uri="?category">
                        <treerow>
                            <treecell label="?label" value="?url" src="chrome://bookmarks/skin/buttons/document.png"/>
                        </treerow>
                    </treeitem>
                </treechildren>
            </action>

Now it looks more like this:

            <action>
                 <treechildren>
                    <treeitem uri="?category">
                        <treerow>
                            <treecell label="?mycategory" value="?mycategory"/>
                            <treecell label="?label" value="?url" src="chrome://bookmarks/skin/buttons/document.png"/>
                        </treerow>
                    </treeitem>
                </treechildren>
            </action>

I’ve added a treecell that contains the category associated with the given link. I then tweak my column headers to look like this:

        <treecols>
            <treecol id="category" hidden="true" label="Tag" flex="1" ignoreincolumnpicker="true"/>
            <treecol id="url" label="Bookmarks" primary="true" flex="1"/>
        </treecols>

The “ignoreincolumnpicker” attribute prevents the header from being displayed in a little button that lets you pick which columns to display in the tree. That’s just an extra precaution, though, as there’s an attribute on the tree tag itself named “hidecolumnpicker” that defaults to false and that I’ve set to true.

While this method actually does exactly what I need it to do, I’m not altogether satisfied with it because it feels a little jury-rigged. Trees should be for display of data rather than for manipulation of it. It seems as if there should be some way to store other values within a tree cell or tree row that can be extracted, but in most of a day’s wheel spinning, I could find none because the elements of an RDF-generated tree are moving targets that you can’t directly manipulate. In any case, this method seems to work for now, and I’m sticking with it barring feedback from any gurus who can point out something obvious that I’m missing.

Blocking Popup Ads in Firefox

March 6th, 2005 by daryl

Blocking Flash popupsI had noticed of late that popups seemed to be coming through my Firefox popup blocker with some frequency. I was a little perplexed but didn’t give it much thought (it wasn’t that frequently). The other day, Asa posted something about it. Basically, rather than using javascript embedded in HTML, the guys who get through the popup blocker are using plugins (such as Flash) to open windows. Luckily, Firefox offers a way to stop these, but it’s turned off by default because turning it on blocks potentially valid functionality within the plugins. I’ve turned the option on, though, and here’s how (screen scraped from Asa’s blog):

To block pop-ups from plugins, open your Firefox 1.0 or 1.0.1 browser, type about:config in the address field. Right-click in the resulting config page somewhere and select New -> Interger. Type privacy.popups.disable_from_plugins in the resulting dialog, hit OK, type 2 in the next dialog and you’re all set.

This pref can actually take three values:

  • 0: open allowed
  • 1: the opened windows are treated as popups, but they’re allowed to open (we limit the number of these types of popups)
  • 2: the window is a popup, block it

In the image accompanying this entry, the preference is highlighted. This is the view you get when you enter “about:config” in the Firefox address bar (though yours won’t have the preference I’ve highlighted until you’ve added it). To add the preference, just right click anywhere in this screen and follow Asa’s instructions. So far, it’s worked great for me, and with no ill side effects.

A Simple Firefox Extension Build Script

March 3rd, 2005 by daryl

I’ve been working on building some extensions for Firefox, including my prawn doohickey and, starting today, something for work. When you build an extension, you have to follow a given directory hierarchy that’s pretty well documented here. You also have to zip up a couple of sets of files and rename them appropriately, move them around, etc. I’ve got a code directory set up that’s forked into a “src” (source) and an “xpi” (the file extension given to completed Firefox extensions) directory. I change files in the src directory and then build the xpi file and save it in the xpi directory. Initially, this was a pain because you have to edit the files, zip some of them, move some of them, zip something else, etc. And every time you make changes to an extension, you have to do this routine. After about three iterations of it, I wrote a quick little shell script that does the build for me. I just execute “./build” from the command line and it assembles the xpi for me. Here’s the build script:

#!/bin/sh

echo “- Removing old r2.jar.”
rm chrome/r2.jar

echo “- Zipping new r2.jar from content.”
zip -r r2.jar content skin locale
mv r2.jar chrome/

echo “- Creating xpi.”
zip -r r2.xpi install.rdf chrome/

echo “- Moving xpi to output directory.”
mv r2.xpi ../../xpi/

If I weren’t lazy, I’d make this portable so that I didn’t have to change the script for each extension, but for now, I can just do a regular expression and, in this case, replace “r2″ throughout the script with whatever the directory name for the current script is. I think you can actually use ant and an xml config file to build extensions, and for more complicated extensions, that might be in order. This seems to fit the bill pretty well for small ones, though.

The script assumes that the current directory contains an install.rdf file, a directory named “chrome,” and directories named “content,” “skin,” and “locale.” It zips the latter three directories into a file named (in this case) r2.jar, shoves that jar file into the “chrome” directory, and then creates a zip of install.rdf and “chrome” with the xpi extension. It copies this up into the xpi directory from which I open xpis to install them.

Big Media Win for Firefox

February 26th, 2005 by daryl

I have a stack of 10 or so issues of Reader’s Digest on the back of my toilet. Last night, intrigued by a table-of-conetnts blurb about protecting your data, I flipped to a section called “RD Technology” and read, among others, the following recommendation:

Change Web Browsers
Viruses that enter your PC via Internet Explorer can do serious damage, says [an unidentified] Poor. He recommends you consider trying a free alternative such as Firefox, available at mozilla.org.

Explaining SQL

February 24th, 2005 by daryl

I’m currently reading High Performance MySQL as part of an effort to compare MySQL and PostgreSQL. The book has proven most informative so far. Rather than just giving the basics of how to use MySQL, which I’m very familiar with, it goes into enhancing query performance and tweaking the server configuration to maximize what MySQL can do for you. Having been introduced to MySQL the way I was — by just jumping in as sort of a n00b programmer with no clue what I was really doing — these are the sorts of things I never found time, gumption, or particular need to learn. Most of the programs I wrote scaled pretty well (or had no need to scale) without a lot of performance tweaking. But for Spread Firefox and for my new job, I have written and will be writing some much higher-end stuff with scalability to hundreds of thousands of users in mind. So I figured it was time to read up on some of the more advanced topics in MySQL. Chapter 5 of High Performance MySQL, it turns out, is the most useful piece of geek writing I can recall ever having read. This chapter alone is worth the $40 price tag on the book (it’s actually only $26.37 through Amazon).

I read about half the book yesterday but didn’t get a chance to apply any of the takeaways in a real life situation. Today, I was glancing at some comments on sfx and saw someone asking that we reinstate the “Top 5 blog posts” block. I didn’t know it had gone away. Sure enough, though, the header was there, but no content existed. So I checked the query, and when I ran it, I got a query error, which seemed odd, as it had been working just recently, and I hadn’t changed the query. Ah, but we changed database servers, and the newer one had a newer version of MySQL. My query stupidly used the “mod” keyword as a table alias, and when I fixed that, the query error went away. But the query, which has always taken awhile because it’s calculating ratings for potentially thousands of posts and ordering them to get the top 100 (which I later apply another little algorithm to to get the top 5), took long enough that I interrupted it and decided I’d see if I could find a way to optimize it. When I say it took long enough, I don’t mean that it took three seconds rather than .0002; I mean that I killed it after 10 or 20 seconds.

To get an idea of just how MySQL optimizes and runs a given query, you use the “explain” keyword followed by the query you want to investigate. For each table the query has to hit, explain displays several pieces of information. Probably the easiest to zoom in on and the one that’ll be the most impressive for this example is how many rows the optimizer estimates it’ll have to read in order to get the results. In the output below, you’ll see that the query will have to look at 5602 rows in the “node_mod” table (aliased to “mymod” and formerly to the problematic “mod”; this table contains a list of which of the site’s posts have been moderated by users). This is a full table scan (I can tell this by looking at the “type” value and seeing “ALL”), which isn’t very efficient. For the “node_mod_user” table (aliased to “u” and listing the ratings given by each user to site posts), the optimizer estimates that it’ll have to scan 27081 rows. Again, this is a full table scan, which is less efficient the more rows you have. And finally, the “node” table (which contains posts) has one reference per iteration of the query. Here’s the output from explain:

mysql> explain SELECT node.nid, node.title, FROM_UNIXTIME(created) as date,
mymod.value as val, count(*) as cnt, (mymod.value/count(*)) as rating
FROM node, node_mod as mymod, node_mod_users as u
WHERE node.nid=mymod.nid
AND node.nid=u.nid AND created >= (UNIX_TIMESTAMP(NOW()) - (86400 * 7)) AND promote != 1 AND type != 'image'
GROUP BY node.nid ORDER BY rating DESC, created DESC LIMIT 100 G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: mymod
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5602
        Extra: Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: u
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 27081
        Extra:
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: node
         type: eq_ref
possible_keys: PRIMARY,node_type,node_promote_status
          key: PRIMARY
      key_len: 4
          ref: spreadfirefox.mymod.nid
         rows: 1
        Extra: Using where
3 rows in set (0.01 sec)

The red flag this raised for me was that I shouldn’t have to do a full table scan on the nod_mod table. It turns out that I hadn’t added an index on this table for the nid field, and by doing so, I eliminate in my query the need to do a full table scan. Sure enough, I added the index, and the query returns almost instantly now (in .44 seconds rather than too many seconds to even bother waiting). Take a look at the new explain output below. Rather than doing a full table scan of 5602 rows, we’re using the new index, and it has a significant positive effect on performance.

mysql> explain SELECT node.nid, node.title, FROM_UNIXTIME(created) as date,
mymod.value as val, count(*) as cnt, (mymod.value/count(*)) as rating
FROM node, node_mod as mymod, node_mod_users as u
WHERE node.nid=mymod.nid
AND node.nid=u.nid AND created >= (UNIX_TIMESTAMP(NOW()) - (86400 * 7)) AND promote != 1 AND type != 'image'
GROUP BY node.nid ORDER BY rating DESC, created DESC LIMIT 100 G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: u
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 27079
        Extra: Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: node
         type: eq_ref
possible_keys: PRIMARY,node_type,node_promote_status
          key: PRIMARY
      key_len: 4
          ref: spreadfirefox.u.nid
         rows: 1
        Extra: Using where
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: mymod
         type: ref
possible_keys: nid
          key: nid
      key_len: 5
          ref: spreadfirefox.node.nid
         rows: 1
        Extra: Using where
3 rows in set (0.10 sec)

After making this change and starting to write this triumphant blog entry, it occurred to me to check and see if I had indexed the node_mod_users table, and it turned out that I hadn’t. When I added an index on nid, it increased performance even more, cutting my query time down to .10 seconds and resulting in the following output from explain:

mysql> explain SELECT node.nid, node.title, FROM_UNIXTIME(created) as date,
mymod.value as val, count(*) as cnt, (mymod.value/count(*)) as rating
FROM node, node_mod as mymod, node_mod_users as u
WHERE node.nid=mymod.nid
AND node.nid=u.nid AND created >= (UNIX_TIMESTAMP(NOW()) - (86400 * 7)) AND promote != 1 AND type != 'image'
GROUP BY node.nid ORDER BY rating DESC, created DESC LIMIT 100 G

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: mymod
         type: ALL
possible_keys: nid
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5604
        Extra: Using temporary; Using filesort
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: node
         type: eq_ref
possible_keys: PRIMARY,node_type,node_promote_status
          key: PRIMARY
      key_len: 4
          ref: spreadfirefox.mymod.nid
         rows: 1
        Extra: Using where
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: u
         type: ref
possible_keys: nid
          key: nid
      key_len: 5
          ref: spreadfirefox.node.nid
         rows: 5
        Extra: Using where; Using index
3 rows in set (0.00 sec)

Note that the optimizer is once again doing a table scan of the roughly 5600 rows of node_mod. This is because MySQL can use only one index for a given query. In this case, with the nid column indexed in both node_mod and node_mod_users, it chooses the better of two options and does a table scan of the table with 5600 rows rather than the one with 27081. That’s 4 - 5 times fewer rows to scan, and our performance increased by a factor of about 4 (from .44 seconds to .10). Makes sense, huh?

The lesson here is pretty obvious. If you’ve got a slow query, explain it to see exactly how MySQL is processing it. Explain can expose, among other things, careless indexing problems that can make a very real difference in how your program executes.

Prawnography and Firefox Exploitability

February 22nd, 2005 by daryl

A few months ago, I created the following bug report at the Mozilla project’s install of Bugzilla:

User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0
Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0

It’s possible to use XMLHttpRequest to retrieve the text from a remote javascript file and then to eval that text and execute the javascript within a local scope. This circumvents the need to sign remote scripts and can be done without enabling UniversalXPConnect. In theory, one would simply suggest that application developers be careful not to write code that would execute arbitrary remote javascript, but this doesn’t account for malicious coders who might make extensions available, for example, and use them to tamper with the users’ machines. It may be that this is a jslib issue and not a Gecko issue, but I wasn’t sure where else to report it.

Reproducible: Always
Steps to Reproduce:
1. Install jstest package (attached).
2. Edit xul.js (in zip file), replacing the second parameter to the “save()” call to a local file on your system (or to a file that doesn’t exist yet in a writable directory).
3. Place xul.js (in zip file) on a remote server.
4. Edit the button in jstest.xul within package so that the parameter to “execute()” in the “oncommand” parameter points to the file created in step 2.
5. Run the package and press the button.
Actual Results:
A file is written to the local path specified in the remote script containing the text sent as the first parameter to the remote “save()” function.

Expected Results:
No unsigned remote javascript should be able to perform certain actions, such as local file operations.

In plain English, it means that installing Firefox extensions can be dangerous if you’re not very careful about what you install. When you install an extension, you’re giving full control of your browser to the developer who wrote the extension. In most cases, this’ll work out just fine, as most people who write extensions are writing utilities that they find useful and wanted to make available to others. But there’s always the jerk who ruins a good thing. Later in the bug report, I go back and forth with a key developer about whether or not this is in fact a bug. He concludes that it’s not. In short, if you agree to install an extension, you agree to take whatever pain or pleasure comes with installing that extension, and it’s a bad idea to install untrusted extensions. And of course he’s right. The extension system has to have pretty much full privileges or else it’ll be rendered essentially useless. So the credibility of Firefox as a secure browser is in some ways in the hands of users, who are known for installing spyware on their systems through IE and can’t really be trusted to keep security in mind.

To illustrate the point, I’ve written a little test extension named Prawn (as in shrimp) that shows you prawnography on demand. The real life example, of course, would showcase pornography and would be more fully-featured than my extension. Prawn adds an item to your “Tools” menu named “Prawn me” that, when selected, spawns a new tab loaded with a random racy image from prawnography.net. The extension also has an annoying habit of popping up a window every 30 seconds or so. It’s ok to download and try my extension — I promise it doesn’t do anything truly malicious, and it shows the point pretty well, I think. If you happen to be a prawn fetishist and you see this great extension that gives you access to prawnography, you might carelessly download this extension and find yourself stuck with annoying popups. Moreover, if the popups don’t indicate that they’re associated with the Prawn extension, you might not be able to figure out how to make them stop, short of reinstalling Firefox (though all it in fact takes is uninstalling the extension).

The real dirty thing about my extension is that it doesn’t merely do a popup. It in fact downloads a remote text file and evaluates the code in that file as javascript. So a particularly sneaky developer could write an extension that, the first few days it’s loaded, does expected and harmless things but that begins after a while to do popups or other unsavory things (writing files to your system, for example, or sending cookies or information about your browsing habits back to a central server). This method renders it more difficult to associate the activities with the extension in question. My little Prawn extension effectively gives complete control of your browser to me. I could program it to close your browser upon startup so that you never even have the chance to uninstall it (unless you know what text files to edit by hand to do so). Can anybody see Microsoft covertly putting out a similar extension in order to frustrate Firefox users and drive them back to IE? The really scary thing is that because the extension executes remote code, I can change its behavior at any time I want without your having to modify your local copy; so it can start out as a friendly extension and morph into something ugly and destructive.

The moral here isn’t that Firefox is bad or insecure, though the argument could be made. I’ve spoken to Firefox developers who point out that the extensions manager instructs users not to install untrusted extensions, and I suppose that’s valid, though we all know that it’s absurd to trust users to follow instructions. (In spite of my warnings about not installing untrusted extensions, did you download and install mine? If so, shame on you. It really is safe, but what if somebody else wrote a similar blog posting with their own extension that actually turned out to be malicious?) Developers and advocates also point out that one of Firefox’s big strengths is that it doesn’t run ActiveX controls, which are responsible for most of the malware that’s out there. And that’s true and good. But if a similarly exploitable technology is built into Firefox, is it really that much better?

Well, I think it is. I’m a devoted Firefox user, and I encourage everybody I can to use the browser. But I also encourage them to be sensible about what extensions they add to Firefox. Theoretically, the extensions available at update.mozilla.org are safe, but I don’t know how much scrutiny is actually given to extensions before they’re added there. (There may be a great deal of scrutiny; I’m not saying there’s not; I’m just saying that I don’t know.) And I don’t know how much code review is done. Is it possible, I wonder, to submit and have approved a cool extension but then to go back and edit it without review a few months later so that it includes malicious code?

Questions like this are no doubt being asked as the Mozilla Foundation works even now on revamping update.mozilla.org, but they’re probably too technical and uninteresting to many, if not most, members of the growing pool of Firefox users. And debatably, they’re questions that users shouldn’t have to worry about. In an ideal world, you’d just install your browser and use it without looking back. The jerks out there who make malware will always find ways to thwart this ideal vision, I suspect. My advice, then, is to use Firefox (right now, it is safer than IE; if you don’t use Firefox, consider Opera or some other alternative). I also advocate spreading Firefox, an activity I’ve been engaged in for six months now. But don’t be blind to the shortcomings that the greatness of Firefox extensibility introduces. Try to verify that any extensions you install are safe. And whatever you do, if you need to browse prawnography, don’t use my extension to do so; you’ll find it most annoying, if (for now) technically harmless.

Delicious and Extispicious

February 17th, 2005 by daryl

If you haven’t heard of del.icio.us, chances are that you’re not missing much. It’s a bookmark management tool that appeared late last year and that promotes community or collaborative bookmarking, with the bookmarks stored remotely. Further, it’s a big of a shift in the approach to bookmarking: Rather than putting a link in a folder as we’re all used to doing, you apply tags to links, and you can apply as many tags as you want to. This makes for one-to-many categorization without the redundancy of bookmarking something many times, one instance per bookmark category. It also implicitly allows for tiered organization. For example, I’ve spent most of the day googling around for information about two major open source database management systems, postgresql and mysql. I’m trying to collect a whole bunch of data about both servers so that I can make a decision about which to use for a big project I’m working on. Because I got really tired of the bookmark interface and the pain it becomes to categorize things, I started tossing my links into my del.icio.us profile. All results I tagged “database.” Postgresql-specific links I also tagged “postgresql,” and mysql-specific links I additionally tagged “mysql.” Sites relevant to both databases (such as feature-comparison sites) I applied all three tags to.

So far, this probably seems very little different from regular old bookmarking except that the interface has changed. The beauty of it all comes together, though, when you consider the handy fact that you can get at your links via RSS, which can be read in a news reader, displayed as bookmarks in Firefox, parsed in a MediaWiki plugin for display in an article, and so on. By using del.icio.us to store and tag my bookmarks, I’m actually making them very portable. Del.icio.us’s RSS API is very simple and elegant in that it allows you by simply using a correctly-formatted URL to get only the subset of links you want to see. Here are some examples:

  • http://del.icio.us/rss/tag/database shows me an RSS feed of all links across the system tagged “database”
  • http://del.icio.us/rss/daryl/database shows me an RSS feed of just my links tagged “database”
  • http://del.icio.us/rss/daryl shows me an RSS feed of all of my links
  • http://del.icio.us/daryl/database shows me an HTML page of all my links tagged “database”
  • http://del.icio.us/daryl/postgresql shows me an HTML page of all my links tagged “postgresql”
  • http://del.icio.us/daryl shows me an HTML page of all my links

So del.icio.us provides not only an online interface for managing and viewing your bookmarks, but also an alternate format for the links that allows you to plug them into pretty much any RSS-enabled system you want to. This is very cool.

But, as I said at the beginning, if you’re not familiar with del.icio.us, you’re probably not missing much. Chances are that you’re bookmarking things and getting along just fine, and the minor shift in mechanism and presentation seems trivial. Even I felt this way until just today. I thought del.icio.us was sort of a pain to use and didn’t want to have to login to a site to get my bookmarks. But as I started combing through sites about postgresql and mysql and bookmarking them, I found the interface for categorizing the bookmarks to be cumbersome and irritating, and I began to think that I’d probably never even bother to go digging through the bookmarks to find the links. Or I’d have to double-bookmark things to categorize them into multiple applicable folders, and it’d all become very hairy to manage and use. So I tried using del.icio.us, and when you add the popup to your link bar in Firefox, it’s really much simpler to use than the bookmark interface. And when you happen to be a developer who can tweak posts in your MediaWiki extranet to consume RSS feeds and use them to display links, del.icio.us starts to look much more attractive. I’m a convert.

Extisp.icio.us is a nifty visual representation of your del.icio.us tags that changes the font size for tag listings to show which are your most oft-used tags. It has no real practical use, but it can be fun to compare your tags to those of friends and hardcore del.icio.us users (see for example the difference between a couple of my colleagues, one of whom is a reluctant user like me and one of whom is verging on being psychotic about tagging his links). You can see my tags here. Not surpirsingly, postgresql and database are the most prominent tags, with mysql coming in third place.

How Fast is Your Browser?

February 16th, 2005 by daryl

Want to optimize your browsing experience? Check out this pretty comprehensive set of browser speed tests targeting all of the major browsers and some minor ones on Linux, Mac, and PC. If you’re not into reading the tech specs and methodology, scroll down to the bottom for the conclusions. It turns out that Opera is a pretty darned fast browser. Although the author concludes that Mozilla and Firefox are optimized for Linux, it seems to me that Opera wins almost across the board, especially on Windows. Of course, Firefox is free, easily extended, and simple out of the box, so it’s still my browser of choice.

Incidentally, Firefox netted 25 million downloads in 100 days. About 110 days ago, when we on the Spread Firefox crew were trying to project a reasonable download count for 100 days, we landed on 10 million. Similarly, the NY Times campaign wound up raising something like six times what some of us thought we could reasonably expect. It’s amazing how many extra miles the Firefox community keeps going.