mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
macOS Keychain Access on Sonoma+ exports .p12 with modern crypto (AES-256-GCM + PBKDF2 + SHA-256). The `security import` binary on some macOS releases — including ours apparently — rejects it with: SecKeychainItemImport: Unknown format in import. The openssl decode itself was fine (now using openssl base64 -d -A), but security can't import the resulting PKCS12 envelope. Pipe the .p12 through openssl: unpack with the user's password, then re-export using legacy PBE-SHA1-3DES for both certs and keys, plus SHA1 MAC. The resulting .p12 uses 90s-era crypto for the OUTER envelope, which is what security import wants — the actual signing keys + cert inside are unchanged. No security implication; the legacy format encryption only matters for the few seconds the .p12 lives in $RUNNER_TEMP before being imported and deleted. Also added diagnostic output (file size, magic bytes, file(1)) so the next failure mode (if any) is easier to characterize.
442 lines
18 KiB
YAML
442 lines
18 KiB
YAML
name: Hash Bags iOS TestFlight build
|
|
|
|
# Phase 2 of iOS CI: full signed build that uploads to TestFlight.
|
|
# Phase 1 (build-ios-sim.yml) validates the Mac runner with no signing —
|
|
# run that first if TestFlight blows up unexpectedly.
|
|
#
|
|
# Required Gitea Actions secrets (all account/app credentials):
|
|
# APPLE_TEAM_ID — 10-char (D8PL9F7X33)
|
|
# APPLE_KEY_ID — 10-char (CHK6B69G58)
|
|
# APPLE_ISSUER_ID — UUID
|
|
# APPLE_API_KEY_P8_BASE64 — base64 of AuthKey_<KeyID>.p8
|
|
# APPLE_DIST_CERT_P12_BASE64 — base64 of distribution.p12
|
|
# APPLE_DIST_CERT_P12_PASSWORD — password set during openssl pkcs12 export
|
|
# APPLE_PROVISIONING_PROFILE_BASE64 — base64 of Hash_Wallet.mobileprovision
|
|
# APPLE_KEYCHAIN_PASSWORD — any string, used to create the temp keychain
|
|
# TROCADOR_* — reused from Linux/Android
|
|
|
|
on:
|
|
# Don't auto-trigger on every push — TestFlight uploads are slow and use
|
|
# build numbers. Manual trigger only; later we can add a workflow_dispatch
|
|
# input for build number or auto-bump.
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: ios-testflight-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: macos-latest
|
|
env:
|
|
APP_IOS_TYPE: cakewallet
|
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
|
# CocoaPods needs UTF-8; Gitea runner shell defaults to ASCII-8BIT.
|
|
LANG: en_US.UTF-8
|
|
LC_ALL: en_US.UTF-8
|
|
# See note in build-ios-sim.yml — fallback if /etc/hosts trick
|
|
# isn't in place. Safe no-op once it is.
|
|
NODE_TLS_REJECT_UNAUTHORIZED: '0'
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Check Flutter 3.32.0
|
|
id: flutter_check
|
|
run: |
|
|
if command -v flutter >/dev/null && flutter --version 2>/dev/null | grep -q "3\.32\.0"; then
|
|
echo "installed=true" >> "$GITHUB_OUTPUT"
|
|
flutter --version
|
|
else
|
|
echo "installed=false" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Install Flutter 3.32.0 (if missing)
|
|
if: steps.flutter_check.outputs.installed != 'true'
|
|
uses: subosito/flutter-action@v2
|
|
with:
|
|
flutter-version: '3.32.0'
|
|
channel: stable
|
|
cache: true
|
|
|
|
- name: Install CocoaPods (if missing)
|
|
run: |
|
|
if command -v pod >/dev/null; then
|
|
pod --version
|
|
exit 0
|
|
fi
|
|
if command -v brew >/dev/null; then
|
|
brew install cocoapods
|
|
else
|
|
export GEM_HOME="$HOME/.gem"
|
|
export PATH="$GEM_HOME/bin:$PATH"
|
|
echo "GEM_HOME=$HOME/.gem" >> "$GITHUB_ENV"
|
|
echo "$HOME/.gem/bin" >> "$GITHUB_PATH"
|
|
gem install --user-install cocoapods --no-document
|
|
fi
|
|
pod --version
|
|
|
|
- name: Install Rust + iOS targets (if missing)
|
|
run: |
|
|
if ! command -v rustup >/dev/null; then
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --no-modify-path
|
|
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
fi
|
|
rm -rf "$HOME/.rustup/downloads"/*.partial 2>/dev/null || true
|
|
rustup target add aarch64-apple-ios
|
|
rustup target add aarch64-apple-ios-sim
|
|
rustup target add x86_64-apple-ios
|
|
rustup show
|
|
|
|
- name: Install Go + gomobile (if missing)
|
|
run: |
|
|
if ! command -v go >/dev/null; then
|
|
if command -v brew >/dev/null; then
|
|
brew install go
|
|
else
|
|
echo "Go missing and brew not available"; exit 1
|
|
fi
|
|
fi
|
|
go version
|
|
GOPATH=$(go env GOPATH)
|
|
echo "$GOPATH/bin" >> "$GITHUB_PATH"
|
|
export PATH="$PATH:$GOPATH/bin"
|
|
if ! command -v gomobile >/dev/null; then
|
|
go install golang.org/x/mobile/cmd/gomobile@latest
|
|
go install golang.org/x/mobile/cmd/gobind@latest
|
|
fi
|
|
which gomobile && gomobile version || true
|
|
|
|
- name: Show toolchain
|
|
run: |
|
|
set -x
|
|
flutter --version
|
|
xcodebuild -version
|
|
pod --version
|
|
uname -m
|
|
|
|
# ---- External prebuilt deps -----------------------------------------
|
|
# macOS doesn't ship wget; using curl everywhere.
|
|
- name: Fetch prebuilt torch_dart
|
|
run: |
|
|
set -x -e
|
|
pushd scripts
|
|
rm -rf torch_dart torch_dart.tar.gz
|
|
curl -fsSL -o torch_dart.tar.gz https://github.com/MrCyjaneK/torch_dart/releases/download/v1.0.17/torch_dart-v1.0.17.tar.gz
|
|
mkdir torch_dart
|
|
tar -xzf torch_dart.tar.gz -C torch_dart
|
|
rm torch_dart.tar.gz
|
|
popd
|
|
|
|
- name: Fetch prebuilt reown_flutter
|
|
run: |
|
|
set -x -e
|
|
pushd scripts
|
|
rm -rf reown_flutter reown_flutter.tar.gz
|
|
curl -fsSL -o reown_flutter.tar.gz https://github.com/cake-tech/reown_flutter/releases/download/v0.0.4/reown_flutter-v0.0.4.tar.gz
|
|
mkdir reown_flutter
|
|
tar -xzf reown_flutter.tar.gz -C reown_flutter
|
|
rm reown_flutter.tar.gz
|
|
popd
|
|
|
|
- name: Clone BitBox Flutter (iOS — skip Android bindings)
|
|
run: |
|
|
# See note in build-ios-sim.yml — iOS uses bitbox's native plugin,
|
|
# not the .aar that build_bindings.sh generates.
|
|
set -x -e
|
|
pushd scripts
|
|
if [[ ! -d bitbox_flutter ]]; then
|
|
git clone https://github.com/konstantinullrich/bitbox_flutter
|
|
fi
|
|
cd bitbox_flutter
|
|
git fetch -a
|
|
git reset --hard
|
|
git checkout 5a6e6dd388ef64003f86094af80d5453518b601d
|
|
git reset --hard
|
|
popd
|
|
|
|
- name: Fetch prebuilt monero_c bundle
|
|
run: |
|
|
set -x -e
|
|
./scripts/prepare_moneroc.sh
|
|
MONERO_C_TAG=$(cd scripts/monero_c && git describe --tags)
|
|
mkdir -p "scripts/monero_c/release/$MONERO_C_TAG"
|
|
pushd "scripts/monero_c/release/$MONERO_C_TAG"
|
|
curl -fsSL -O https://github.com/MrCyjaneK/monero_c/releases/download/v0.18.4.6-RC1/release-bundle.zip
|
|
unzip -q release-bundle.zip
|
|
rm release-bundle.zip
|
|
popd
|
|
|
|
- name: Build MoneroWallet + WowneroWallet XCFrameworks
|
|
run: |
|
|
set -x -e
|
|
pushd scripts/ios
|
|
bash ./gen_framework.sh
|
|
popd
|
|
ls -la ios/MoneroWallet.xcframework ios/WowneroWallet.xcframework
|
|
|
|
# ---- Configure: pubspec.yaml, Info.plist, etc. ----------------------
|
|
- name: Run iOS configure (cakewallet profile)
|
|
run: |
|
|
set -x -e
|
|
pushd scripts/ios
|
|
source ./app_env.sh cakewallet
|
|
./app_config.sh
|
|
popd
|
|
|
|
# ---- Secrets ---------------------------------------------------------
|
|
- name: Generate per-module secrets.g.dart files (empty defaults)
|
|
run: dart run tool/generate_new_secrets.dart
|
|
|
|
- name: Inject Trocador affiliate secrets
|
|
env:
|
|
TROCADOR_API_KEY: ${{ secrets.TROCADOR_API_KEY }}
|
|
TROCADOR_MONERO_API_KEY: ${{ secrets.TROCADOR_MONERO_API_KEY }}
|
|
TROCADOR_EXCHANGE_MARKUP: ${{ secrets.TROCADOR_EXCHANGE_MARKUP }}
|
|
run: |
|
|
sed -i '' \
|
|
-e "s|const trocadorApiKey = '';|const trocadorApiKey = '${TROCADOR_API_KEY}';|" \
|
|
-e "s|const trocadorMoneroApiKey = '';|const trocadorMoneroApiKey = '${TROCADOR_MONERO_API_KEY}';|" \
|
|
-e "s|const trocadorExchangeMarkup = '';|const trocadorExchangeMarkup = '${TROCADOR_EXCHANGE_MARKUP:-1}';|" \
|
|
lib/.secrets.g.dart
|
|
|
|
# ---- Apple signing setup --------------------------------------------
|
|
- name: Sanity-check Apple secrets are reaching the runner
|
|
env:
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
|
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
|
|
APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }}
|
|
APPLE_DIST_CERT_P12_BASE64: ${{ secrets.APPLE_DIST_CERT_P12_BASE64 }}
|
|
APPLE_DIST_CERT_P12_PASSWORD: ${{ secrets.APPLE_DIST_CERT_P12_PASSWORD }}
|
|
APPLE_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}
|
|
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
# Print LENGTHS only — never the secret values. Length 0 means the
|
|
# secret isn't actually reaching the runner (most often: secret is
|
|
# set on a different Gitea repo than this workflow is running in).
|
|
set +e
|
|
echo "APPLE_TEAM_ID length: ${#APPLE_TEAM_ID}"
|
|
echo "APPLE_KEY_ID length: ${#APPLE_KEY_ID}"
|
|
echo "APPLE_ISSUER_ID length: ${#APPLE_ISSUER_ID}"
|
|
echo "APPLE_API_KEY_P8_BASE64 length: ${#APPLE_API_KEY_P8_BASE64}"
|
|
echo "APPLE_DIST_CERT_P12_BASE64 length: ${#APPLE_DIST_CERT_P12_BASE64}"
|
|
echo "APPLE_DIST_CERT_P12_PASSWORD length: ${#APPLE_DIST_CERT_P12_PASSWORD}"
|
|
echo "APPLE_PROVISIONING_PROFILE_BASE64 length: ${#APPLE_PROVISIONING_PROFILE_BASE64}"
|
|
echo "APPLE_KEYCHAIN_PASSWORD length: ${#APPLE_KEYCHAIN_PASSWORD}"
|
|
set -e
|
|
# Fail fast on any zero-length secret so we don't waste time on the
|
|
# subsequent steps.
|
|
for n in TEAM_ID KEY_ID ISSUER_ID API_KEY_P8_BASE64 DIST_CERT_P12_BASE64 DIST_CERT_P12_PASSWORD PROVISIONING_PROFILE_BASE64 KEYCHAIN_PASSWORD; do
|
|
var="APPLE_$n"
|
|
if [[ -z "${!var}" ]]; then
|
|
echo "FATAL: $var is empty — set it as a Gitea repo secret on the repo this workflow runs in (Builds/hash-wallet)."
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
- name: Create temp keychain + import distribution cert
|
|
env:
|
|
APPLE_DIST_CERT_P12_BASE64: ${{ secrets.APPLE_DIST_CERT_P12_BASE64 }}
|
|
APPLE_DIST_CERT_P12_PASSWORD: ${{ secrets.APPLE_DIST_CERT_P12_PASSWORD }}
|
|
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
set -e
|
|
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
|
|
# Create + unlock dedicated keychain so we don't touch the user's login keychain
|
|
security create-keychain -p "$APPLE_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" # 6 hours
|
|
security unlock-keychain -p "$APPLE_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
# Add to user search list so codesign can find it
|
|
security list-keychains -d user -s "$KEYCHAIN_PATH" $(security list-keychains -d user | sed 's/"//g')
|
|
# Decode the user-uploaded .p12 to disk.
|
|
P12_MODERN="$RUNNER_TEMP/dist-modern.p12"
|
|
echo "$APPLE_DIST_CERT_P12_BASE64" | openssl base64 -d -A > "$P12_MODERN"
|
|
echo "=== uploaded .p12 file ==="
|
|
ls -la "$P12_MODERN"
|
|
xxd "$P12_MODERN" | head -1
|
|
file "$P12_MODERN" || true
|
|
|
|
# macOS Keychain Access in Sonoma+ exports .p12 with modern crypto
|
|
# (AES-256-GCM + PBKDF2 + SHA-256) that the `security import`
|
|
# binary on some macOS releases rejects with
|
|
# "SecKeychainItemImport: Unknown format in import." Re-export
|
|
# the PKCS12 through openssl using legacy PBE-SHA1-3DES so the
|
|
# macOS security command can definitely parse it.
|
|
P12="$RUNNER_TEMP/dist-legacy.p12"
|
|
echo "=== converting to legacy PKCS12 format ==="
|
|
openssl pkcs12 -in "$P12_MODERN" -nodes \
|
|
-password pass:"$APPLE_DIST_CERT_P12_PASSWORD" \
|
|
| openssl pkcs12 -export \
|
|
-macalg sha1 -keypbe PBE-SHA1-3DES -certpbe PBE-SHA1-3DES \
|
|
-password pass:"$APPLE_DIST_CERT_P12_PASSWORD" \
|
|
-out "$P12"
|
|
ls -la "$P12"
|
|
|
|
security import "$P12" -k "$KEYCHAIN_PATH" -P "$APPLE_DIST_CERT_P12_PASSWORD" \
|
|
-T /usr/bin/codesign -T /usr/bin/security
|
|
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$APPLE_KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
# Sanity-check: list identities the keychain offers
|
|
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
|
|
rm -f "$P12_MODERN" "$P12"
|
|
|
|
- name: Install provisioning profile + parse name/UUID for ExportOptions
|
|
env:
|
|
APPLE_PROVISIONING_PROFILE_BASE64: ${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}
|
|
run: |
|
|
set -e
|
|
PROFILES_DIR="$HOME/Library/MobileDevice/Provisioning Profiles"
|
|
mkdir -p "$PROFILES_DIR"
|
|
PROFILE="$RUNNER_TEMP/Hash_Wallet.mobileprovision"
|
|
echo "$APPLE_PROVISIONING_PROFILE_BASE64" | openssl base64 -d -A > "$PROFILE"
|
|
|
|
# Parse the .mobileprovision to get its UUID + Name (CMS-decoded plist).
|
|
PROFILE_UUID=$(security cms -D -i "$PROFILE" | plutil -extract UUID raw -o - -)
|
|
PROFILE_NAME=$(security cms -D -i "$PROFILE" | plutil -extract Name raw -o - -)
|
|
echo "Profile UUID: $PROFILE_UUID"
|
|
echo "Profile name: $PROFILE_NAME"
|
|
echo "PROFILE_UUID=$PROFILE_UUID" >> "$GITHUB_ENV"
|
|
echo "PROFILE_NAME=$PROFILE_NAME" >> "$GITHUB_ENV"
|
|
|
|
# Xcode looks profiles up by UUID filename.
|
|
cp "$PROFILE" "$PROFILES_DIR/$PROFILE_UUID.mobileprovision"
|
|
ls -la "$PROFILES_DIR" | head -10
|
|
|
|
- name: Install App Store Connect API key for altool
|
|
env:
|
|
APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }}
|
|
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
|
run: |
|
|
set -e
|
|
mkdir -p "$HOME/.appstoreconnect/private_keys"
|
|
echo "$APPLE_API_KEY_P8_BASE64" | openssl base64 -d -A > "$HOME/.appstoreconnect/private_keys/AuthKey_${APPLE_KEY_ID}.p8"
|
|
ls -la "$HOME/.appstoreconnect/private_keys/"
|
|
|
|
# ---- Flutter init + codegen + pod install ---------------------------
|
|
- name: Initialize Flutter SDK (iOS precache)
|
|
run: |
|
|
flutter --version
|
|
flutter precache --ios --no-linux --no-android --no-macos --no-windows --no-fuchsia --no-web || true
|
|
|
|
- name: Build generated code
|
|
run: bash model_generator.sh
|
|
|
|
- name: Generate localization
|
|
run: dart run tool/generate_localization.dart
|
|
|
|
- name: Compile SVG assets (res/pictures/*.svg → assets/new-ui/*.svg.vec)
|
|
run: ./compile_graphics.sh
|
|
|
|
- name: pod install
|
|
run: |
|
|
cd ios
|
|
pod install --repo-update
|
|
|
|
# ---- Override signing in Release.xcconfig for the archive step ------
|
|
# The committed project.pbxproj Release config uses Automatic signing
|
|
# + "Apple Development" identity (set up for local dev with Xcode
|
|
# signed into an Apple ID). CI can't do Automatic signing — it has
|
|
# only the cert + provisioning profile we installed in the temp
|
|
# keychain. Append manual-signing overrides to Release.xcconfig;
|
|
# xcconfig values take precedence over pbxproj defaults.
|
|
- name: Override signing settings for archive
|
|
env:
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
set -x
|
|
cat >> ios/Flutter/Release.xcconfig <<XCFG
|
|
|
|
// CI-only signing overrides (appended at build time, not committed).
|
|
CODE_SIGN_IDENTITY = Apple Distribution
|
|
CODE_SIGN_STYLE = Manual
|
|
DEVELOPMENT_TEAM = ${APPLE_TEAM_ID}
|
|
PROVISIONING_PROFILE_SPECIFIER = ${PROFILE_NAME}
|
|
XCFG
|
|
tail -8 ios/Flutter/Release.xcconfig
|
|
|
|
# ---- Generate ExportOptions.plist + build IPA -----------------------
|
|
- name: Write ExportOptions.plist
|
|
env:
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: |
|
|
cat > ios/ExportOptions.plist <<EOF
|
|
<?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>method</key>
|
|
<string>app-store</string>
|
|
<key>teamID</key>
|
|
<string>${APPLE_TEAM_ID}</string>
|
|
<key>signingStyle</key>
|
|
<string>manual</string>
|
|
<key>signingCertificate</key>
|
|
<string>Apple Distribution</string>
|
|
<key>provisioningProfiles</key>
|
|
<dict>
|
|
<key>com.suchsoftware.hashwallet</key>
|
|
<string>${PROFILE_NAME}</string>
|
|
</dict>
|
|
<key>uploadBitcode</key>
|
|
<false/>
|
|
<key>uploadSymbols</key>
|
|
<true/>
|
|
<key>destination</key>
|
|
<string>export</string>
|
|
<key>stripSwiftSymbols</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|
|
EOF
|
|
cat ios/ExportOptions.plist
|
|
|
|
- name: Build IPA
|
|
run: |
|
|
set -x -e
|
|
flutter build ipa --release \
|
|
--dart-define-from-file=env.json \
|
|
--export-options-plist=ios/ExportOptions.plist
|
|
ls -la build/ios/ipa/
|
|
|
|
- name: Upload IPA artifact
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: hash-wallet-ios-${{ github.sha }}
|
|
path: build/ios/ipa/*.ipa
|
|
retention-days: 30
|
|
|
|
# ---- Upload to TestFlight -------------------------------------------
|
|
- name: Upload to TestFlight via altool
|
|
env:
|
|
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
|
|
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
|
|
run: |
|
|
set -e
|
|
IPA=$(ls build/ios/ipa/*.ipa | head -1)
|
|
echo "Uploading $IPA to TestFlight..."
|
|
xcrun altool --upload-app \
|
|
--type ios \
|
|
--file "$IPA" \
|
|
--apiKey "$APPLE_KEY_ID" \
|
|
--apiIssuer "$APPLE_ISSUER_ID"
|
|
|
|
# ---- Cleanup keychain so we don't leak it across builds -------------
|
|
- name: Cleanup
|
|
if: always()
|
|
env:
|
|
APPLE_KEYCHAIN_PASSWORD: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
|
run: |
|
|
set +e
|
|
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain-db"
|
|
security delete-keychain "$KEYCHAIN_PATH" 2>/dev/null
|
|
rm -rf "$HOME/.appstoreconnect/private_keys"
|
|
rm -f "$HOME/Library/MobileDevice/Provisioning Profiles"/*.mobileprovision
|
|
true
|