macOS:在脚本中公证?

Jer*_*ock 12 macos notarize

由于代码签名和Xcode的存档费时,枯燥和有问题的,我一直codesigned,归档和运签署我的开发者ID的MacOS应用程序中使用的命令行工具xcodebuildcodesign等等。通过我自己的脚本。公证看起来将是一个巨大的痛苦。是否可以在脚本中添加公证?

Jer*_*ock 15

是。不幸的是,官方答复留下了一些松散的结局,例如奎因(Quinn)的《爱斯基摩人》(Eskimo)的重要消息。这是操作方法:

一次性设置

获取特定于应用程序的密码

确定公证应用的“应用”的名称。我使用产品运输脚本的名称,SSYShipProduct.pl因为这是将使用此密码的“应用程序”。我们将把您撰写的任何名称都称为your-notarizing-name

浏览到https://appleid.apple.com/account/manage,滚动到“ 安全性” >“ 应用程序专用密码”,然后为名为your-notarizing-name应用程序生成应用程序专用密码。复制它提供给您的密码。我们将其称为app-specific-password

将特定于应用程序的密码添加到您的macOS钥匙串

运行以下命令以将刚创建的密码添加到钥匙串中:

security add-generic-password -a "your-apple-ID-email" -w "app-specific-password" -s "your-notarizing-name"

-s参数是,这个项目将在您的钥匙串的名称。我认为您实际上可以使用其他名称,但是在我看来,your-notarizing-name在此处使用也很有意义。

您可以通过在“ 钥匙串访问”应用程序中搜索来验证它是否有效。但是,请注意,直到退出并重新启动后,新项目才会在“ 钥匙串访问”中列出。

也许,获取相关的itc提供者

如果您的Apple ID与一个以上的Apple Developer Connection团队相关联(例如,如果您从事合同工作),则需要该应用程序经过公证的团队的itc_provider

要找到您团队的itc_provider,请执行以下命令:

/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/itms/bin/iTMSTransporter -m provider -u "your-apple-ID-email" -p "app-specific-password"

滚动到此命令输出的输出的末尾,然后查看提供者列表。复制所需团队的简称。我们将其称为“ developer-team-itc-provider”。

对于每次装运(可编写脚本!)

如果使用/usr/bin/codesign命令行工具对应用程序的组件进行签名,则每次对codesign的调用都必须具有以下新的parameter参数,该参数告诉codesign使用所谓的强化运行时进行签名:

 `--options runtime`
Run Code Online (Sandbox Code Playgroud)

相反,如果您的应用程序已用Xcode签名,则必须在所有可执行组件目标中将Xcode 10或更高版本中可用的“ Build Setting Hardened”运行时设置为“ 是”

除此之外,与公证前的日子一样,您的脚本应在Release配置中创建应用的构建并对其进行代码签名。

上载到Apple公证服务

然后,您的脚本应将您的应用存档到.zip或.dmg。请注意,这是一个临时文件,将仅上传到Apple Notary服务,而不附带。

然后,您的脚本应组成一个主要的捆绑包ID值,该将是您应用的捆绑包标识符,.zip.dmg附加在其后。示例:your-pbid-value = com.mycompany.YourApp.zip

接下来,您的脚本将使用altool,这是Apple的Application Loader Tool的名称。

然后,您的脚本应运行以下命令以对.zip或.dmg进行公证:

/usr/bin/xcrun altool --notarize-app --primary-bundle-id "your-pbid-value" --username "your-apple-id-email" --password "@keychain:your-notarizing-name" -itc_provider "developer-team-itc-provider" --file /path/to/YourApp.zip/or/YourApp.dmg --output-format "xml"

(请注意,在上面的命令中,奇怪的是,所有参数名称都以两个破折号开头,但-itc_provider仅以一个破折号开头。此外,如果您使用的脚本语言是@在字符串中插入字符,请对其进行编码以防止插入@keychain)。

xcrun大约一分钟后,将退出并打印以输出一些XML,如果您的提交被接受(注意:尚未批准),则该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>notarization-upload</key>
    <dict>
        <key>RequestUUID</key>
        <string>2ab59b26-19ec-4a30-84cf-6d2cb8d3c97e</string>
    </dict>
    <key>os-version</key>
    <string>10.15.0</string>
    <key>success-message</key>
    <string>No errors uploading 'path/to/YourApp.zip'.</string>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
    <key>tool-version</key>
    <string>1.1.1138</string>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)



您真正需要的就是这些RequestUUID价值。但是,由于我经常发布四个应用程序,并且由于我的发布脚本失败而又没有提供有用的错误信息,这毁了我的一天,并且因为(请参阅下文)您将要进行另一个调用,该调用也返回了有趣的XML,因此我花了一些时间在我的脚本中添加了一个子例程,该子例程带有两个参数,即XML和一个密钥路径,并在给定的密钥路径下返回XML的值。在上述情况下,我调用此子例程获取RequestUUID,然后再次获取success-message

(我的脚本在Perl中。尽管CPAN中有一个名为XML :: Simple的模块,可以在一两行中进行此解析,但维护人员将其标记为不用于新设计。因此,避免了需要要使用真正的 XML解析器安装和纠缠,我选择使用PlistBuddy@khuttun的注释中建议的方法,这有点痛苦,因为不幸的是,altool它没有选择将其输出写入文件,并且PlistBuddy没有记录接受stdin。因此,我的子例程将stdout从写入altool临时文件,然后将该临时文件的路径传递给PlistBuddy。有点令人讨厌,但它可以工作。)

删除未装订的zip软件包

此时,我建议您的脚本删除其上载的.zip.dmg文件。原因:该文件是从尚未装订公证证件的产品中存档的。在脚本末尾,您将创建一个新的.zip.dmg从带有票证的修改后的应用程序。立即删除文件可防止您错误地运送未装订的应用程序。

等待循环中苹果的回应

然后,通过循环运行以下命令并进行一些睡眠,您的脚本可以开始为您的最终结果困扰Apple的服务器:

`/ usr / bin / xcrun altool --notarization-info --username“ your-apple-id-email” --password“ @keychain:your-notarizing-name”-输出格式“ xml”

如果您的脚本立即运行此命令,它将在stdout中返回一些xml,看起来像下面的示例:

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>notarization-info</key>
    <dict>
        <key>Date</key>
        <date>2019-08-07T01:17:37Z</date>
        <key>RequestUUID</key>
        <string>4ba71353-9d99-4b52-b579-37f384717130</string>
        <key>Status</key>
        <string>in progress</string>
    </dict>
    <key>os-version</key>
    <string>10.15.0</string>
    <key>success-message</key>
    <string>No errors getting notarization info.</string>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
    <key>tool-version</key>
    <string>1.1.1138</string>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)


其中的重要关键路径是notarization-info:Status,其值in progress表示Apple仍在处理您的提交。通常在几分钟后(Apple说“应该少于一个小时”,但是我在2019年7月4日美国假日下午经历了长达三个半小时的时间),altool将使用不同的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>notarization-info</key>
    <dict>
        <key>Date</key>
        <date>2019-08-06T23:28:25Z</date>
        <key>LogFileURL</key>
        <string>https://osxapps-ssl.itunes.apple.com/itunes-assets/Enigma113/v4/f6/09/be/f609bee3-b031-323a-0987-d1f620a78758/developer_log.json?accessKey=1565410613_1722173034418364591_TvycjBAzd6FRTYGKZEFU6EwDfsws8Wa1MV%2FYnTiJ1zyOZamc%2FoeO5RMeIzZN669ZQJgO2Q4W48ipKNFO%2BQGuq%2FITXN8MQAetbNe90w9ogzqXbrzTHg%2FgYK89yvEFmiiRxhaVlZqLI93NBpY0hwBqXv2bvvlg%2FRCc%2BVaCNRJ%2BrnE%3D</string>
        <key>RequestUUID</key>
        <string>07fc3745-b0ff-4d1a-9b15-37f384717130</string>
        <key>Status</key>
        <string>success</string>
        <key>Status Code</key>
        <integer>0</integer>
        <key>Status Message</key>
        <string>Package Approved</string>
    </dict>
    <key>os-version</key>
    <string>10.15.0</string>
    <key>success-message</key>
    <string>No errors getting notarization info.</string>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework</string>
    <key>tool-version</key>
    <string>1.1.1138</string>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)


经过一些反向工程之后,您会看到,在每次循环迭代中,只要的值Status不是in progressLogFileURL定义了when,则脚本应该解析XML并退出循环。或者,如果您更喜欢电子邮件触发器,则脚本可以查找主题行来自Apple的电子邮件。现在,您可以分发Mac软件。

更新2019-11-02

在最后几次发货后(今天又是今天)遇到了这一步骤的麻烦之后,我现在确认了Apple的Notary Service中的错误。错误是altool --notarization-info命令将在1-5个小时内失败,返回非零退出代码,并在stdout中显示错误代码1519“找不到RequestUUID”,如以下示例stdout中所示:

<?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>os-version</key>
    <string>10.15.1</string>
    <key>product-errors</key>
    <array>
        <dict>
            <key>code</key>
            <integer>1519</integer>
            <key>message</key>
            <string>Could not find the RequestUUID.</string>
            <key>userInfo</key>
            <dict>
                <key>NSLocalizedDescription</key>
                <string>Could not find the RequestUUID.</string>
                <key>NSLocalizedFailureReason</key>
                <string>Apple Services operation failed.</string>
                <key>NSLocalizedRecoverySuggestion</key>
                <string>Could not find the RequestUUID.</string>
            </dict>
        </dict>
    </array>
    <key>tool-path</key>
    <string>/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Versions/A/Frameworks/AppStoreService.framework</string>
    <key>tool-version</key>
    <string>4.00.1181</string>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)


这是一个错误,因为,当然,我的剧本没有提交它刚刚从苹果公证服务接收到的请求UUID,苹果应该能够找到它,而且,当我不停手动发送命令,约2小时后,突然,该命令返回Success并继续返回Success后续命令,然后我收到了来自Apple 的成功电子邮件。今天,这种延迟发生了,有7个不同的良好Request UUID,最长为5小时。可能此时,Apple Notary Service创建与向您发送请求UUID之间存在1-5小时的延迟,并且该延迟出现在数据库中,Apple Notary Service用于响应notarization-info请求,因此您会收到此错误消息。很伤心

因为我有当苹果转让人修正错误,我已经修改了这个阶段,我的脚本来解析来自苹果的回应并无控制,死亡仅当命令返回非零退出状态,并code第一(指数= 0)product-errors数组项不是1519。如果您按原样使用PlistBuddy解析XML,则其关键路径应为代码product-errors:0:code。每当收到错误1519时,脚本中的循环都会打印出来,因此我可以看到发生了什么,当然,我修改了它的while条件,以使错误代码为1519时不退出。

修改完脚本后,我发布了几个应用程序。Apple Notary Service很好地对待了第一个:No Error 1519,大约两分钟后成功。但是,下一个需要我脚本的新功能。在时间09:54(HH:mm),我的脚本收到了Apple的Request UUID。20秒后,它发送了第一个altool --notarization-info查询。响应是错误的错误1519。后续查询也返回错误的错误1519,持续了将近3个小时,直到12:44。然后,在12:45,它突然收到了in progress响应。经过5次in progress回复后,终于在12:47 成功

离开本主题之前的另一件事:该请求成功执行一个小时,没有出现错误1519,一个小时前的先前请求突然开始返回in progress,然后几分钟后返回Success。结论:绕开到错误1519混乱中的请求UUID不会与以后的请求UUID一起排队在FIFO中,后者可能会避免错误1519绕道。因此,更好的解决方法可能是在收到另一个错误1519响应后放弃请求UUID,然后通过将应用程序重新上载到Apple Notary Service重新开始,并获取另一个您希望能更好地工作的请求UUID。当然,由于您放弃的所有请求UUID最终都会成功,因此在接下来的几个小时内您会收到许多电子邮件。

无论如何,现在,继续进行脚本的下一步…

检查苹果的日志文件

您的脚本应该解析出的值,LogFileURL以便可以检查日志,因为即使公证成功,Apple创建的日志文件也可能包含警告。要获取日志文件,您的脚本当然应该

curl <LogFileURL-Value>
Run Code Online (Sandbox Code Playgroud)

日志文件显然是JSON。警告或错误以数组形式显示,它是key的值issues。因此,您的脚本应curl使用JSON解析器解析该输出,并且如果key的issues值为JSON null或空数组,请继续发货。

订票到您的应用程序

这一步很容易...

xcrun stapler staple /path/to/YourApp.app
Run Code Online (Sandbox Code Playgroud)

运行此命令会将一个新文件添加到您应用的软件包中YourApp.app/Contents/CodeResources。这显然是您的公证单。请注意,此文件是对YourApp.app/Contents/_CodeSignature/CodeResources仍存在的文件的补充,并且包含代码签名,与公证前的日子相同。

验证票证装订

但是,有一种更好的方法来验证您的应用程序现在是否有票证。您的脚本现在应该运行(或重新运行)Gatekeeper检查:

spctl -a -v /path/to/YourApp.app
Run Code Online (Sandbox Code Playgroud)

在stderr中,结果应该是,

/path/to/YourApp.app: accepted
source=Notarized Developer ID
Run Code Online (Sandbox Code Playgroud)

除了插入Notarized以外,与预公证的结果相同。如果未检测到上述单词,则精明的脚本将解析该stderr并中止发货。

邮递

现在已经添加了票证,您的脚本可以再次对.app进行zip或dmg处理,但这一次,将其发送出去。


red*_*oah 5

这是一个可重复使用且免费许可的公证和订书脚本,用于自动构建:

https://github.com/rednoah/notarize-app/blob/master/notarize-app

它会运行并等待,只有在一切完成后才退出:

  1. 跑步altool --notarize-app
  2. 定期运行altool --notarization-info直至公证完成
  3. 跑步stapler staple