#!/usr/bin/env bash set -euo pipefail ts() { date +"%H:%M:%S"; } usage() { cat <<'EOF' Usage: ./build_tools/macos/find_mas_provisioning_profile.sh --bundle-id com.dryark.strawberry What it does: - Scans common macOS provisioning profile locations (new Xcode + legacy) - Uses Apple's `security cms -D` to decode each *.provisionprofile into a plist - Prints a readable table and recommends a best match for the given bundle id Notes: - A provisioning profile is required for Mac App Store signing. - This script only helps you *find* the right profile file. EOF } if [[ "$(uname -s)" != "Darwin" ]]; then echo "Error: This script is for macOS only." >&2 exit 1 fi bundle_id="" while [[ $# -gt 0 ]]; do case "$1" in --bundle-id) bundle_id="${2:-}"; shift 2 ;; -h|--help) usage; exit 0 ;; *) echo "Unknown arg: $1" >&2; usage; exit 2 ;; esac done if [[ -z "$bundle_id" ]]; then echo "Error: missing --bundle-id" >&2 usage exit 2 fi if ! command -v security >/dev/null 2>&1; then echo "Error: 'security' not found." >&2 exit 1 fi plistbuddy_print() { local keypath="$1" local plist="$2" /usr/libexec/PlistBuddy -c "Print :${keypath}" "$plist" 2>/dev/null || true } plutil_extract() { local keypath="$1" local plist="$2" /usr/bin/plutil -extract "$keypath" raw -o - "$plist" 2>/dev/null || true } find_profiles_in_dir() { local dir="$1" if [[ -d "$dir" ]]; then find "$dir" -maxdepth 1 -type f \( -name "*.provisionprofile" -o -name "*.mobileprovision" \) 2>/dev/null || true fi } declare -a candidates candidates=() while IFS= read -r f; do candidates+=("$f"); done < <(find_profiles_in_dir "$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles") while IFS= read -r f; do candidates+=("$f"); done < <(find_profiles_in_dir "$HOME/Library/MobileDevice/Provisioning Profiles") if [[ ${#candidates[@]} -eq 0 ]]; then echo "==> [$(ts)] No provisioning profiles found in common locations." exit 1 fi echo "==> [$(ts)] Scanning ${#candidates[@]} provisioning profile(s) for bundle id: ${bundle_id}" echo printf "%-4s %-36s %-10s %-25s %-45s %s\n" "No." "UUID" "TeamID" "Expires" "AppID" "Path" printf "%s\n" "---- ------------------------------------ ---------- ------------------------- --------------------------------------------- ----" best_score=-1 best_path="" best_reason="" idx=0 for f in "${candidates[@]}"; do idx=$((idx + 1)) tmp="$(mktemp -t strawberry-profile.XXXXXX.plist)" if ! security cms -D -i "$f" >"$tmp" 2>/dev/null; then rm -f "$tmp" >/dev/null 2>&1 || true continue fi uuid="$(plutil_extract UUID "$tmp")" name="$(plutil_extract Name "$tmp")" teamid="$(plutil_extract 'TeamIdentifier.0' "$tmp")" if [[ -z "$teamid" ]]; then teamid="$(plutil_extract 'ApplicationIdentifierPrefix.0' "$tmp")" fi exp="$(plutil_extract ExpirationDate "$tmp")" # App identifier lives under Entitlements; use PlistBuddy because some key names contain dots. appid="$(plistbuddy_print 'Entitlements:application-identifier' "$tmp")" if [[ -z "$appid" ]]; then appid="$(plistbuddy_print 'Entitlements:com.apple.application-identifier' "$tmp")" fi rm -f "$tmp" >/dev/null 2>&1 || true [[ -z "$uuid" ]] && uuid="(unknown)" [[ -z "$teamid" ]] && teamid="(unknown)" [[ -z "$exp" ]] && exp="(unknown)" [[ -z "$appid" ]] && appid="(unknown)" printf "%-4s %-36s %-10s %-25s %-45s %s\n" "$idx" "$uuid" "$teamid" "$exp" "$appid" "$f" score=0 reason="" if [[ "$appid" != "(unknown)" && "$teamid" != "(unknown)" ]]; then if [[ "$appid" == "${teamid}.${bundle_id}" ]]; then score=100 reason="exact match (${appid})" elif [[ "$appid" == *".${bundle_id}" ]]; then score=50 reason="endswith match (${appid})" elif [[ "$appid" == "${teamid}."* && "$appid" == *"*"* ]]; then score=40 reason="wildcard match (${appid})" fi fi if [[ "$score" -gt 0 && -n "$name" ]]; then case "$name" in *Mac\ App\ Store*|*App\ Store*|*appstore*|*AppStore*) score=$((score + 5)) reason="${reason}, name looks like MAS" ;; esac fi if [[ "$score" -gt "$best_score" ]]; then best_score="$score" best_path="$f" best_reason="$reason" fi done echo if [[ "$best_score" -le 0 ]]; then echo "==> [$(ts)] Could not confidently auto-select a profile for ${bundle_id}." echo "Pick the profile whose AppID is TEAMID.${bundle_id} and is a macOS Mac App Store profile." exit 2 fi echo "==> [$(ts)] Recommended profile:" echo " $best_path" echo " reason: $best_reason"