- PVSM.RU - https://www.pvsm.ru -

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

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

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

Введение

Спустя 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

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

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

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

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

  • 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 необходимо просто поставить галочку о нотаризации

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

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

$ 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 [1]
  • password — "app-specific password". Его можно создать в личном кабинете appleid.apple.com [2] под учеткой разработчика.

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

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

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

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

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

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

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

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

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

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

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

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

  • appleId — логин developer.apple.com [1]
  • appleASP — "app-specific password", который можно создать в личном кабинете appleid.apple.com [2].

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

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

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>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Автор: Антон

Источник [8]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/320658

Ссылки в тексте:

[1] developer.apple.com: https://developer.apple.com

[2] appleid.apple.com: https://appleid.apple.com

[3] Kallin: https://github.com/Kilian

[4] Описание всех полей: https://developer.apple.com/documentation/security/hardened_runtime_entitlements

[5] Репозиторий electron-notarize: https://github.com/electron-userland/electron-notarize

[6] Статья Apple о нотаризации приложений: https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution

[7] Статья Kallin о процессе нотаризации, нашел её когда заканчивал писать свою: https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/

[8] Источник: https://habr.com/ru/post/455874/?utm_source=habrahabr&utm_medium=rss&utm_campaign=455874