add apns supports.

This commit is contained in:
aria committed 2026-04-23 15:38:20 +09:00
1 parent 855d24bc64
commit 21c392db8f
6 files changed
+442 -31

No files matched your search

+144 -22
View File
@@ -1,7 +1,9 @@
#!/usr/bin/env bash
set -u
ENTITLEMENT_KEY="com.apple.developer.networking.HotspotConfiguration"
HOTSPOT_ENTITLEMENT_KEY="com.apple.developer.networking.HotspotConfiguration"
APNS_ENTITLEMENT_KEY="aps-environment"
CHECK_SCRIPT_VERSION="2026-04-23.3"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TIMESTAMP="$(date '+%Y%m%d-%H%M%S')"
@@ -23,8 +25,9 @@ Usage:
$(basename "$0") /path/to/App.ipa
Checks:
1. embedded.mobileprovision contains ${ENTITLEMENT_KEY}=true
2. App executable appears to contain ${ENTITLEMENT_KEY}=true
1. embedded.mobileprovision contains ${HOTSPOT_ENTITLEMENT_KEY}=true
2. embedded.mobileprovision contains ${APNS_ENTITLEMENT_KEY}=development|production
3. App executable appears to contain both signed entitlements
Notes:
Linux cannot run Apple's codesign tool. The executable check is a best-effort
@@ -59,22 +62,32 @@ has_command() {
extract_plist_from_binary() {
local source_file="$1"
local target_file="$2"
local needle="${3:-}"
python3 - "$source_file" "$target_file" <<'PY'
python3 - "$source_file" "$target_file" "$needle" <<'PY'
import sys
from pathlib import Path
source = Path(sys.argv[1])
target = Path(sys.argv[2])
needle = sys.argv[3].encode("utf-8") if len(sys.argv) > 3 and sys.argv[3] else b""
data = source.read_bytes()
start = data.find(b"<?xml")
if start < 0:
start = data.find(b"<plist")
needle_index = data.find(needle) if needle else -1
if needle_index >= 0:
start = data.rfind(b"<?xml", 0, needle_index)
if start < 0:
start = data.rfind(b"<plist", 0, needle_index)
end = data.find(b"</plist>", needle_index)
else:
start = data.find(b"<?xml")
if start < 0:
start = data.find(b"<plist")
end = data.find(b"</plist>", start if start >= 0 else 0)
if start < 0:
sys.exit(2)
end = data.find(b"</plist>", start)
if end < 0:
sys.exit(3)
@@ -97,7 +110,28 @@ key = sys.argv[2]
data = path.read_bytes()
try:
value = plistlib.loads(data).get(key)
plist = plistlib.loads(data)
values = []
def collect(obj):
if isinstance(obj, dict):
if key in obj:
values.append(obj.get(key))
entitlements = obj.get("Entitlements")
if isinstance(entitlements, dict) and key in entitlements:
values.append(entitlements.get(key))
for value in obj.values():
if isinstance(value, (dict, list, tuple)):
collect(value)
elif isinstance(obj, (list, tuple)):
for value in obj:
if isinstance(value, (dict, list, tuple)):
collect(value)
collect(plist)
value = values[0] if values else None
if value is True:
print("true")
sys.exit(0)
@@ -123,6 +157,63 @@ except Exception:
PY
}
check_plist_key_string_allowed() {
local plist_file="$1"
local key="$2"
shift 2
python3 - "$plist_file" "$key" "$@" <<'PY'
import plistlib
import re
import sys
from pathlib import Path
path = Path(sys.argv[1])
key = sys.argv[2]
allowed = set(sys.argv[3:])
data = path.read_bytes()
def finish(value):
if value is None:
print("missing")
sys.exit(1)
print(value)
if str(value) in allowed:
sys.exit(0)
sys.exit(2)
try:
plist = plistlib.loads(data)
values = []
def collect(obj):
if isinstance(obj, dict):
if key in obj:
values.append(obj.get(key))
entitlements = obj.get("Entitlements")
if isinstance(entitlements, dict) and key in entitlements:
values.append(entitlements.get(key))
for value in obj.values():
if isinstance(value, (dict, list, tuple)):
collect(value)
elif isinstance(obj, (list, tuple)):
for value in obj:
if isinstance(value, (dict, list, tuple)):
collect(value)
collect(plist)
finish(values[0] if values else None)
except Exception:
text = data.decode("utf-8", errors="ignore")
pattern = re.compile(
r"<key>\s*" + re.escape(key) + r"\s*</key>\s*<string>\s*([^<]+?)\s*</string>",
re.IGNORECASE,
)
match = pattern.search(text)
finish(match.group(1).strip() if match else None)
PY
}
find_main_executable() {
local app_dir="$1"
local info_plist="${app_dir}/Info.plist"
@@ -157,7 +248,8 @@ print_section() {
echo "==== $* ===="
}
echo "iOS Hotspot Configuration Signature Check"
echo "iOS Hotspot/APNs Signature Check"
echo "Checker version: ${CHECK_SCRIPT_VERSION}"
echo "Started: $(date -Is)"
echo "Script: ${BASH_SOURCE[0]}"
echo "Log: ${LOG_FILE}"
@@ -246,43 +338,71 @@ if [[ "${PROFILE_EXTRACTED}" -eq 0 ]]; then
fi
fi
PROFILE_RESULT="$(check_plist_key_true "${PROFILE_PLIST}" "${ENTITLEMENT_KEY}" 2>&1)"
PROFILE_RESULT="$(check_plist_key_true "${PROFILE_PLIST}" "${HOTSPOT_ENTITLEMENT_KEY}" 2>&1)"
PROFILE_STATUS=$?
echo "Profile entitlement value: ${PROFILE_RESULT}"
echo "Profile Hotspot entitlement value: ${PROFILE_RESULT}"
if [[ "${PROFILE_STATUS}" -eq 0 ]]; then
pass "Provisioning profile contains ${ENTITLEMENT_KEY}=true"
pass "Provisioning profile contains ${HOTSPOT_ENTITLEMENT_KEY}=true"
else
fail "Provisioning profile does not contain ${ENTITLEMENT_KEY}=true"
fail "Provisioning profile does not contain ${HOTSPOT_ENTITLEMENT_KEY}=true"
fi
PROFILE_APNS_RESULT="$(check_plist_key_string_allowed "${PROFILE_PLIST}" "${APNS_ENTITLEMENT_KEY}" development production 2>&1)"
PROFILE_APNS_STATUS=$?
echo "Profile APNs entitlement value: ${PROFILE_APNS_RESULT}"
if [[ "${PROFILE_APNS_STATUS}" -eq 0 ]]; then
pass "Provisioning profile contains ${APNS_ENTITLEMENT_KEY}=${PROFILE_APNS_RESULT}"
else
fail "Provisioning profile does not contain ${APNS_ENTITLEMENT_KEY}=development|production"
fi
echo
echo "Profile entitlement context:"
grep -n -A2 -B1 "${ENTITLEMENT_KEY}" "${PROFILE_PLIST}" || true
grep -n -A2 -B1 "${HOTSPOT_ENTITLEMENT_KEY}" "${PROFILE_PLIST}" || true
grep -n -A2 -B1 "${APNS_ENTITLEMENT_KEY}" "${PROFILE_PLIST}" || true
print_section "Signed App Entitlements"
echo "Linux cannot run Apple's codesign. This is a best-effort scan of the app executable."
if grep -a -q "${ENTITLEMENT_KEY}" "${EXECUTABLE_PATH}"; then
pass "Executable contains entitlement key string: ${ENTITLEMENT_KEY}"
if grep -a -q "${HOTSPOT_ENTITLEMENT_KEY}" "${EXECUTABLE_PATH}"; then
pass "Executable contains entitlement key string: ${HOTSPOT_ENTITLEMENT_KEY}"
else
fail "Executable does not contain entitlement key string. Signed app entitlements likely do not include Hotspot Configuration."
fi
if grep -a -q "${APNS_ENTITLEMENT_KEY}" "${EXECUTABLE_PATH}"; then
pass "Executable contains entitlement key string: ${APNS_ENTITLEMENT_KEY}"
else
fail "Executable does not contain entitlement key string. Signed app entitlements likely do not include APNs aps-environment."
fi
EXEC_ENTITLEMENTS_PLIST="${WORK_DIR}/signed-entitlements-heuristic.plist"
if extract_plist_from_binary "${EXECUTABLE_PATH}" "${EXEC_ENTITLEMENTS_PLIST}"; then
if extract_plist_from_binary "${EXECUTABLE_PATH}" "${EXEC_ENTITLEMENTS_PLIST}" "${HOTSPOT_ENTITLEMENT_KEY}"; then
echo "Extracted executable plist candidate: ${EXEC_ENTITLEMENTS_PLIST}"
EXEC_RESULT="$(check_plist_key_true "${EXEC_ENTITLEMENTS_PLIST}" "${ENTITLEMENT_KEY}" 2>&1)"
EXEC_RESULT="$(check_plist_key_true "${EXEC_ENTITLEMENTS_PLIST}" "${HOTSPOT_ENTITLEMENT_KEY}" 2>&1)"
EXEC_STATUS=$?
echo "Executable entitlement value: ${EXEC_RESULT}"
echo "Executable Hotspot entitlement value: ${EXEC_RESULT}"
if [[ "${EXEC_STATUS}" -eq 0 ]]; then
pass "Executable plist candidate contains ${ENTITLEMENT_KEY}=true"
pass "Executable plist candidate contains ${HOTSPOT_ENTITLEMENT_KEY}=true"
else
warn "Executable contains entitlement key, but extracted plist candidate did not prove value=true."
warn "Use macOS codesign for authoritative validation."
fi
EXEC_APNS_RESULT="$(check_plist_key_string_allowed "${EXEC_ENTITLEMENTS_PLIST}" "${APNS_ENTITLEMENT_KEY}" development production 2>&1)"
EXEC_APNS_STATUS=$?
echo "Executable APNs entitlement value: ${EXEC_APNS_RESULT}"
if [[ "${EXEC_APNS_STATUS}" -eq 0 ]]; then
pass "Executable plist candidate contains ${APNS_ENTITLEMENT_KEY}=${EXEC_APNS_RESULT}"
else
warn "Executable contains APNs entitlement key, but extracted plist candidate did not prove value=development|production."
warn "Use macOS codesign for authoritative validation."
fi
echo
echo "Executable entitlement context:"
grep -n -A2 -B1 "${ENTITLEMENT_KEY}" "${EXEC_ENTITLEMENTS_PLIST}" || true
grep -n -A2 -B1 "${HOTSPOT_ENTITLEMENT_KEY}" "${EXEC_ENTITLEMENTS_PLIST}" || true
grep -n -A2 -B1 "${APNS_ENTITLEMENT_KEY}" "${EXEC_ENTITLEMENTS_PLIST}" || true
else
warn "Could not extract XML plist from executable. Key string was present, but value=true was not proven."
warn "Use macOS codesign for authoritative validation."
@@ -290,7 +410,9 @@ fi
print_section "Summary"
pass "Provisioning profile Hotspot entitlement: true"
pass "Provisioning profile APNs entitlement: ${PROFILE_APNS_RESULT}"
pass "Executable Hotspot entitlement key: present"
pass "Executable APNs entitlement key: present"
echo
echo "Full log written to:"
echo " ${LOG_FILE}"