#!/usr/bin/env bash # 对已经 Developer ID 签名的 DMG 做 Apple 公证并 staple。 # 已钉票则直接退出,避免重复上传。 # notarytool --wait 有时会一直 In Progress,即使苹果已 Accepted;超时后仍尝试 staple。 set -u ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" VERSION="$(node -p "require('$ROOT_DIR/package.json').version")" DMG="${1:-$ROOT_DIR/release/v$VERSION/macos-arm64/OpsXShell_${VERSION}_aarch64.dmg}" APPLE_ID="${APPLE_ID:-}" TEAM_ID="${APPLE_TEAM_ID:-B8DVUUUF6W}" WAIT_TIMEOUT="${NOTARY_WAIT_TIMEOUT:-15m}" : "${WAIT_TIMEOUT:=15m}" if [ ! -f "$DMG" ]; then echo "找不到安装包:$DMG" >&2 exit 1 fi # 挂载中的 DMG 无法 staple / validate if hdiutil info 2>/dev/null | grep -Fq "$DMG"; then echo "DMG 仍挂载,请先在 Finder 弹出 /Volumes 下的 OpsXShell,再重试。" >&2 hdiutil info | grep -E "image-path|/Volumes/" || true exit 1 fi export http_proxy="${http_proxy:-http://127.0.0.1:7897}" export https_proxy="${https_proxy:-http://127.0.0.1:7897}" export HTTP_PROXY="$http_proxy" export HTTPS_PROXY="$https_proxy" export ALL_PROXY="${ALL_PROXY:-socks5://127.0.0.1:7897}" export no_proxy="localhost,127.0.0.1,::1" export NO_PROXY="$no_proxy" already_stapled() { xcrun stapler validate "$DMG" >/dev/null 2>&1 } try_staple() { echo "尝试 staple(从苹果拉票据钉进 DMG,不需要专用密码)…" if xcrun stapler staple "$DMG"; then xcrun stapler validate "$DMG" echo echo "完成(已钉票):$DMG" return 0 fi return 1 } if already_stapled; then echo "这份 DMG 已经公证并 staple,不用再执行。" echo "$DMG" xcrun stapler validate "$DMG" exit 0 fi echo "尚未钉票。先看苹果是否已经公证通过(常见于 --wait 卡住)。" if try_staple; then exit 0 fi if [ -z "$APPLE_ID" ]; then APPLE_ID="$( osascript <<'APPLESCRIPT' tell application "System Events" activate set dlg to display dialog "Apple ID(开发者账号邮箱)" default answer "" with title "OpsXShell 公证" buttons {"取消", "继续"} default button "继续" cancel button "取消" return text returned of dlg end tell APPLESCRIPT )" || exit 1 fi echo echo "需要提交公证。请输入 App 专用密码,不要发到聊天。" PASSWORD="$( osascript <<'APPLESCRIPT' tell application "System Events" activate set dlg to display dialog "App 专用密码(xxxx-xxxx-xxxx-xxxx)" default answer "" with hidden answer with title "OpsXShell 公证" buttons {"取消", "提交"} default button "提交" cancel button "取消" return text returned of dlg end tell APPLESCRIPT )" || { echo "已取消。" >&2 exit 1 } if [ -z "$PASSWORD" ] || [ -z "$APPLE_ID" ]; then echo "未输入 Apple ID 或专用密码,已取消。" >&2 exit 1 fi echo "正在提交 ${DMG} (最多等 ${WAIT_TIMEOUT}) …" set +e SUBMIT_LOG="$(mktemp)" xcrun notarytool submit "$DMG" \ --apple-id "$APPLE_ID" \ --password "$PASSWORD" \ --team-id "$TEAM_ID" \ --wait \ --timeout "${WAIT_TIMEOUT}" | tee "$SUBMIT_LOG" SUBMIT_STATUS="${PIPESTATUS[0]}" set -e SUB_ID="$(awk '/id: / { print $2; exit }' "$SUBMIT_LOG")" rm -f "$SUBMIT_LOG" if [ -n "$SUB_ID" ]; then echo "提交号:$SUB_ID" fi if [ "$SUBMIT_STATUS" -eq 0 ]; then echo "notarytool 报告处理结束。" else echo "等待超时或状态未刷新 (exit ${SUBMIT_STATUS}). 改为直接 staple。" fi if try_staple; then exit 0 fi echo >&2 echo "staple 仍失败。可等几分钟再执行本脚本(已公证则不会重新上传)。" >&2 if [ -n "${SUB_ID:-}" ]; then echo " xcrun notarytool info $SUB_ID --apple-id \"$APPLE_ID\" --team-id \"$TEAM_ID\"" >&2 fi echo "不要对同一份未变化的 DMG 连续第三次提交。" >&2 exit 1