verify-build.sh 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #!/usr/bin/env bash
  2. #
  3. # A script to verify that a locally compiled APK matches the released APK.
  4. set -euo pipefail
  5. GREEN="\033[0;32m"
  6. RED="\033[0;31m"
  7. YELLOW="\033[1;33m"
  8. RESET="\033[0m"
  9. function print_usage() {
  10. echo "Usage: $0 -n <version-name> -v <variant> -p <published-apk> [-l <local-apk>]"
  11. echo ""
  12. echo "Options:"
  13. echo " -n <version-name> The version name. Example: '4.43k'"
  14. echo " -v <variant> Variant to verify: Either googleplay_private, threemashop_private, libre_private or hms_private"
  15. echo " -p <published-apk> Path to the APK file extracted from the phone"
  16. echo " -l <local-apk> Optional: Path to the locally built APK"
  17. echo " -h,--help Print this help and exit"
  18. }
  19. function log() {
  20. echo -en "$1"
  21. echo -n "$2 $3"
  22. echo -e "$RESET"
  23. }
  24. function log_major() { log "$GREEN" "==>" "$1"; }
  25. function log_minor() { log "$GREEN" "--> " "$1"; }
  26. function log_warning() { log "$YELLOW" "==>" "$1"; }
  27. function log_error() { log "$RED" "!!!" "Error: $1"; }
  28. function fail() {
  29. log_error "$1"
  30. exit 1
  31. }
  32. # Re-implementation of realpath function (hello macOS)
  33. function realpath() {
  34. OURPWD=$PWD
  35. cd "$(dirname "$1")"
  36. LINK=$(readlink "$(basename "$1")")
  37. while [ "$LINK" ]; do
  38. cd "$(dirname "$LINK")"
  39. LINK=$(readlink "$(basename "$1")")
  40. done
  41. REALPATH="$PWD/$(basename "$1")"
  42. cd "$OURPWD"
  43. echo "$REALPATH"
  44. }
  45. # Determine script directory
  46. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
  47. # If no arguments are passed, print usage
  48. if [ "$#" -lt 1 ]; then print_usage; exit 1; fi
  49. # Parse arguments
  50. name=""
  51. variant=""
  52. published_apk=""
  53. local_apk=""
  54. while [[ "$#" -gt 0 ]]; do
  55. case $1 in
  56. -n) name="$2"; shift ;;
  57. -v) variant="$2"; shift ;;
  58. -p) published_apk="$2"; shift ;;
  59. -l) local_apk="$2"; shift ;;
  60. -h|--help) print_usage; exit 0 ;;
  61. *) echo "Unknown parameter passed: $1"; print_usage; exit 1 ;;
  62. esac
  63. shift
  64. done
  65. # Process arguments
  66. if [[ "$name" == "" || "$name" == .* ]]; then
  67. log_error 'Please set a valid version name with "-n <name>".'
  68. fail 'Example: "-n 4.43k"'
  69. fi
  70. if [[ "$published_apk" == "" ]]; then
  71. log_error 'Please set a valid published APK path with "-p <path>".'
  72. fail 'Example: "-p threema-extracted.apk"'
  73. fi
  74. published_apk=$(realpath "$published_apk")
  75. if [[ "$variant" == "" ]]; then
  76. log_error 'Please set a valid build variant with "-v <variant>".'
  77. fail 'Example: "-v googleplay_private" or "-v threemashop_private"'
  78. fi
  79. case "$variant" in
  80. googleplay_private) variant_name="store_google" ;;
  81. threemashop_private) variant_name="store_threema" ;;
  82. libre_private) variant_name="libre" ;;
  83. hms_private) variant_name="hms" ;;
  84. *) fail "Invalid build variant: $variant" ;;
  85. esac
  86. # Validate target directory
  87. targetdir=$(realpath "$DIR/../reproduce")
  88. if [[ -d "$targetdir" ]]; then
  89. fail "The directory $targetdir already exists. Please remove it first."
  90. fi
  91. mkdir -p "$targetdir"/{published,local}
  92. # Unpack published APK
  93. if [[ ! -f "$published_apk" ]]; then
  94. fail "The published APK $published_apk could not be found."
  95. fi
  96. log_major "Unpacking published APK"
  97. unzip -q -d "$targetdir/published/" "$published_apk"
  98. # Determine local APK path
  99. if [[ "$local_apk" == "" ]]; then
  100. log_major "Determine local APK path"
  101. lib_count="$(find "$targetdir/published/lib/" -mindepth 1 -maxdepth 1 -type d | wc -l | xargs)"
  102. log_minor "Found $lib_count libs"
  103. case "$lib_count" in
  104. 1) architecture="$(ls "$targetdir/published/lib/")" ;;
  105. 4) architecture="universal" ;;
  106. *) fail "Could not determine architecture of published APK"
  107. esac
  108. log_minor "Architecture: $architecture"
  109. if [ -f "$DIR/../release/$name/$variant/app-$variant_name-$architecture-release-unsigned.apk" ]; then
  110. local_apk="$(realpath "$DIR/../release/$name/$variant/app-$variant_name-$architecture-release-unsigned.apk")"
  111. else
  112. local_apk="$(realpath "$DIR/../release/$name/$variant/app-$variant_name-$architecture-release.apk")"
  113. fi
  114. fi
  115. if [[ ! -f "$local_apk" ]]; then
  116. fail "The local APK $local_apk could not be found."
  117. fi
  118. log_major "Comparing the following APKs:"
  119. log_minor "Published: $published_apk"
  120. log_minor "Local: $local_apk"
  121. # Unpack local APK
  122. log_major "Unpacking local APK"
  123. unzip -q -d "$targetdir/local/" "$local_apk"
  124. # Remove meta information (containing things like the signature)
  125. log_major "Removing meta information, containing things like the app signature:"
  126. for path in META-INF/ resources.arsc; do
  127. for target in local published; do
  128. log_minor "rm -r $target/$path"
  129. rm -r "${targetdir:?}/${target:?}/${path:?}"
  130. done
  131. done
  132. # Diff!
  133. log_major "Comparing releases"
  134. diff -r "$targetdir/local/" "$targetdir/published/" && success=1 || success=0
  135. if [ $success -eq 1 ]; then
  136. log_major "Success! The APKs match."
  137. else
  138. log_warning "APK could not be verified."
  139. log_warning "Don't panic! First, make sure that you have compiled the correct version!"
  140. log_warning "If you cannot figure out why the verification failed,"
  141. log_warning "send us an e-mail to opensource@threema.ch containing the log above."
  142. exit 2
  143. fi