Процедура нотаризации Electron приложения для macOS 10.14.5

С выходом macOS 10.14.5, Apple добавила обязательную процедуру нотаризации (Notarization process) приложений перед их распространением. Что это и какие сложности возникли с этим обновлением при разработке на Electron.js я и хотел бы рассказать.

Введение

Спустя 2 года после бума Electron.js, все горячие холивары о том насколько он плох и зачем нужен — затихли. Давайте не будем разжигать их заново в комментариях. Спасибо.

На нашем проекте используется electron-builder для сборки приложения, но и для electron-packager эта процедура будет примерно аналогична.

Сам проект представляет из себя лаунчер для облачного гейминга, через который запускается нативный клиент для доступа к удаленному компьютеру.

Подписание приложения c electron-builder не выглядит сложным, но для полноты картины, я в кратце расскажу и об этой процедуре. Если у вас нет проблем с подписанием приложения, можете пропустить эту главу.

Подписание приложения

Для подписания приложения нам необходимо экспортировать сертификаты из личного кабинета разработчика Apple. Нам потребуются:

  • Developer ID Application
  • Developer ID Installer
  • *3rd Party Mac Developer Application и 3rd Party Mac Developer Installer (Если планируется публиковать приложение в AppStore)

Сертификат Developer ID Installer выпускается под определенное приложение, для этого необходим bundleID. У electron-builder он задается параметром «appId» в package.json

Сертификаты необходимо собрать в единый файл. Для этого добавляем их в keychain (2 клика по сертификату).
Затем переходим в keychain, выбираем нужные сертификаты и в контекстном меню нажимаем «export items». После экcпорта мы получаем один файл с расширением .p12.

После полученного файла сертификата, добавляем следующие записи в переменные окружения

  • CSC_LINK (путь до файла сертификата .p12)
  • CSC_KEY_PASSWORD (пароль доступа к сертификату)

Если не добавлять эти переменные, то сборщик будет автоматически искать подходящие ключи в хранилище keychain. Добавление этих записей, позволяет точно определить сертификаты, которые вы хотите использовать для подписи.

После этих операций, вы можете запускать процесс сборки и всё должно пройти гладко.

Гладко это работало до выхода macOS 10.14.5….

Что изменилось с выходом macOS 10.14.5

Небольшое отступление. Выполняя ночью последние работы над новым патчем, решил оставить сборку продакшн версии на утро. Заметив, что пришло обновление на macOS запустил его и пошел спать.

На следующее утро с удивлением увидел, что сборка падает от незнакомой ошибки в момент подписания приложения — «Unnotarized Developer ID».

Не откладывай на завтра то, что можно сделать сегодня. Бенджамин Франклин

Суть проблемы

Начиная с macOS 10.14.5, Apple ввела обязательную процедуру нотаризации. Первая статья Apple об этом была в 2018 году, но именно с этим обновлением эта процедура стала обязательной. Как она выглядит.

Вы собираете приложение -> отправляете его на сервер Apple -> Apple заверяет его -> Возвращает статус успешного заверения -> Выполняется команда установки штампа заверения.

Для разработчиков на Xcode необходимо просто поставить галочку о нотаризации

Так же процесс нотаризации собранного приложения можно выполнить командой в терминале.

$ xcrun altool --notarize-app --primary-bundle-id "com.example.ote.zip" --username "AC_USERNAME" --password "@keychain:AC_PASSWORD" --file OvernightTextEditor_11.6.8.zip

  • primary-bundle-id — bundleID приложения
  • username — логин пользователя на developer.apple.com
  • password — «app-specific password». Его можно создать в личном кабинете appleid.apple.com под учеткой разработчика.

Если не выполнить процедуру нотаризации, то при попытке пользователя установить приложение, вылетает окошко с ошибкой. За проверку на безопасность приложения отвечает gatekeeper. Именно он и ломал сборку приложения на electron-builder.

Как выглядел процесс сборки electron-builder

После сборки приложения в .app файл, с помощью утилиты electron-osx-sign происходило подписание приложения. После подписания сертификатом запускался процесс проверки приложения gatekepper’ом. Но с выходом обновления gatekeeper стал проверять и корректную нотаризацию приложения, это и не давало успешно завершить процедуру подписания приложения.

Патч для возможности нотаризации

Github пользователь Kallin довольно оперативно предложил коммит решения, с добавлением двух новых параметров в настройки. Первый это «gatekeeperAssess» — отключает валидацию сборки после подписания и второй «sign» — который отключает подписание сертификатом установочного файла(dmg). Данный коммит вошел в релиз electron-builder 20.43.0.

Для самого процесса нотаризации у electron-userland есть модуль electron-notarize, который выполняет эту задачу, нужно лишь написать небольшой скрипт и запустить его, используя хук afterSign.

Процесс подписания и нотаризации приложения

Первоначально нужно проверить, что у вас установлен electron-builder версии >=20.43.0 и установить пакет electron-notarize.

В переменные окружения добавим 2 записи:

Теперь создадим скрипт нотаризации, который будет выполняться после подписания приложения.

const notarize = require('electron-notarize').notarize;  module.exports = async (context) => {     const { electronPlatformName } = context;     if (electronPlatformName === 'darwin') {         try {             console.log('Try notarize app');             await notarize({               appBundleId: 'APP_BUNDLE_ID',               appPath: './dist/mac/APP_NAME.app',               appleId: process.env.appleId,               appleIdPassword: process.env.appleASP,             });             console.log('Success notarize');         } catch (err) {             console.log(err);         }   } };

Сохраняем его в удобном для вас месте.

Так же для корректной нотаризации нам потребуется определить права доступа
к ресурсам системы для нашего приложения. Для этого создадим файл build/entitlements.mac.plist

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">   <dict>     <key>com.apple.security.cs.allow-jit</key>     <true/>     <key>com.apple.security.cs.allow-unsigned-executable-memory</key>     <true/>     <key>com.apple.security.cs.allow-dyld-environment-variables</key>     <true/>     <key>com.apple.security.cs.disable-library-validation</key>     <true/>     <key>com.apple.security.cs.disable-executable-page-protection</key>     <true/>     <key>com.apple.security.cs.debugger</key>     <true/>     <key>com.apple.security.automation.apple-events</key>     <true/>    </dict> </plist>

Содержимое файла в моем случае. Для вас может быть другая конфигурация. Описание всех полей.
Обязательным для Electron.js является — com.apple.security.cs.allow-unsigned-executable-memory.

Теперь обновим настройки в package.json

В разделе для macOS:

  • gatekeeperAssess (отключает валидацию приложения на стороне electron-osx-sign)
  • hardenedRuntime (позволяет создать перечень разрешений безопасности и доступа к ресурсам системы)
  • entitlements (путь к файлу резрешений доступа для нашего приложения)

В общем разделе настроек electron-builder:

  • afterSign (путь до скрипта нотаризации, который будет зупущен после подписания приложения)

Запускаем процесс сборки. Может показаться, что он немного подвис, но передача файла на сервер Apple и ожидание ответа занимает какое-то время (от 3 до 10 минут)

Состояние нотаризации можно посмотреть в терминале, выполнив команду:

$ xcrun altool --notarization-history 0 -u $appleId -p $appleASP

Ответ будет представлен таблицей. Поле статус может иметь значение ‘process’, ‘approved’, ‘invalid’

При статусе ‘invalid’ по номеру запроса можно посмотреть, что именно пошло не так.

$ xcrun altool --notarization-info "RequestUUID" -u $appleId

Вот и весь процесс подписания и нотаризации. Надеюсь, моя статья окажется вам полезна. Спасибо.

Небольшое дополнение

При передаче приложения для тестирования, обнаружился интересный глюк. Приложение полученное через Телеграм, просто отказывалось запускаться. При просмотре логов обнаружилось, что приложение помещено в карантин Телеграмом. По какой причине и как это произошло, я не смог найти ответ. При отправке файла через Яндекс.Диск( или любой другой способ, чтобы скачать через браузер) такой проблемы не возникает.

Полезные ссылки

FavoriteLoadingДобавить в избранное
Posted in Без рубрики

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *