Данная тема (заметка) посвящена восстановлению настроек веб-браузера Mozilla Firefox (версия 115.9.1 под GNU/Linux) после повреждения профиля.
Казалось бы ничего не предвещало беду. Где-то за сутки до происшествия, копаясь в настройках FF я заметил, надпись
Your stored cookies, site data, and cache are currently using 1.2 GB of disk space.
Но не придал этому особого значения, да и не было тогда у меня на это времени.
FF как обычно был прибит через pkill, с расчетом на последующее автовосстановленние сессии и вкладок.
По прошествии суток при запуске помимо диалога автовосстановленния вкладок FF показал вкладки, обычно сопутствующие первому запуску после установки. После перезапуска FF «забыл» старые вкладки (что в принципе ожидаемо), но также потерял кастомизации UI, и поотваливались аддоны (пометились как несовместимые с текущей версией FF или что-то в этом роде). На третий перезапуск аддоны вовсе исчезли из списка установленных. Что-то явно шло не так.
Быстрый осмотр показал, что подозрительных сообщений типа ошибок ext4fs в выводе dmesg нет, однако на разделе, где лежит профиль осталось всего 28MB, что предположительно и привело к повреждению файлов профиля.
После расчистки свободного места было выяснено, что все настройки about:config сбросились на default, в частности xpinstall.signatures.required, что стало причиной отвала аддонов, и toolkit.legacyUserProfileCustomizations.stylesheets, из-за чего отключился userChrome.css.
Поскольку список аддонов about:addons был пуст, я попробовал установить их заново, однако столкнулся с тем, что FF «забыл» и их настройки тоже. Ситуация несколько напоминал применение процедуры «Refresh», но ее никто явно не вызывал, кроме того, судя по документации в этом случае FF создает бэкап профиля в каталоге ~/Desktop (впрочем в условиях окончания места в $HOME он бы в любом случае не смог бы создать бэкап).
Доки по «Refresh» в интернетах приводили инструкции по востановлению bookmarks, история и прочих несущественных настроек, что мне было бесполезно, т.к. основную ценность представляли настройки аддонов, а букмарки как раз таки не пострадали в ходе инцидента.
В ходе изучения источников в интернетах и контента профиля выяснилось следующее:
Настройки аддонов хранятся по путям:
<profile_path>/storage/default/moz-extension+++<addon_install_uuid>/
<profile_path>/storage/default/moz-extension+++<addon_install_uuid>^userContextId=<container_id>/
<profile path> - каталог профиля;addon_install_uuid - идентификатор инсталляции аддона (internal uuid), который не следует путать постоянным ID аддона (Extension ID);container_id - идентификатор FF-контейнера.Внутри этих каталогов среди прочего находится подкаталог idb где лежит sqlite БД с данными в формате Firefox IndexedDB. Т.е. БД можно прочитать через sqlite, но данные внутри в основном в формате key-value, где key - машиночитаемая строка, а value - бинарное значение (BLOB) в недокументированном формате, специфичном для FF.
В каталоге профиля FF находится файл addons.json, в котором содержится список установленных аддонов: там метаданные включая extension ID, но без internal uuid.
В настройке extensions.webextensions.uuids (в about:config, также можно изменить напрямую через pref.js в каталоге профиля) содержится список в формате key-value, где key это что-то из метаданных аддона (название, либо extension id), а value - internal uuid. Посмотреть связь между extension id и internal uuid можно также через about:debugging#/runtime/this-firefox
В моем случае файл addons.json был пуст (из-за чего было пусто в about:addons), а опция extensions.webextensions.uuids хотя и содержала полный список установленных до инцидента аддонов, но internal uuid, не соответствовал каталогам в <profile_path>/storage/default/ (как так получилось, и что это за «левые» internal uuid, мне выяснить не удалось). Соответствено после установки аддона в extensions.webextensions.uuids генерируется новый uuid (и создается каталог в <profile_path>/storage/default/), а настройки не подхватываются.
Таким образом задача восстановления работы аддонов сводилась к тому, чтобы:
- установить все аддоны заново, причем на ту же версию, что использовалась ранее;
- прочитать настройки из Firefox IndexedDB;
- определить к какому аддону они относятся;
- заменить internal uuid в
extensions.webextensions.uuidsна uuid из имени каталога на файловой системе для каждого аддона.
Источники в интернетах также упоминают, что internal uuid может содержаться в sqlite БД (в человекочитаемом виде), и их тоже следует заменить, однако я этот шаг опустил - и без этого пока работает.
В принципе Firefox IndexedDB можно читать средствами самого FF, но это относится к тем данным (локальное хранилище данных веб-сайтов и аддонов), которые «видит» сам FF, а не к произвольному файлу БД.
В интернетах есть online конверторы, но степень их работоспособности невысокая.
В обсуждениях на stackoverflow нашелся проект moz-idb-edit. Это приложение на Python, позволяющее читать данные аддонов и веб-сайтов из IndexedDB прямо из файлов профиля.
Пример запуска:
moz-idb-edit --profile ~/.mozilla/firefox/abc123.default/ read --extension 'foo'
foo это ключ из списка extensions.webextensions.uuids.Иными словами, чтобы прочитать БД из каталога
<profile_path>/storage/default/moz-extension+++<internall_uuid>^userContextId=<context_id>/idb/ нужно временно добавить в extensions.webextensions.uuids пару "foo":"<internall_uuid>" и выполнить команду приведенную выше. В данном случае подставляется context_id по умолчанию (4294967295). Для указания иного context_id нужно дополнительно указать параметр --userctx.Итого:
- настройки всех аддонов были найдены и восстановлены;
userChrome.cssи FF-контейнеры не пострадали;- основные настройки
about:configвосстановлены по памяти.
Осмотр объема storage в «Cookies and Site Data» показал, что топ 3 веб-сайта это:
- wildberries.ru (около 500MB)
- telegram (242MB)
- whatsapp (около 50 MB).
Из них как persistent помечены только данные whatsapp, т.е., если верить комментарию в настройках, FF должен удалять non-persistent при недостатке места. Но что-то ему помешало.
По-видимом придется организовать выборочный бэкап профиля для избежания таких ситуаций (и заодно сессии сохранять вместо глючного TabSessionManager). Но это уже тема дальнейшего исследования.


