📜 ⬆️ ⬇️

Automatically update Firefox extensions

I bring to your attention the translation of the article Automatic Firefox Extension Updates .

The article is old, but all the information is relevant to this day.

The developers of Firefox extensions of course know that when distributing extensions through the official store, you get the opportunity to automatically update your extensions for free. But what if we want to host our extension on our website ourselves? How can we implement automatic update support?

Signing Extensions


Starting with the third version of Firefox, all extensions updates should be provided via secure channels. Since we decided to host our extension ourselves, we have two options to fulfill this requirement:
')

We will not consider the first option - in most cases it requires additional expenses (you need to buy an SSL certificate and have a static IP (I did not understand what it is for, but you cannot throw out words from the song )) Digital signature opposite - is free, easy to use and quick to implement. Well, let's learn how to use it!

Create a private / public key pair


The first step in signing our extension is to create a private / public key pair. Mozilla provides the McCoy utility for this purpose. Not the easiest utility in the world, so below is how to prepare it:


Well, the keys are created, now you need to update the extension manifest.

Update install.rdf


It is assumed that you are familiar with install.rdf, so we will not waste time on the description of its structure (if not - you are here ). For example, I use install.rdf from the Toolbar Tutorial . Here is its original version:

<?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>tuttoolbar@borngeek.com</em:id> <em:name>Tutorial Toolbar</em:name> <em:type>2</em:type> <em:version>1.0</em:version> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>4.0</em:minVersion> <em:maxVersion>30.*</em:maxVersion> </Description> </em:targetApplication> <em:creator>Jonah Bishop</em:creator> <em:description>An example toolbar extension.</em:description> <em:homepageURL>https://www.borngeek.com/firefox/</em:homepageURL> </Description> </RDF> 

We need to add two elements to this manifest: em:updateURL and em:updateKey . The em:updateURL points to the URL for the update manifest (update.rdf). It looks like this:

 <em:updateURL>http://www.example.com/update.rdf</em:updateURL> 

Keep in mind - you will not be able to place the extension in the official store if your manifest contains this element.

The following is our em:updateKey . It simply contains the public key. To get it, open McCoy, right-click on the key you created earlier and select Copy Public Key from the context menu. Then place the key between the opening and closing tags:

 <em:updateKey> MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDW8qxAeURIMLnHjb KrjR/uqnRsiomahNArMh3KqRLDDmRGCoO21fyHyh5kdgiEL+2Q+sNP z+j5maIG4qePXp7BVp90QMqiGLvl+z4baDOqcNvErN0l8scd8EegXc G7Ofa5Gc5oEU/gItIVR4k9AICyW2pJhe51UPa3UKXDS0v3TwIDAQAB </em:updateKey> 

Abracadabra. Fortunately, Firefox is smart enough to use spaces in the em:updateKey element, which makes install.rdf more readable (as shown above, this is already a formatted version). By default, one long line is copied from McCoy.

After adding these two elements, install.rdf begins to look like this:

 <?xml version="1.0"?> <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> <Description about="urn:mozilla:install-manifest"> <em:id>tuttoolbar@borngeek.com</em:id> <em:name>Tutorial Toolbar</em:name> <em:type>2</em:type> <em:version>1.0</em:version> <em:targetApplication> <Description> <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <em:minVersion>4.0</em:minVersion> <em:maxVersion>30.*</em:maxVersion> </Description> </em:targetApplication> <em:creator>Jonah Bishop</em:creator> <em:description>An example toolbar extension.</em:description> <em:homepageURL>https://www.borngeek.com/firefox/</em:homepageURL> <em:updateURL>http://www.example.com/update.rdf</em:updateURL> <em:updateKey> MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDW8qxAeURIMLnHjb KrjR/uqnRsiomahNArMh3KqRLDDmRGCoO21fyHyh5kdgiEL+2Q+sNP z+j5maIG4qePXp7BVp90QMqiGLvl+z4baDOqcNvErN0l8scd8EegXc G7Ofa5Gc5oEU/gItIVR4k9AICyW2pJhe51UPa3UKXDS0v3TwIDAQAB </em:updateKey> </Description> </RDF> 

We have completed the update of our expansion manifest! Please note - this step needs to be done only once. That is, with each subsequent update these actions will not have to be repeated (unless you change the URL update.rdf or change the key). Everything, at this stage it is already possible to pack an extension for further distribution (distribute to users).

Create update.rdf


Since we're done with the extension itself, it's time to create an update manifest. This file (update.rdf) will live on our server and, in fact, it determines what the user will see when checking for updates. Let's start by looking at the final version of the file we are going to create:

 <?xml version="1.0"?> <r:RDF xmlns:r="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.mozilla.org/2004/em-rdf#"> <r:Description about="urn:mozilla:extension:tuttoolbar@borngeek.com"> <updates> <r:Seq> <r:li> <r:Description> <version>1.0.2</version> <targetApplication> <r:Description> <id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</id> <minVersion>4.0</minVersion> <maxVersion>30.*</maxVersion> <updateLink>http://www.example.com/downloads/tuttoolbar_1_0_2.xpi</updateLink> <updateHash> sha256:c22ad513c1243959a6d8e6b3cfad18a2a9141306f0165da6b05b008b2042e502 </updateHash> </r:Description> </targetApplication> </r:Description> </r:li> </r:Seq> </updates> </r:Description> </r:RDF> 

Let's go over line by line and discuss what's going on here. First, we have a standard XML header followed by an r: RDF element, which tells us that we have an RDF (Resource Description Framework) file. We are mainly interested in the element r: Description. You must have one element for each extension described in update.rdf.

( Yes, yes, in one update.rdf it is possible to describe updates of multiple extensions, Extension Versioning, Update and Compatibility [comment. Translation.] )

Further, the first thing we need to register is the about attribute. The urn:mozilla:extension required, followed by the GUID of your extension. In our case, the GUID is: tuttoolbar@borngeek.com. Keep in mind - if you do not have email-style GUID (and something like d4373b50-43b3-11de-8a39-0800200c9a66), then it should be enclosed in braces: {d4373b50-43b3-11de-8a39-0800200c9a66} .

After several child elements ( updates , r:Seq , r:li , and one more r:Description ) we r:Description focus on the version element. This is the version of your extension, in our case 1.0.2 .

Next we have information about the application for which our extension is intended (Firefox). We have a targetApplication element enclosed in r:Description and containing the extremely important id element. The value of this element is the Firefox GUID.

( Immediately it’s clear that they wrote to the bassurman. In short, each target has its own GUID — Firefox, Thunderbird, and Firefox for Android, everyone’s different. Go here , choose the application under which our extension works and copy it GUID. Here you can take a look at the update.rdf example for several targets [comment. Translation]

This is followed by the familiar minVersion and maxVersion elements, which respectively determine the minimum and maximum versions of Firefox (or another target) , for which the extension is calculated. It is very important that these values ​​coincide with those specified in install.rdf.

Next we have the updateLink element. It indicates the URL of the extension itself (i.e., the xpi file). Make sure that the URL points to the appropriate file, especially if you support and allow older versions of the extension to download.

Well, in the end we are waiting for the updateHash element. This element contains the sha1, sha256, sha384, or sha512 hash of our extension (i.e., xpi file). I prefer sha256, because there were backward compatibility problems for sha384 and sha512 (see bug 383390 ( everything has been fixed for a long time ). If you are on Linux, you already have everything you need to generate sha. Windows users can download the corresponding utility (I use sha256sum), for example, here: Cygwin . To get a hash, type something like this in the terminal:

 sha256sum tuttoolbar_1_0_2.xpi 

The output will look something like this:

 c22ad513c1243959a6d8e6b3cfad18a2a9141306f0165da6b05b008b2042e502 *tuttoolbar.xpi 

The hexadecimal string (all that is up to the space) is what you need to put in updateHash indicating the type of encryption. It should look something like this:

 <updateHash> sha256:c22ad513c1243959a6d8e6b3cfad18a2a9141306f0165da6b05b008b2042e502 </updateHash> 

Actually everything! Save it as a developer version! I personally use the name update.rdf.dev. Why is it necessary to keep a separate version for development? Because when you sign this manifest ( and we are considering a variant with the signature [comment. Of translation.] ) Its contents will become a little unreadable and unsuitable for further editing. So it’s better to keep the developer version separate and, when necessary, to sign a copy of it.

We sign the manifesto


In order to sign the manifest, follow these simple steps:


It will look like nothing is happening, but it is not! I have such a claim to McCoy - he says nothing at the end of the work. But if you open the manifesto, you may notice that it has changed a little. Actually on this work on the extension is completed - it's time to upload files to the server.

Host update.rdf


Before uploading files, we need to make sure that our server is ready to host rdf and xpi files. On Apache, we can do this through .htaccess rules (I don’t know how it works in IIS or TomCat, keep in mind - this is an Apache instruction only). I usually put these rules in the .htaccess site root - in case I want to move xpi and rdf. The rules are simple:

 AddType application/x-xpinstall .xpi AddType text/xml .rdf 

( now it is already fashionable nginx, under it we do this:

 types { application/x-xpinstall xpi; text/xml xml, rdf; } 

and put it either in the general /etc/nginx/mime.types , or in the configuration of our server. [approx. translation.] )

This is necessary for the correct return of files by the server. This is a very important point! Otherwise, your extension will not be installed, updates will not work either. Also keep in mind: if you use any CMS (like WordPress), then it is better to place these rules in the root of the site just in case.

After everything is spelled out, you can fill in our xpi and update.rdf at the appropriate addresses. Update.rdf should be located where the install.rdf extension points ( em:updateURL tag of the em:updateURL install.rdf file). The extension itself (.xpi) must be placed where update.rdf points ( updateLink tag). Try not to get confused.

That's all! Although the procedure is a bit confusing for the first time - everything is quite simple.

Clean code!

Source: https://habr.com/ru/post/279063/


All Articles