Как меня назвали параноиком и что из этого вышло

в 15:09, , рубрики: extension, Google Chrome, javascript, opera, Opera 12, метки: , , ,

Когда начались утечки баз паролей/хэшей с разных форумов и соц. сетей я начал задумываться о том как и где хранить свои пароли, что бы их можно было быстро менять и при этом не забыть. Так я наткнулся на программу KeePass Password Safe, о её возможностях я расписывать не буду так как на Хабре статей предостаточно и тематика данной статьи не о его возможностях. По мере эксплуатации KeePass обрастал плагинами, особенно для связки с браузерами, LastPass был отброшен так как не хотелось где-то «у дяди» хранить пароли (особенно к рабочим системам), да и не факт, что их от туда тоже не сольют.

Сначала для Firefox было расширение KeeFox, но так как через KeePassRPC (плагин KeePass) работает только оно — то сейчас это расширение давно отключено и не используется. Затем было найдено расширение PassIFox (работает через плагин KeePass — KeePassHttp) с ним же сразу и ChromeIPass — а вот для Opera 11, Opera 12 (здесь и в дальнейшем подразумевается на движке Presto и это мой основной браузер) хорошей интеграции не было, был только UserJS-скрипт добавляющий в заголовок окна адрес страницы, было даже создано расширение делающее тоже самое — для того чтобы KeePass мог определить адрес для которого нужно искать логин и пароль для подстановки по Ctrl+Alt+A (стандартный хот-кей авто-заполнения KeePass). Так как современных навыков по JavaScript у меня нет, я попытал счастья на OperaFan с просьбой написать/переделать расширение для Opera — где меня и назвали параноиком. Продолжение истории о портировании ChromeIPass в Opera 12 (без сильно технических деталей) под катом.

Важно

Сразу оговорюсь, что не всё мне удалось портировать, но для меня получилось довольно работоспособно с учётом отсутствия альтернативы. Прошу не пинать за ляпы и ошибки реализации. Если кто что подскажет, поправит буду благодарен.
Понимаю, что Opera на движке Presto — это уже труп, но как писал выше — это мой основной браузер и пока я не вижу ему замены в плане потребления памяти, скорости и возможности допилить функционал. Использую последнюю сборку Opera AC с допиленными под себя плюшками.

Первый подход к снаряду

Для портирования в Opera было выбрано расширение ChromeIPass так как посмотрев во внутрь его и расширения LastPass, RoboForm Lite и увидев приблизительно похожие вызовы для Оперы и Хрома — я сделал предположение что они наиболее близки (со временем я понял, что сильно ошибался).
Первым пациентом была выбрана на то время версия ChromeIPass 1.0.7. Не было функционала запоминания паролей, скудно малые познания о написании расширений и их взаимодействии с браузером, мало свободного времени, расширение LastPass так же как и RoboForm были написаны универсальными сразу под Opera,Chrome и Safari и имели огромные размеры. Была простая замена chrome.extension.sendMessage на opera.extension.postMessage с естественным «epic fail». В общем предприняв несколько попыток я так и забросил портирование, хотя скриптов было мало и я был готов смириться с добавлением паролей через сам KeePass.

Второй подход к снаряду

Два месяца назад я обнаружил, что версия ChromeIPass уже 2.6.6 и в нём появился функционал запоминания паролей и ещё ряд плюшек. И оно даже без каких либо изменений работает в Opera (на движке blink), подсунув в режиме разработчика, потом можно и конвертнуть в NEX.
В этот раз было принято решение однозначно добиться рабочего результата. Основательно почитав о взаимодействии Injected script, Background script и Popup script в Opera, погуглив, глянув в другие расширения, облазив уже закрытые форум и блоги на My Opera (пришлось даже копаться в Web Archive и кэше гугля) — я приступил к работе.

Был создан config.xml, переложены файлы в нужные директории, произведена замена chrome.extension.sendMessage на opera.extension.postMessage (в некоторых местах на e.source.postMessage где нужно было отвечать на событие — а не просто отсылать, e — это событие, т.к. в ChromeIPass есть объект event определённый в event.js).

Переделаны все вызовы с использованием механизма callback в Chrome на просто отсылку событий и добавлены реакции на эти события в обработчиках событий, там где эти callback-функции определены.

Переделаны chrome.tabs.*.addListener на opera.extension.tabs.* (для Оперы события обязательно в нижнем регистре иначе не работает) в init.js.
opera.extension.tabs.onupdate в Opera (chrome.tabs.onUpdated.addListener в Chrome) не отрабатывает.

Включена отладка (вывод сообщений в консоль) где была, добавление своих отладочных сообщений, что бы понять что и как и с чем взаимодействует.

Добавлено новое расширение в режиме разработчика в отдельно установленую оперу и запущен Dragonfly.

Очень много полезного было взято из постов и блога пользователя Joel Spadin aka spadija на my.opera.com и его расширений tab vault, autostack.

Для начала проверил как расширение работает с KeePass, в этой части почти ничего не переделывал.т.к. работает «на ура».

Было сделано внедрение CSS (было тут), как потом обнаружил тот же способ используется в документации

Потом была борьба за последовательность загрузки Injected scripts (в ChromeIPass их три: основной и два переделанных jQuery и jQuery UI). В Хроме с этим полегче чем в Опере.
Решение было найдено на форуме my.opera (уже недоступно) и для jQuery (в ChromeIPass jQuery переименован в cIPJQ, что бы не было конфликтов с подгружаемым jQuery с сайтов) был добавлен код его инициализации в init.js, что бы не вываливал ошибок и работал

var cIPJQ;
if (typeof cIPJQ === 'undefined') {
  if (typeof window.cIPJQ !== 'undefined') {
    cIPJQ = window.cIPJQ.noConflict(true);
  } else {
    opera.postError(['Error: could not load jQuery']);
  }
}

Наступил на грабли, что opera.extension.bgProcess это объект window — а не сам background script.

Переделана работа с заменой адресов для popup, решение было взято отсюда, пока ещё есть в кэше гугля.

А вот с портами пришлось повозиться дольше всего. Так если сделать передачу порта от popup script в injected script и обратно (как указано в документации) напрочь перестаёт работать e.source.postMessage на события от popup script в background script. Пришлось создавать ещё один MessageChannel для работы popup script c background script. И «понатыкивать» закрытия этих всех MessageChannel, т.к. есть проблемы что при создании табов функция opera.extension.tabs.getSelected() возвращает таб с port=null.

Для внедрения картинок сначала попробовал opera.extension.getFile(), но она оказалась асинхронной, по-этому загрузку картинок реализовал так же как и загрузку CSS (через XMLHttpRequest) и при внедрении стилей производил замену на base64 закодированные картинки.

Собственно само расширение:
rghost, sendspace
с не закомментированными postError
rghost, sendspace

Ограничения

  • Если сменить порт для подключения к KeePassHttp то нужно править <access origin="http://localhost:19455"/> в config.xml из-за ограничений в спецификации по которой реализован контроль сетевого доступа расширений в Опере.
  • Не работает перехват HTTP авторизации, т.к. в Опере просто нет такого механизма перехвата.
  • В консоли много ошибок «Unknown pseudo class» с указанием на атрибут CSS ":first". По крайней мере в Dragonfly их было просто масса.
  • Иногда приходиться обновлять страницу из-за проблем с портами, мне так и не удалось выяснить почему при создании новых табов значение port=null.
  • Не отрабатывает alert() в background script, при этом ни ошибок ничего.
  • Не работает копирование пароля в буфер обмена из генератора паролей, сильно не копался пока. нужно курить спецификацию

Спасибо за внимание!

Автор: SkyRE

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js