С выходом 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 записи:
- appleId — логин developer.apple.com
- appleASP — "app-specific password", который можно создать в личном кабинете appleid.apple.com.
Теперь создадим скрипт нотаризации, который будет выполняться после подписания приложения.
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
Вот и весь процесс подписания и нотаризации. Надеюсь, моя статья окажется вам полезна. Спасибо.
Небольшое дополнение
При передаче приложения для тестирования, обнаружился интересный глюк. Приложение полученное через Телеграм, просто отказывалось запускаться. При просмотре логов обнаружилось, что приложение помещено в карантин Телеграмом. По какой причине и как это произошло, я не смог найти ответ. При отправке файла через Яндекс.Диск( или любой другой способ, чтобы скачать через браузер) такой проблемы не возникает.
Полезные ссылки
- Репозиторий electron-notarize
- Статья Apple о нотаризации приложений
- Статья Kallin о процессе нотаризации, нашел её когда заканчивал писать свою
Автор: Антон