port to androguard >= 4 and drop support for older than 3.3.3

This also makes androguard a hard requirement, which has been true for a
while anyway.  So the code that handles androguard as an optional
requirement is removed.  androguard from Debian/buster is new enough, so
this does not seem like it will cause any problems.
This commit is contained in:
Hans-Christoph Steiner 2024-04-01 11:42:23 +02:00
parent cdc7c98707
commit 7a144a4762
5 changed files with 30 additions and 35 deletions

View file

@ -2629,29 +2629,12 @@ def get_file_extension(filename):
return os.path.splitext(filename)[1].lower()[1:] return os.path.splitext(filename)[1].lower()[1:]
def use_androguard():
"""Report if androguard is available, and config its debug logging."""
try:
import androguard
if use_androguard.show_path:
logging.debug(_('Using androguard from "{path}"').format(path=androguard.__file__))
use_androguard.show_path = False
if options and options.verbose:
logging.getLogger("androguard.axml").setLevel(logging.INFO)
logging.getLogger("androguard.core.api_specific_resources").setLevel(logging.ERROR)
return True
except ImportError:
return False
use_androguard.show_path = True # type: ignore
def get_androguard_APK(apkfile): def get_androguard_APK(apkfile):
try: try:
# these were moved in androguard 4.0
from androguard.core.apk import APK
except ImportError:
from androguard.core.bytecodes.apk import APK from androguard.core.bytecodes.apk import APK
except ImportError as exc:
raise FDroidException("androguard library is not installed") from exc
return APK(apkfile) return APK(apkfile)
@ -2693,7 +2676,11 @@ def is_debuggable_or_testOnly(apkfile):
""" """
if get_file_extension(apkfile) != 'apk': if get_file_extension(apkfile) != 'apk':
return False return False
from androguard.core.bytecodes.axml import AXMLParser, format_value, START_TAG try:
# these were moved in androguard 4.0
from androguard.core.axml import AXMLParser, format_value, START_TAG
except ImportError:
from androguard.core.bytecodes.axml import AXMLParser, format_value, START_TAG
with ZipFile(apkfile) as apk: with ZipFile(apkfile) as apk:
with apk.open('AndroidManifest.xml') as manifest: with apk.open('AndroidManifest.xml') as manifest:
axml = AXMLParser(manifest.read()) axml = AXMLParser(manifest.read())
@ -2753,12 +2740,19 @@ def get_apk_id_androguard(apkfile):
versionName is set to a Android String Resource (e.g. an integer versionName is set to a Android String Resource (e.g. an integer
hex value that starts with @). hex value that starts with @).
This function is part of androguard as get_apkid(), so this
vendored and modified to return versionCode as an integer.
""" """
if not os.path.exists(apkfile): if not os.path.exists(apkfile):
raise FDroidException(_("Reading packageName/versionCode/versionName failed, APK invalid: '{apkfilename}'") raise FDroidException(_("Reading packageName/versionCode/versionName failed, APK invalid: '{apkfilename}'")
.format(apkfilename=apkfile)) .format(apkfilename=apkfile))
from androguard.core.bytecodes.axml import AXMLParser, format_value, START_TAG, END_TAG, TEXT, END_DOCUMENT try:
# these were moved in androguard 4.0
from androguard.core.axml import AXMLParser, format_value, START_TAG, END_TAG, TEXT, END_DOCUMENT
except ImportError:
from androguard.core.bytecodes.axml import AXMLParser, format_value, START_TAG, END_TAG, TEXT, END_DOCUMENT
appid = None appid = None
versionCode = None versionCode = None
@ -3159,7 +3153,7 @@ def get_first_signer_certificate(apkpath):
elif len(cert_files) == 1: elif len(cert_files) == 1:
cert_encoded = get_certificate(apk.read(cert_files[0])) cert_encoded = get_certificate(apk.read(cert_files[0]))
if not cert_encoded and use_androguard(): if not cert_encoded:
apkobject = get_androguard_APK(apkpath) apkobject = get_androguard_APK(apkpath)
certs = apkobject.get_certificates_der_v2() certs = apkobject.get_certificates_der_v2()
if len(certs) > 0: if len(certs) > 0:

View file

@ -1722,8 +1722,7 @@ def _sanitize_sdk_version(value):
def scan_apk_androguard(apk, apkfile): def scan_apk_androguard(apk, apkfile):
try: try:
from androguard.core.bytecodes.apk import APK apkobject = common.get_androguard_APK(apkfile)
apkobject = APK(apkfile)
if apkobject.is_valid_APK(): if apkobject.is_valid_APK():
arsc = apkobject.get_android_resources() arsc = apkobject.get_android_resources()
else: else:
@ -2581,7 +2580,6 @@ def main():
config = common.read_config(options) config = common.read_config(options)
common.setup_status_output(start_timestamp) common.setup_status_output(start_timestamp)
common.use_androguard()
if not (('jarsigner' in config or 'apksigner' in config) if not (('jarsigner' in config or 'apksigner' in config)
and 'keytool' in config): and 'keytool' in config):
raise FDroidException(_('Java JDK not found! Install in standard location or set java_paths!')) raise FDroidException(_('Java JDK not found! Install in standard location or set java_paths!'))

View file

@ -92,7 +92,7 @@ setup(
], ],
install_requires=[ install_requires=[
'appdirs', 'appdirs',
'androguard >= 3.1.0, != 3.3.0, != 3.3.1, != 3.3.2, <4', 'androguard >= 3.3.3',
'clint', 'clint',
'defusedxml', 'defusedxml',
'GitPython', 'GitPython',

View file

@ -8,7 +8,9 @@ echo_header() {
get_fdroid_apk_filename() { get_fdroid_apk_filename() {
if [ -z $aapt ]; then if [ -z $aapt ]; then
python3 -c "from androguard.core.bytecodes.apk import APK; a=APK('$1'); print(a.package+'_'+a.get_androidversion_code()+'.apk')" appid=$(androguard apkid "$1" | sed -En 's/ +"([a-z][^"]+)",$/\1/ip')
versionCode=$(androguard apkid "$1" | sed -En 's/ +"([0-9]+)",$/\1/p')
echo "${appid}_${versionCode}.apk"
else else
$aapt dump badging "$1" | sed -n "s,^package: name='\(.*\)' versionCode='\([0-9][0-9]*\)' .*,\1_\2.apk,p" $aapt dump badging "$1" | sed -n "s,^package: name='\(.*\)' versionCode='\([0-9][0-9]*\)' .*,\1_\2.apk,p"
fi fi

View file

@ -5,6 +5,7 @@
import copy import copy
import git import git
import glob import glob
import hashlib
import inspect import inspect
import json import json
import logging import logging
@ -20,11 +21,18 @@ import unittest
import yaml import yaml
import zipfile import zipfile
import textwrap import textwrap
from binascii import hexlify
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
from testcommon import TmpCwd, mkdtemp from testcommon import TmpCwd, mkdtemp
from unittest import mock from unittest import mock
try:
# these were moved in androguard 4.0
from androguard.core.apk import APK
except ImportError:
from androguard.core.bytecodes.apk import APK
try: try:
from yaml import CSafeLoader as SafeLoader from yaml import CSafeLoader as SafeLoader
except ImportError: except ImportError:
@ -581,13 +589,6 @@ class UpdateTest(unittest.TestCase):
self.assertEqual(good_fingerprint, sig, self.assertEqual(good_fingerprint, sig,
'python sig was: ' + str(sig)) 'python sig was: ' + str(sig))
# check that v1 and v2 have the same certificate # check that v1 and v2 have the same certificate
try:
import hashlib
from binascii import hexlify
from androguard.core.bytecodes.apk import APK
except ImportError:
print('WARNING: skipping rest of test since androguard is missing!')
return
apkobject = APK(apkpath) apkobject = APK(apkpath)
cert_encoded = apkobject.get_certificates_der_v2()[0] cert_encoded = apkobject.get_certificates_der_v2()[0]
self.assertEqual(good_fingerprint, sig, self.assertEqual(good_fingerprint, sig,