verify-build.sh 5.7 KB

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