uechi.io/source/_posts/2019/sign-and-notarize-electron-app.md

188 lines
7.0 KiB
Markdown
Raw Permalink Normal View History

2019-06-05 14:28:21 +09:00
---
2019-06-05 14:36:19 +09:00
title: Electronアプリをコード署名してApple 公証 (Notary) を通過させる方法
2019-06-05 14:28:30 +09:00
date: 2019-06-05 00:00:00 +09:00
2019-08-14 21:24:49 +09:00
redirect_from: "/blog/2019/06/05/sign-and-notarize-electron-app"
2019-06-05 14:28:21 +09:00
---
2022-12-24 03:20:02 +09:00
electron-builder を利用して macOS 向け Electron アプリをコード署名し、公証を通過させる。
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
> **tl;dr**: コード署名と公証に対応した macOS アプリ Juno のリポジトリを[GitHub で公開](https://github.com/uetchy/juno)している。
2019-06-05 14:36:19 +09:00
2019-06-05 14:31:39 +09:00
# Code Sign
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
アプリのコード署名は`electron-builder`によって自動で行われる。内部的には[electron-osx-sign](https://github.com/electron-userland/electron-osx-sign)が使用される。
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
リリース用のアプリにコード署名をするには、Keychain に有効な Developer ID Certificate が格納されている必要がある。macOS Developer Certificate は開発用のコード署名にしか使えないため、リリース用としては不十分だ。
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
まだ証明書を発行していない場合は、[Apple Developer](https://developer.apple.com/account/resources/certificates/list)で証明書の追加ウィザードに進み、**Developer ID Application**を選択して証明書を発行する。
2019-06-05 14:28:21 +09:00
2019-06-05 14:31:39 +09:00
# Notarize
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
コード署名済みのアプリを[electron-notarize](https://github.com/electron-userland/electron-notarize)を使用して Apple Notary Service に提出する。
2019-06-05 14:28:21 +09:00
```js
2021-01-21 21:45:05 +09:00
const { notarize } = require("electron-notarize");
2019-06-05 14:28:21 +09:00
notarize({
appBundleId,
appPath,
appleId,
appleIdPassword,
ascProvider,
2021-01-21 21:45:05 +09:00
});
2019-06-05 14:28:21 +09:00
```
2022-12-24 03:20:02 +09:00
- **appBundleId**: アプリの Bundle ID 。`package.json``build.appId`と同じものを使う。
- **appPath**: `.app`の絶対パスを指定する。
- **appleId**: Apple Developer として登録している Apple ID を指定する。
- **appleIdPassword**: Apple ID のパスワード。2 要素認証を必要としないパスワードが必要なので、[Apple ID](https://appleid.apple.com/#!&page=signin)にアクセスして**App-specific Password**を発行する。
- **ascProvider**: Apple Developer の Membership に記載されている**Team ID**を指定する。
2019-06-05 14:28:21 +09:00
2019-06-05 14:31:39 +09:00
## electron-builder の afterSign フック
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
electron-builder の afterSign フックを使用して、コード署名が済んだアプリを自動で Notary に提出する。
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
フックスクリプトを`./scripts/after-sign-mac.js`に置く。
2019-06-05 14:28:21 +09:00
```js
2021-01-21 21:45:05 +09:00
const path = require("path");
const { notarize } = require("electron-notarize");
2019-06-05 14:28:21 +09:00
2021-01-21 21:45:05 +09:00
const appleId = process.env.APPLE_ID;
const appleIdPassword = process.env.APPLE_PASSWORD;
const ascProvider = process.env.ASC_PROVIDER;
2019-06-05 14:28:21 +09:00
2021-01-21 21:45:05 +09:00
const configPath = path.resolve(__dirname, "../package.json");
const appPath = path.resolve(__dirname, "../dist/mac/App.app");
const config = require(configPath);
const appBundleId = config.build.appId;
2019-06-05 14:28:21 +09:00
async function notarizeApp() {
2021-01-21 21:45:05 +09:00
console.log(`afterSign: Notarizing ${appBundleId} in ${appPath}`);
2019-06-05 14:28:21 +09:00
await notarize({
appBundleId,
appPath,
appleId,
appleIdPassword,
ascProvider,
2021-01-21 21:45:05 +09:00
});
console.log("afterSign: Notarized");
2019-06-05 14:28:21 +09:00
}
exports.default = async () => {
2021-01-21 21:45:05 +09:00
await notarizeApp();
};
2019-06-05 14:28:21 +09:00
```
2022-12-24 03:20:02 +09:00
`package.json``build``afterSign`を追加して、コード署名が終わった後にスクリプトが実行されるようにする。
2019-06-05 14:28:21 +09:00
```json
"build": {
2019-06-05 14:36:19 +09:00
"afterSign": "./scripts/after-sign-mac.js"
2019-06-05 14:28:21 +09:00
}
```
2019-06-06 02:58:07 +09:00
## Hardened Runtime and Entitlements
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
このままでは公証に失敗する。デフォルトで書き出されるバイナリでは、セキュリティの強化された[Hardened Runtime](https://developer.apple.com/documentation/security/hardened_runtime_entitlements)が有効になっていないためだ。以下のようなエラーメッセージが帰ってくる。
2019-06-05 14:28:21 +09:00
2019-06-05 14:31:39 +09:00
```json
2019-06-05 14:28:21 +09:00
{
"status": "Invalid",
"statusSummary": "Archive contains critical validation errors",
"statusCode": 4000,
"issues": [
{
"severity": "error",
"code": null,
"path": "App.zip/App.app/Contents/MacOS/App",
"message": "The executable does not have the hardened runtime enabled.",
"docUrl": null,
"architecture": "x86_64"
},
}
}
```
2022-12-24 03:20:02 +09:00
そこで、`package.json``build.mac.hardenedRuntime``true`にして Hardened Runtime を有効にする。
2019-06-05 14:28:21 +09:00
```json
"build": {
"mac": {
"hardenedRuntime": true
}
}
```
2022-12-24 03:20:02 +09:00
Hardened Runtime 下では、必要に応じて Entitlement を指定しなければならない。Electron の実行には`allow-unsigned-executable-memory` Entitlement が必要だ。そこで、`entitlement.plist`ファイルを`build`フォルダに作成し、以下のような plist を記述する。
2019-06-06 02:58:07 +09:00
```xml
<?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-unsigned-executable-memory</key>
<true/>
</dict>
</plist>
```
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
`package.json``entitlements`及び`entitlementsInherit`に Entitlement が記述された plist のファイルパスを指定する。
2019-06-06 02:58:07 +09:00
```json
"build": {
"mac": {
"hardenedRuntime": true,
"entitlements": "./src/build/entitlement.plist",
"entitlementsInherit": "./src/build/entitlement.plist"
}
}
```
2022-12-24 03:20:02 +09:00
Hardened Runtime で Electron を実行することができるようになったので、Notary を通過できる状態になった。
2019-06-06 02:58:07 +09:00
2022-12-24 03:20:02 +09:00
実際に`electron-builder`を実行して、すべてのプロセスが滞りなく動作することを確かめよう。
2019-06-05 14:28:21 +09:00
2019-06-05 14:31:39 +09:00
# Verify Notary Status
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
ただしく公証を得られたかどうかは`altool`で調べることができる。
2019-06-05 14:28:21 +09:00
2022-12-24 03:20:02 +09:00
公証通過後に送られてくるメールに`Request Identifier`が記載されているのでメモする。
2019-06-05 14:28:21 +09:00
```
2022-12-24 03:20:02 +09:00
Dear uetchy,
2019-06-05 14:28:21 +09:00
Your Mac software has been notarized. You can now export this software and distribute it directly to users.
Bundle Identifier: <Bundle ID>
Request Identifier: <UUID>
For details on exporting a notarized app, visit Xcode Help or the notarization guide.
Best Regards,
Apple Developer Relations
```
2022-12-24 03:20:02 +09:00
`xcrun altool --notarization-info`コマンドに UUID と Apple ID、パスワードを指定して公証ステータスを確認する。
2019-06-05 14:28:21 +09:00
```
xcrun altool --notarization-info <UUID> -u $APPLE_ID -p $APPLE_PASSWORD
```
2022-12-24 03:20:02 +09:00
正しく公証が得られている場合は以下のようなメッセージが表示される。おめでとう!
2019-06-05 14:28:21 +09:00
```
2019-06-05 13:51:18.236 altool[5944:261201] No errors getting notarization info.
RequestUUID: <UUID>
Date: 2019-06-05 04:45:54 +0000
Status: success
LogFileURL: https://osxapps-ssl.itunes.apple.com/itunes-assets/Enigma123/v4/<Log file identifier>
Status Code: 0
Status Message: Package Approved
```
2019-06-06 02:58:07 +09:00
## 参考文献
- [Resolving Common Notarization Issues](https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution/resolving_common_notarization_issues)
- [Notarizing your Electron application](https://kilianvalkhof.com/2019/electron/notarizing-your-electron-application/)
- [Feature request: Enable hardened runtime for macOS #3383](https://github.com/electron-userland/electron-builder/issues/3383)