Предлагаю вашему вниманию перевод статьи Automatic Firefox Extension Updates.
Статья старенькая, но вся информация актуальна и по сей день.
Разработчики расширений Firefox конечно знают, что при распространении расширений через официальный store вы бесплатно получаете возможность автоматически обновлять свои расширения. Но что делать, если мы хотим сами хостить свое расширение на своем сайте? Как нам самим реализовать поддержку автоматических обновлений?
Подписывание расширений
Начиная с третьей версии Firefox все обновления расширений должны предоставляться по надежным каналам. Раз уж мы решили самостоятельно хостить свое расширение, у нас есть два варианта, чтобы выполнить это требование:
- Предоставлять обновления по защищенному (https) соединению
- Подписывать расширение электронной подписью
Первый вариант мы рассматривать не будем — в большинстве случаев это требует дополнительных затрат (надо купить SSL сертификат и иметь статичный IP (сам не понял, к чему это, но из песни слов не выкинешь [прим. перев.])) Цифровая подпись напротив — бесплатна, легка в использовании и быстро реализуема. Ну давайте уже научимся ею пользоваться!
Создаем пару приватный/публичный ключ
Первый шаг в подписывании нашего расширения заключается в создании пары приватного/публичного ключа. Mozilla предоставляет утилиту McCoy для этих целей. Не самая простая утилита в мире, так что ниже расписано как её готовить:
- идем на сайт McCoy и качаем подходящий пакет (есть версии для Windows, Linux и Mac OS X)
- распаковываем пакет в удобную нам директорию
- запускаем приложение. При первом запуске оно предложит создать master password для защиты ключей. Создание такого пароля крайне настойчиво рекомендуется! При каждом последующем запуске McCoy он будет спрашивать этот пароль.
- Приложение запущено, выбираем в меню Keys » Create New Key. Введите вменяемое имя своему ключу и нажмите Ok. Имейте в виду, даже если вы хотите хостить несколько расширений на своем сайте — вам достаточно будет одного ключа.
Ну что же, ключи созданы, теперь необходимо обновить манифест расширения.
Обновляем install.rdf
Предполагается, что вы знакомы с install.rdf, так что не будем тратить время на описание его структуры (если нет — вам сюда). Для примера я использую install.rdf из Toolbar Tutorial. Вот его исходный вариант:
<?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>
Нам надо добавить два элемента в этот манифест: em:updateURL
и em:updateKey
. Элемент em:updateURL
указывает на URL по которому лежит манифест обновления (update.rdf). Выглядит вот так:
<em:updateURL>http://www.example.com/update.rdf</em:updateURL>
Имейте в виду — вы не сможете разместить расширение в официальном store, если ваш манифест содержит этот элемент.
Следующий у нас em:updateKey
. Он просто содержит в себе публичный ключ. Чтобы получить его, откройте McCoy, сделайте правый клик на ключе, который вы создали ранее и выберите Copy Public Key в контекстном меню. После поместите ключ между открывающим и закрывающим тегами:
<em:updateKey>
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDW8qxAeURIMLnHjb
KrjR/uqnRsiomahNArMh3KqRLDDmRGCoO21fyHyh5kdgiEL+2Q+sNP
z+j5maIG4qePXp7BVp90QMqiGLvl+z4baDOqcNvErN0l8scd8EegXc
G7Ofa5Gc5oEU/gItIVR4k9AICyW2pJhe51UPa3UKXDS0v3TwIDAQAB
</em:updateKey>
Абракадабра. К счастью, Firefox достаточно умен и позволяет использовать пробелы в em:updateKey
элементе, что позволяет сделать install.rdf более читаемым (как показано выше, это уже отформатированный вариант). По умолчанию из McCoy копируется одна длинная строка.
После добавления этих двух элементов install.rdf начинает выглядет так:
<?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>
Мы завершили обновление манифеста нашего расширения! Обратите внимание — этот шаг необходимо сделать всего один раз. То есть при каждом следующем обновлении эти действия повторять не придется (если только вы не измените URL update.rdf или не поменяете ключ). Все, на этом этапе уже можно паковать расширение для дальнейшей дистрибуции (раздавать пользователям).
Создаем update.rdf
Раз уж мы завершили с самим расширением, самое время создать манифест обновления. Этот файл (update.rdf) будет жить у нас на сервере и, собственно, именно он определяет, что увидит пользователь при проверке наличия обновлений. Давайте начнем с того, что взглянем сразу на конечный вариант файла, который мы собираемся создать:
<?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>
Давайте пробежимся построчно и обсудим, что тут происходит. Во первых, мы имеем стандартный XML заголовок с последующим r:RDF элементом, который и говорит нам о том, что перед нами RDF (Resource Description Framework) файл. Нас в основном интересует элемент r:Description. Вы должны иметь по одному элементу на каждое расширение, которое описываете в update.rdf.
(Да, да, в одном update.rdf можно описывать обновления множества расширений, Extension Versioning, Update and Compatibility [прим. перевод.])
Далее, первое, что мы должны прописать — это аттрибут about
. Часть urn:mozilla:extension
обязательна, далее следует GUID вашего расширения. В нашем случае GUID такой: tuttoolbar@borngeek.com. Имейте в виду — если у вас не email-style GUID ( а что то вроде d4373b50-43b3-11de-8a39-0800200c9a66), то его надо заключить в фигурные скобки: {d4373b50-43b3-11de-8a39-0800200c9a66}
.
После нескольких дочерних элементов (updates
, r:Seq
, r:li
, и еще одного r:Description
) остановимся на элементе version
. Это версия вашего расширения, в нашем случае 1.0.2
.
Далее у нас идет информация о приложении, для которого предназначено наше расширение (Firefox). У нас есть targetApplication
элемент, заключенный в r:Description
и содержащий крайне важный id
элемент. Значение этого элемента — GUID Firefox-а.
(Сразу видно, басурмане писали. Коротко — у каждого target есть свой GUID — у Firefox-а, у Thunderbird- а, у Firefox for Android, у всех разные. Идем вот сюда, выбираем приложение, под которым работает наше расширение и копируем его GUID. Тут можно взглянуть на пример update.rdf для нескольких targets [прим. перевод.])
Далее следуют знакомые нам minVersion
и maxVersion
элементы, которые соответственно определяют минимальную и максимальную версии Firefox-а (или иного target-а), на работу в которых рассчитано расширение. Очень важно, чтобы эти значения совпадали с указанными в install.rdf.
Следующим у нас идет updateLink
элемент. В нем указывается URL самого расширения (т.е. xpi файла). Убедитесь в том, что URL указывает на соответствующий файл, особенно если вы поддерживаете и даете скачать более старые версии расширения.
Ну и в конце нас ждет updateHash
элемент. Этот элемент содержит sha1, sha256, sha384, или sha512 хэш нашего расширения (то есть xpi файла). Я предпочитаю sha256, поскольку были проблемы с обратной совместимостью для sha384 и sha512 (см. bug 383390 (пофиксено все уже давно). Если вы на Линуксе — у вас уже есть все необходимое для генерации sha. Пользователи Windows могут скачать соответствующую утилиту (я использую sha256sum), например, тут: Cygwin. Для того, чтобы получить хэш, наберите что-то вроде этого в терминале:
sha256sum tuttoolbar_1_0_2.xpi
Вывод будет выглядеть примерно так:
c22ad513c1243959a6d8e6b3cfad18a2a9141306f0165da6b05b008b2042e502 *tuttoolbar.xpi
Шестнадцатеричная строка (все что до пробела) — это то, что вам надо положить в updateHash
с указанием типа шифрования. Выглядеть это должно примерно так:
<updateHash>
sha256:c22ad513c1243959a6d8e6b3cfad18a2a9141306f0165da6b05b008b2042e502
</updateHash>
Собственно все! Сохраните его как девелоперскую версию! Я лично использую название update.rdf.dev. Почему надо держать отдельную версию для девелопмента? Потому что когда вы подпишите этот манифест (а мы ведь рассматриваем вариант с подписью [прим. перев.]) его содержимое станет немного малочитаемым и малопригодным для дальнейшего редактирования. Так что лучше держать отдельно девелоперскую версию, а когда надо — подписывать её копию.
Подписываем манифест
Для того, чтобы подписать манифест, последовательно выполните следующие несложные действия:
- скопируйте девелоперскую версию манифеста и назовите её update.rdf. Именно этот файл мы и будем подписывать
- запустите McCoy если он еще не запущен
- выделите в нем ключ, которым вы собираетесь подписать и выберите в меню Update » Sign Update Manifest
- в открывшемся меню выберите update.rdf, который мы только что создали, и жмите Open
Будет выглядеть так, будто ничего не происходит, но это не так! Есть у меня такая претензия к McCoy — он ничего не говорит по завершении работы. Но если вы откроете манифест, то можете заметить, что он немного изменился. Собственно на этом работа над расширением завершается — пришло время загружать файлы на сервер.
Хостим update.rdf
Перед тем, как залить файлы, мы должны убедиться в том, что наш сервер готов хостить rdf и xpi файлы. На Apache мы можем сделать это через правила .htaccess (не знаю как это работает в IIS или TomCat, имейте в виду — это инструкция только для Apache). Я обычно кладу эти правила в .htaccess корня сайта — на тот случай, если мне захочется поперемещать xpi и rdf. Правила простые:
AddType application/x-xpinstall .xpi
AddType text/xml .rdf
(сейчас-то уже модно nginx, под него делаем так:
types {
application/x-xpinstall xpi;
text/xml xml, rdf;
}
и кладем это либо в общий /etc/nginx/mime.types
, либо в конфиг нашего сервера. [прим. перевод.])
Это необходимо для правильной отдачи файлов сервером. Это очень важный момент! В противном случае ваше расширение не будет установлено, также не будут работать обновления. Также имейте в виду: если вы используете какую-либо CMS (типа WordPress), то лучше на всякий случай эти правила разместить в корне сайта.
После того, как все прописано, можно залить наш xpi и update.rdf по соответствующим адресам. Update.rdf должен лежать там, куда указывает install.rdf расширения (тег em:updateURL
файла install.rdf расширения). Само расширение (.xpi) должно лежать там, куда указывает update.rdf (тег updateLink
). Постарайтесь не запутаться.
На этом все! Хоть процедура слегка запутанна на первый раз — все достаточно просто.
Чистого кода!
Автор: gonzazoid