mirror of
https://github.com/flectar/mail.git
synced 2026-11-11 17:57:54 +00:00
106 lines
5.2 KiB
Bash
Executable File
106 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
project_dir="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
|
|
apk="${1:-$project_dir/target/android/release/apk/flectar-mail.apk}"
|
|
signing_mode="${2:-test}"
|
|
android_sdk="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}"
|
|
|
|
if [[ ! -f "$apk" ]]; then
|
|
printf 'APK not found: %s\n' "$apk" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$android_sdk" || ! -d "$android_sdk/build-tools" ]]; then
|
|
printf 'Android SDK build-tools not found. Set ANDROID_HOME.\n' >&2
|
|
exit 1
|
|
fi
|
|
|
|
build_tools="$(find "$android_sdk/build-tools" -mindepth 1 -maxdepth 1 -type d -print | sort -V | tail -n 1)"
|
|
aapt="$build_tools/aapt"
|
|
apksigner="$build_tools/apksigner"
|
|
if [[ ! -x "$aapt" || ! -x "$apksigner" ]]; then
|
|
printf 'aapt/apksigner not found under %s\n' "$build_tools" >&2
|
|
exit 1
|
|
fi
|
|
|
|
badging="$($aapt dump badging "$apk")"
|
|
xmltree="$($aapt dump xmltree "$apk" AndroidManifest.xml)"
|
|
|
|
assert_contains() {
|
|
local haystack="$1"
|
|
local needle="$2"
|
|
local description="$3"
|
|
if [[ "$haystack" != *"$needle"* ]]; then
|
|
printf 'APK verification failed: %s (missing %s)\n' "$description" "$needle" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
assert_contains "$badging" "package: name='com.flectar.mail'" 'package identity'
|
|
if [[ -n "${FLECTAR_ANDROID_VERSION_NAME:-}" ]]; then
|
|
assert_contains "$badging" "versionName='$FLECTAR_ANDROID_VERSION_NAME'" 'release version name'
|
|
fi
|
|
if [[ "$signing_mode" == production && -n "${FLECTAR_ANDROID_VERSION_NAME:-}" ]]; then
|
|
expected_code="$(python3 "$project_dir/scripts/android-version-code.py" "$FLECTAR_ANDROID_VERSION_NAME")"
|
|
assert_contains "$badging" "versionCode='$expected_code'" 'shared release version code'
|
|
elif [[ -n "${FLECTAR_ANDROID_VERSION_CODE:-}" ]]; then
|
|
assert_contains "$badging" "versionCode='$FLECTAR_ANDROID_VERSION_CODE'" 'release version code'
|
|
fi
|
|
assert_contains "$badging" "sdkVersion:'26'" 'minimum SDK'
|
|
assert_contains "$badging" "targetSdkVersion:'36'" 'target SDK'
|
|
assert_contains "$badging" "uses-permission: name='android.permission.INTERNET'" 'network permission'
|
|
assert_contains "$badging" "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'" 'network-state permission'
|
|
assert_contains "$badging" "uses-permission: name='android.permission.POST_NOTIFICATIONS'" 'notification permission declaration'
|
|
assert_contains "$badging" "uses-permission: name='android.permission.RECEIVE_BOOT_COMPLETED'" 'persisted mail check permission'
|
|
assert_contains "$badging" "native-code: 'arm64-v8a'" 'arm64 ABI'
|
|
assert_contains "$badging" 'application-icon-' 'launcher icon'
|
|
assert_contains "$xmltree" 'android:usesCleartextTraffic(0x010104ec)=(type 0x12)0x0' 'cleartext traffic disabled'
|
|
assert_contains "$xmltree" 'android:scheme(0x01010027)="msauth"' 'Microsoft OAuth callback scheme'
|
|
assert_contains "$xmltree" 'android:host(0x01010028)="com.flectar.mail"' 'Microsoft OAuth callback host'
|
|
assert_contains "$xmltree" 'android:exported(0x01010010)=(type 0x12)0xffffffff' 'explicitly exported callback/launcher Activity'
|
|
assert_contains "$xmltree" 'com.flectar.mail.FlectarActivity' 'Google AuthorizationClient Activity host'
|
|
assert_contains "$xmltree" 'com.flectar.mail.NotificationActionReceiver' 'notification button receiver'
|
|
assert_contains "$xmltree" 'com.flectar.mail.MailCheckJob' 'background mail check job'
|
|
assert_contains "$xmltree" 'android.permission.BIND_JOB_SERVICE' 'mail check job binding permission'
|
|
assert_contains "$xmltree" 'android:allowBackup(0x01010280)=(type 0x12)0x0' 'Android backup disabled'
|
|
|
|
if [[ "$badging" == *"application-debuggable"* ]]; then
|
|
printf 'APK verification failed: release application is debuggable\n' >&2
|
|
exit 1
|
|
fi
|
|
if [[ "$badging" == *"'x86'"* || "$badging" == *"'x86_64'"* ]]; then
|
|
printf 'APK verification failed: release artifact contains an emulator ABI\n' >&2
|
|
exit 1
|
|
fi
|
|
archive_listing="$(unzip -l "$apk")"
|
|
if [[ "$archive_listing" != *'classes.dex'* ]]; then
|
|
printf 'APK verification failed: Google Play Services bridge classes are absent\n' >&2
|
|
exit 1
|
|
fi
|
|
|
|
python3 "$project_dir/scripts/verify-android-native.py" "$apk"
|
|
|
|
signing="$($apksigner verify --verbose --print-certs "$apk")"
|
|
printf '%s\n' "$signing"
|
|
signing_args=("$signing_mode")
|
|
if [[ "$signing_mode" == production || "${CI:-}" == true || "${GITHUB_ACTIONS:-}" == true ]]; then
|
|
# Published previews and stable releases must match the same committed
|
|
# certificate. Verification needs no access to the private key or password.
|
|
expected_sha256="$(cat "$project_dir/platform/android/app-signing-certificate.sha256")"
|
|
elif [[ "$signing_mode" == test ]]; then
|
|
data_home="${XDG_DATA_HOME:-$HOME/.local/share}"
|
|
keystore="${FLECTAR_ANDROID_TEST_KEYSTORE:-$data_home/flectar-mail/android/test-signing.keystore}"
|
|
if [[ ! -f "$keystore" ]]; then
|
|
printf 'Expected test keystore not found: %s\n' "$keystore" >&2
|
|
exit 1
|
|
fi
|
|
# Local development keys are unrelated to the published app identity.
|
|
expected_sha256="$(keytool -exportcert -keystore "$keystore" -alias androiddebugkey -storepass android | sha256sum)"
|
|
else
|
|
printf 'Unknown Android signing mode: %s\n' "$signing_mode" >&2
|
|
exit 1
|
|
fi
|
|
signing_args+=(--expected-sha256 "${expected_sha256%% *}")
|
|
printf '%s\n' "$signing" | python3 "$project_dir/scripts/verify-android-signing.py" "${signing_args[@]}"
|
|
printf 'Verified Android package metadata, arm64 ABI, TLS policy, and signing: %s\n' "$apk"
|