mirror of
				https://github.com/f-droid/fdroidserver.git
				synced 2025-11-04 06:30:27 +03:00 
			
		
		
		
	use androguard if aapt isn't found
This commit is contained in:
		
							parent
							
								
									9607cdb621
								
							
						
					
					
						commit
						06598ae406
					
				
					 8 changed files with 490 additions and 111 deletions
				
			
		| 
						 | 
					@ -483,15 +483,23 @@ def capitalize_intact(string):
 | 
				
			||||||
    return string[0].upper() + string[1:]
 | 
					    return string[0].upper() + string[1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_metadata_from_apk(app, build, apkfile):
 | 
					def has_native_code(apkobj):
 | 
				
			||||||
    """get the required metadata from the built APK"""
 | 
					    """aapt checks if there are architecture folders under the lib/ folder
 | 
				
			||||||
 | 
					    so we are simulating the same behaviour"""
 | 
				
			||||||
 | 
					    arch_re = re.compile("^lib/(.*)/.*$")
 | 
				
			||||||
 | 
					    arch = [file for file in apkobj.get_files() if arch_re.match(file)]
 | 
				
			||||||
 | 
					    return False if not arch else True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_apk_metadata_aapt(apkfile):
 | 
				
			||||||
 | 
					    """aapt function to extract versionCode, versionName, packageName and nativecode"""
 | 
				
			||||||
    vercode = None
 | 
					    vercode = None
 | 
				
			||||||
    version = None
 | 
					    version = None
 | 
				
			||||||
    foundid = None
 | 
					    foundid = None
 | 
				
			||||||
    nativecode = None
 | 
					    nativecode = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for line in p.output.splitlines():
 | 
					    for line in p.output.splitlines():
 | 
				
			||||||
        if line.startswith("package:"):
 | 
					        if line.startswith("package:"):
 | 
				
			||||||
            pat = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
 | 
					            pat = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
 | 
				
			||||||
| 
						 | 
					@ -509,6 +517,38 @@ def get_metadata_from_apk(app, build, apkfile):
 | 
				
			||||||
        elif line.startswith("native-code:"):
 | 
					        elif line.startswith("native-code:"):
 | 
				
			||||||
            nativecode = line[12:]
 | 
					            nativecode = line[12:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return vercode, version, foundid, nativecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_apk_metadata_androguard(apkfile):
 | 
				
			||||||
 | 
					    """androguard function to extract versionCode, versionName, packageName and nativecode"""
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        from androguard.core.bytecodes.apk import APK
 | 
				
			||||||
 | 
					        apkobject = APK(apkfile)
 | 
				
			||||||
 | 
					    except ImportError:
 | 
				
			||||||
 | 
					        raise BuildException("androguard library is not installed and aapt binary not found")
 | 
				
			||||||
 | 
					    except FileNotFoundError:
 | 
				
			||||||
 | 
					        raise BuildException("Could not open apk file for metadata analysis")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not apkobject.is_valid_APK():
 | 
				
			||||||
 | 
					        raise BuildException("Invalid APK provided")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    foundid = apkobject.get_package()
 | 
				
			||||||
 | 
					    vercode = apkobject.get_androidversion_code()
 | 
				
			||||||
 | 
					    version = apkobject.get_androidversion_name()
 | 
				
			||||||
 | 
					    nativecode = has_native_code(apkobject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return vercode, version, foundid, nativecode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_metadata_from_apk(app, build, apkfile):
 | 
				
			||||||
 | 
					    """get the required metadata from the built APK"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if common.set_command_in_config('aapt'):
 | 
				
			||||||
 | 
					        vercode, version, foundid, nativecode = get_apk_metadata_aapt(apkfile)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        vercode, version, foundid, nativecode = get_apk_metadata_androguard(apkfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Ignore empty strings or any kind of space/newline chars that we don't
 | 
					    # Ignore empty strings or any kind of space/newline chars that we don't
 | 
				
			||||||
    # care about
 | 
					    # care about
 | 
				
			||||||
    if nativecode is not None:
 | 
					    if nativecode is not None:
 | 
				
			||||||
| 
						 | 
					@ -533,7 +573,6 @@ def get_metadata_from_apk(app, build, apkfile):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, extlib_dir, tmp_dir, force, onserver, refresh):
 | 
					def build_local(app, build, vcs, build_dir, output_dir, log_dir, srclib_dir, extlib_dir, tmp_dir, force, onserver, refresh):
 | 
				
			||||||
    """Do a build locally."""
 | 
					    """Do a build locally."""
 | 
				
			||||||
 | 
					 | 
				
			||||||
    ndk_path = build.ndk_path()
 | 
					    ndk_path = build.ndk_path()
 | 
				
			||||||
    if build.ndk or (build.buildjni and build.buildjni != ['no']):
 | 
					    if build.ndk or (build.buildjni and build.buildjni != ['no']):
 | 
				
			||||||
        if not ndk_path:
 | 
					        if not ndk_path:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,8 @@ from pyasn1.codec.der import decoder, encoder
 | 
				
			||||||
from pyasn1_modules import rfc2315
 | 
					from pyasn1_modules import rfc2315
 | 
				
			||||||
from pyasn1.error import PyAsn1Error
 | 
					from pyasn1.error import PyAsn1Error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from distutils.util import strtobool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import fdroidserver.metadata
 | 
					import fdroidserver.metadata
 | 
				
			||||||
from .asynchronousfilereader import AsynchronousFileReader
 | 
					from .asynchronousfilereader import AsynchronousFileReader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1690,14 +1692,7 @@ def get_file_extension(filename):
 | 
				
			||||||
    return os.path.splitext(filename)[1].lower()[1:]
 | 
					    return os.path.splitext(filename)[1].lower()[1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def isApkAndDebuggable(apkfile, config):
 | 
					def get_apk_debuggable_aapt(apkfile):
 | 
				
			||||||
    """Returns True if the given file is an APK and is debuggable
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    :param apkfile: full path to the apk to check"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if get_file_extension(apkfile) != 'apk':
 | 
					 | 
				
			||||||
        return False
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    p = SdkToolsPopen(['aapt', 'dump', 'xmltree', apkfile, 'AndroidManifest.xml'],
 | 
					    p = SdkToolsPopen(['aapt', 'dump', 'xmltree', apkfile, 'AndroidManifest.xml'],
 | 
				
			||||||
                      output=False)
 | 
					                      output=False)
 | 
				
			||||||
    if p.returncode != 0:
 | 
					    if p.returncode != 0:
 | 
				
			||||||
| 
						 | 
					@ -1709,6 +1704,35 @@ def isApkAndDebuggable(apkfile, config):
 | 
				
			||||||
    return False
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_apk_debuggable_androguard(apkfile):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        from androguard.core.bytecodes.apk import APK
 | 
				
			||||||
 | 
					    except ImportError:
 | 
				
			||||||
 | 
					        logging.critical("androguard library is not installed and aapt not present")
 | 
				
			||||||
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apkobject = APK(apkfile)
 | 
				
			||||||
 | 
					    if apkobject.is_valid_APK():
 | 
				
			||||||
 | 
					        debuggable = apkobject.get_element("application", "debuggable")
 | 
				
			||||||
 | 
					        if debuggable is not None:
 | 
				
			||||||
 | 
					            return bool(strtobool(debuggable))
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def isApkAndDebuggable(apkfile, config):
 | 
				
			||||||
 | 
					    """Returns True if the given file is an APK and is debuggable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    :param apkfile: full path to the apk to check"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if get_file_extension(apkfile) != 'apk':
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if set_command_in_config('aapt'):
 | 
				
			||||||
 | 
					        return get_apk_debuggable_aapt(apkfile)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return get_apk_debuggable_androguard(apkfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PopenResult:
 | 
					class PopenResult:
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        self.returncode = None
 | 
					        self.returncode = None
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ from . import btlog
 | 
				
			||||||
from . import common
 | 
					from . import common
 | 
				
			||||||
from . import index
 | 
					from . import index
 | 
				
			||||||
from . import metadata
 | 
					from . import metadata
 | 
				
			||||||
from .common import SdkToolsPopen
 | 
					from .common import BuildException, SdkToolsPopen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
METADATA_VERSION = 18
 | 
					METADATA_VERSION = 18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,6 +60,17 @@ APK_PERMISSION_PAT = \
 | 
				
			||||||
APK_FEATURE_PAT = re.compile(".*name='([^']*)'.*")
 | 
					APK_FEATURE_PAT = re.compile(".*name='([^']*)'.*")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
screen_densities = ['640', '480', '320', '240', '160', '120']
 | 
					screen_densities = ['640', '480', '320', '240', '160', '120']
 | 
				
			||||||
 | 
					screen_resolutions = {
 | 
				
			||||||
 | 
					    "xxxhdpi": '640',
 | 
				
			||||||
 | 
					    "xxhdpi": '480',
 | 
				
			||||||
 | 
					    "xhdpi": '320',
 | 
				
			||||||
 | 
					    "hdpi": '240',
 | 
				
			||||||
 | 
					    "mdpi": '160',
 | 
				
			||||||
 | 
					    "ldpi": '120',
 | 
				
			||||||
 | 
					    "undefined": '-1',
 | 
				
			||||||
 | 
					    "anydpi": '65534',
 | 
				
			||||||
 | 
					    "nodpi": '65535'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all_screen_densities = ['0'] + screen_densities
 | 
					all_screen_densities = ['0'] + screen_densities
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -871,6 +882,196 @@ def scan_repo_files(apkcache, repodir, knownapks, use_date_from_file=False):
 | 
				
			||||||
    return repo_files, cachechanged
 | 
					    return repo_files, cachechanged
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def scan_apk_aapt(apk, apkfile):
 | 
				
			||||||
 | 
					    p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
 | 
				
			||||||
 | 
					    if p.returncode != 0:
 | 
				
			||||||
 | 
					        if options.delete_unknown:
 | 
				
			||||||
 | 
					            if os.path.exists(apkfile):
 | 
				
			||||||
 | 
					                logging.error("Failed to get apk information, deleting " + apkfile)
 | 
				
			||||||
 | 
					                os.remove(apkfile)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                logging.error("Could not find {0} to remove it".format(apkfile))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            logging.error("Failed to get apk information, skipping " + apkfile)
 | 
				
			||||||
 | 
					        raise BuildException("Invaild APK")
 | 
				
			||||||
 | 
					    for line in p.output.splitlines():
 | 
				
			||||||
 | 
					        if line.startswith("package:"):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                apk['packageName'] = re.match(APK_NAME_PAT, line).group(1)
 | 
				
			||||||
 | 
					                apk['versionCode'] = int(re.match(APK_VERCODE_PAT, line).group(1))
 | 
				
			||||||
 | 
					                apk['versionName'] = re.match(APK_VERNAME_PAT, line).group(1)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                logging.error("Package matching failed: " + str(e))
 | 
				
			||||||
 | 
					                logging.info("Line was: " + line)
 | 
				
			||||||
 | 
					                sys.exit(1)
 | 
				
			||||||
 | 
					        elif line.startswith("application:"):
 | 
				
			||||||
 | 
					            apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
 | 
				
			||||||
 | 
					            # Keep path to non-dpi icon in case we need it
 | 
				
			||||||
 | 
					            match = re.match(APK_ICON_PAT_NODPI, line)
 | 
				
			||||||
 | 
					            if match:
 | 
				
			||||||
 | 
					                apk['icons_src']['-1'] = match.group(1)
 | 
				
			||||||
 | 
					        elif line.startswith("launchable-activity:"):
 | 
				
			||||||
 | 
					            # Only use launchable-activity as fallback to application
 | 
				
			||||||
 | 
					            if not apk['name']:
 | 
				
			||||||
 | 
					                apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
 | 
				
			||||||
 | 
					            if '-1' not in apk['icons_src']:
 | 
				
			||||||
 | 
					                match = re.match(APK_ICON_PAT_NODPI, line)
 | 
				
			||||||
 | 
					                if match:
 | 
				
			||||||
 | 
					                    apk['icons_src']['-1'] = match.group(1)
 | 
				
			||||||
 | 
					        elif line.startswith("application-icon-"):
 | 
				
			||||||
 | 
					            match = re.match(APK_ICON_PAT, line)
 | 
				
			||||||
 | 
					            if match:
 | 
				
			||||||
 | 
					                density = match.group(1)
 | 
				
			||||||
 | 
					                path = match.group(2)
 | 
				
			||||||
 | 
					                apk['icons_src'][density] = path
 | 
				
			||||||
 | 
					        elif line.startswith("sdkVersion:"):
 | 
				
			||||||
 | 
					            m = re.match(APK_SDK_VERSION_PAT, line)
 | 
				
			||||||
 | 
					            if m is None:
 | 
				
			||||||
 | 
					                logging.error(line.replace('sdkVersion:', '')
 | 
				
			||||||
 | 
					                              + ' is not a valid minSdkVersion!')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                apk['minSdkVersion'] = m.group(1)
 | 
				
			||||||
 | 
					                # if target not set, default to min
 | 
				
			||||||
 | 
					                if 'targetSdkVersion' not in apk:
 | 
				
			||||||
 | 
					                    apk['targetSdkVersion'] = m.group(1)
 | 
				
			||||||
 | 
					        elif line.startswith("targetSdkVersion:"):
 | 
				
			||||||
 | 
					            m = re.match(APK_SDK_VERSION_PAT, line)
 | 
				
			||||||
 | 
					            if m is None:
 | 
				
			||||||
 | 
					                logging.error(line.replace('targetSdkVersion:', '')
 | 
				
			||||||
 | 
					                              + ' is not a valid targetSdkVersion!')
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                apk['targetSdkVersion'] = m.group(1)
 | 
				
			||||||
 | 
					        elif line.startswith("maxSdkVersion:"):
 | 
				
			||||||
 | 
					            apk['maxSdkVersion'] = re.match(APK_SDK_VERSION_PAT, line).group(1)
 | 
				
			||||||
 | 
					        elif line.startswith("native-code:"):
 | 
				
			||||||
 | 
					            apk['nativecode'] = []
 | 
				
			||||||
 | 
					            for arch in line[13:].split(' '):
 | 
				
			||||||
 | 
					                apk['nativecode'].append(arch[1:-1])
 | 
				
			||||||
 | 
					        elif line.startswith('uses-permission:'):
 | 
				
			||||||
 | 
					            perm_match = re.match(APK_PERMISSION_PAT, line).groupdict()
 | 
				
			||||||
 | 
					            if perm_match['maxSdkVersion']:
 | 
				
			||||||
 | 
					                perm_match['maxSdkVersion'] = int(perm_match['maxSdkVersion'])
 | 
				
			||||||
 | 
					            permission = UsesPermission(
 | 
				
			||||||
 | 
					                perm_match['name'],
 | 
				
			||||||
 | 
					                perm_match['maxSdkVersion']
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            apk['uses-permission'].append(permission)
 | 
				
			||||||
 | 
					        elif line.startswith('uses-permission-sdk-23:'):
 | 
				
			||||||
 | 
					            perm_match = re.match(APK_PERMISSION_PAT, line).groupdict()
 | 
				
			||||||
 | 
					            if perm_match['maxSdkVersion']:
 | 
				
			||||||
 | 
					                perm_match['maxSdkVersion'] = int(perm_match['maxSdkVersion'])
 | 
				
			||||||
 | 
					            permission_sdk_23 = UsesPermissionSdk23(
 | 
				
			||||||
 | 
					                perm_match['name'],
 | 
				
			||||||
 | 
					                perm_match['maxSdkVersion']
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            apk['uses-permission-sdk-23'].append(permission_sdk_23)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        elif line.startswith('uses-feature:'):
 | 
				
			||||||
 | 
					            feature = re.match(APK_FEATURE_PAT, line).group(1)
 | 
				
			||||||
 | 
					            # Filter out this, it's only added with the latest SDK tools and
 | 
				
			||||||
 | 
					            # causes problems for lots of apps.
 | 
				
			||||||
 | 
					            if feature != "android.hardware.screen.portrait" \
 | 
				
			||||||
 | 
					                    and feature != "android.hardware.screen.landscape":
 | 
				
			||||||
 | 
					                if feature.startswith("android.feature."):
 | 
				
			||||||
 | 
					                    feature = feature[16:]
 | 
				
			||||||
 | 
					                apk['features'].add(feature)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def scan_apk_androguard(apk, apkfile):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        from androguard.core.bytecodes.apk import APK
 | 
				
			||||||
 | 
					        apkobject = APK(apkfile)
 | 
				
			||||||
 | 
					        if apkobject.is_valid_APK():
 | 
				
			||||||
 | 
					            arsc = apkobject.get_android_resources()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if options.delete_unknown:
 | 
				
			||||||
 | 
					                if os.path.exists(apkfile):
 | 
				
			||||||
 | 
					                    logging.error("Failed to get apk information, deleting " + apkfile)
 | 
				
			||||||
 | 
					                    os.remove(apkfile)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    logging.error("Could not find {0} to remove it".format(apkfile))
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                logging.error("Failed to get apk information, skipping " + apkfile)
 | 
				
			||||||
 | 
					            raise BuildException("Invaild APK")
 | 
				
			||||||
 | 
					    except ImportError:
 | 
				
			||||||
 | 
					        logging.critical("androguard library is not installed and aapt not present")
 | 
				
			||||||
 | 
					        sys.exit(1)
 | 
				
			||||||
 | 
					    except FileNotFoundError:
 | 
				
			||||||
 | 
					        logging.error("Could not open apk file for analysis")
 | 
				
			||||||
 | 
					        raise BuildException("Invaild APK")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    apk['packageName'] = apkobject.get_package()
 | 
				
			||||||
 | 
					    apk['versionCode'] = int(apkobject.get_androidversion_code())
 | 
				
			||||||
 | 
					    apk['versionName'] = apkobject.get_androidversion_name()
 | 
				
			||||||
 | 
					    if apk['versionName'][0] == "@":
 | 
				
			||||||
 | 
					        version_id = int(apk['versionName'].replace("@", "0x"), 16)
 | 
				
			||||||
 | 
					        version_id = arsc.get_id(apk['packageName'], version_id)[1]
 | 
				
			||||||
 | 
					        apk['versionName'] = arsc.get_string(apk['packageName'], version_id)[1]
 | 
				
			||||||
 | 
					    apk['name'] = apkobject.get_app_name()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if apkobject.get_max_sdk_version() is not None:
 | 
				
			||||||
 | 
					        apk['maxSdkVersion'] = apkobject.get_max_sdk_version()
 | 
				
			||||||
 | 
					    apk['minSdkVersion'] = apkobject.get_min_sdk_version()
 | 
				
			||||||
 | 
					    apk['targetSdkVersion'] = apkobject.get_target_sdk_version()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    icon_id = int(apkobject.get_element("application", "icon").replace("@", "0x"), 16)
 | 
				
			||||||
 | 
					    icon_name = arsc.get_id(apk['packageName'], icon_id)[1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    density_re = re.compile("^res/(.*)/" + icon_name + ".*$")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for file in apkobject.get_files():
 | 
				
			||||||
 | 
					        d_re = density_re.match(file)
 | 
				
			||||||
 | 
					        if d_re:
 | 
				
			||||||
 | 
					            folder = d_re.group(1).split('-')
 | 
				
			||||||
 | 
					            if len(folder) > 1:
 | 
				
			||||||
 | 
					                resolution = folder[1]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                resolution = 'mdpi'
 | 
				
			||||||
 | 
					            density = screen_resolutions[resolution]
 | 
				
			||||||
 | 
					            apk['icons_src'][density] = d_re.group(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if apk['icons_src'].get('-1') is None:
 | 
				
			||||||
 | 
					        apk['icons_src']['-1'] = apk['icons_src']['160']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arch_re = re.compile("^lib/(.*)/.*$")
 | 
				
			||||||
 | 
					    arch = set([arch_re.match(file).group(1) for file in apkobject.get_files() if arch_re.match(file)])
 | 
				
			||||||
 | 
					    if len(arch) >= 1:
 | 
				
			||||||
 | 
					        apk['nativecode'] = []
 | 
				
			||||||
 | 
					        apk['nativecode'].extend(sorted(list(arch)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    xml = apkobject.get_android_manifest_xml()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for item in xml.getElementsByTagName('uses-permission'):
 | 
				
			||||||
 | 
					        name = str(item.getAttribute("android:name"))
 | 
				
			||||||
 | 
					        maxSdkVersion = item.getAttribute("android:maxSdkVersion")
 | 
				
			||||||
 | 
					        maxSdkVersion = None if maxSdkVersion is '' else int(maxSdkVersion)
 | 
				
			||||||
 | 
					        permission = UsesPermission(
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            maxSdkVersion
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        apk['uses-permission'].append(permission)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for item in xml.getElementsByTagName('uses-permission-sdk-23'):
 | 
				
			||||||
 | 
					        name = str(item.getAttribute("android:name"))
 | 
				
			||||||
 | 
					        maxSdkVersion = item.getAttribute("android:maxSdkVersion")
 | 
				
			||||||
 | 
					        maxSdkVersion = None if maxSdkVersion is '' else int(maxSdkVersion)
 | 
				
			||||||
 | 
					        permission_sdk_23 = UsesPermissionSdk23(
 | 
				
			||||||
 | 
					            name,
 | 
				
			||||||
 | 
					            maxSdkVersion
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        apk['uses-permission-sdk-23'].append(permission_sdk_23)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for item in xml.getElementsByTagName('uses-feature'):
 | 
				
			||||||
 | 
					        feature = str(item.getAttribute("android:name"))
 | 
				
			||||||
 | 
					        if feature != "android.hardware.screen.portrait" \
 | 
				
			||||||
 | 
					                and feature != "android.hardware.screen.landscape":
 | 
				
			||||||
 | 
					            if feature.startswith("android.feature."):
 | 
				
			||||||
 | 
					                feature = feature[16:]
 | 
				
			||||||
 | 
					        apk['features'].append(feature)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk):
 | 
					def scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk):
 | 
				
			||||||
    """Scan the apk with the given filename in the given repo directory.
 | 
					    """Scan the apk with the given filename in the given repo directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -888,7 +1089,7 @@ def scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ' ' in apkfilename:
 | 
					    if ' ' in apkfilename:
 | 
				
			||||||
        logging.critical("Spaces in filenames are not allowed.")
 | 
					        logging.critical("Spaces in filenames are not allowed.")
 | 
				
			||||||
        sys.exit(1)
 | 
					        return True, None, False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    apkfile = os.path.join(repodir, apkfilename)
 | 
					    apkfile = os.path.join(repodir, apkfilename)
 | 
				
			||||||
    shasum = sha256sum(apkfile)
 | 
					    shasum = sha256sum(apkfile)
 | 
				
			||||||
| 
						 | 
					@ -921,100 +1122,16 @@ def scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk):
 | 
				
			||||||
        apk['antiFeatures'] = set()
 | 
					        apk['antiFeatures'] = set()
 | 
				
			||||||
        if has_old_openssl(apkfile):
 | 
					        if has_old_openssl(apkfile):
 | 
				
			||||||
            apk['antiFeatures'].add('KnownVuln')
 | 
					            apk['antiFeatures'].add('KnownVuln')
 | 
				
			||||||
        p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
 | 
					
 | 
				
			||||||
        if p.returncode != 0:
 | 
					        try:
 | 
				
			||||||
            if options.delete_unknown:
 | 
					            if common.set_command_in_config('aapt'):
 | 
				
			||||||
                if os.path.exists(apkfile):
 | 
					                logging.warning("Using AAPT for metadata")
 | 
				
			||||||
                    logging.error("Failed to get apk information, deleting " + apkfile)
 | 
					                scan_apk_aapt(apk, apkfile)
 | 
				
			||||||
                    os.remove(apkfile)
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    logging.error("Could not find {0} to remove it".format(apkfile))
 | 
					 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                logging.error("Failed to get apk information, skipping " + apkfile)
 | 
					                logging.warning("Using androguard for metadata")
 | 
				
			||||||
 | 
					                scan_apk_androguard(apk, apkfile)
 | 
				
			||||||
 | 
					        except BuildException:
 | 
				
			||||||
            return True, None, False
 | 
					            return True, None, False
 | 
				
			||||||
        for line in p.output.splitlines():
 | 
					 | 
				
			||||||
            if line.startswith("package:"):
 | 
					 | 
				
			||||||
                try:
 | 
					 | 
				
			||||||
                    apk['packageName'] = re.match(APK_NAME_PAT, line).group(1)
 | 
					 | 
				
			||||||
                    apk['versionCode'] = int(re.match(APK_VERCODE_PAT, line).group(1))
 | 
					 | 
				
			||||||
                    apk['versionName'] = re.match(APK_VERNAME_PAT, line).group(1)
 | 
					 | 
				
			||||||
                except Exception as e:
 | 
					 | 
				
			||||||
                    logging.error("Package matching failed: " + str(e))
 | 
					 | 
				
			||||||
                    logging.info("Line was: " + line)
 | 
					 | 
				
			||||||
                    sys.exit(1)
 | 
					 | 
				
			||||||
            elif line.startswith("application:"):
 | 
					 | 
				
			||||||
                apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
 | 
					 | 
				
			||||||
                # Keep path to non-dpi icon in case we need it
 | 
					 | 
				
			||||||
                match = re.match(APK_ICON_PAT_NODPI, line)
 | 
					 | 
				
			||||||
                if match:
 | 
					 | 
				
			||||||
                    apk['icons_src']['-1'] = match.group(1)
 | 
					 | 
				
			||||||
            elif line.startswith("launchable-activity:"):
 | 
					 | 
				
			||||||
                # Only use launchable-activity as fallback to application
 | 
					 | 
				
			||||||
                if not apk['name']:
 | 
					 | 
				
			||||||
                    apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
 | 
					 | 
				
			||||||
                if '-1' not in apk['icons_src']:
 | 
					 | 
				
			||||||
                    match = re.match(APK_ICON_PAT_NODPI, line)
 | 
					 | 
				
			||||||
                    if match:
 | 
					 | 
				
			||||||
                        apk['icons_src']['-1'] = match.group(1)
 | 
					 | 
				
			||||||
            elif line.startswith("application-icon-"):
 | 
					 | 
				
			||||||
                match = re.match(APK_ICON_PAT, line)
 | 
					 | 
				
			||||||
                if match:
 | 
					 | 
				
			||||||
                    density = match.group(1)
 | 
					 | 
				
			||||||
                    path = match.group(2)
 | 
					 | 
				
			||||||
                    apk['icons_src'][density] = path
 | 
					 | 
				
			||||||
            elif line.startswith("sdkVersion:"):
 | 
					 | 
				
			||||||
                m = re.match(APK_SDK_VERSION_PAT, line)
 | 
					 | 
				
			||||||
                if m is None:
 | 
					 | 
				
			||||||
                    logging.error(line.replace('sdkVersion:', '')
 | 
					 | 
				
			||||||
                                  + ' is not a valid minSdkVersion!')
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    apk['minSdkVersion'] = m.group(1)
 | 
					 | 
				
			||||||
                    # if target not set, default to min
 | 
					 | 
				
			||||||
                    if 'targetSdkVersion' not in apk:
 | 
					 | 
				
			||||||
                        apk['targetSdkVersion'] = m.group(1)
 | 
					 | 
				
			||||||
            elif line.startswith("targetSdkVersion:"):
 | 
					 | 
				
			||||||
                m = re.match(APK_SDK_VERSION_PAT, line)
 | 
					 | 
				
			||||||
                if m is None:
 | 
					 | 
				
			||||||
                    logging.error(line.replace('targetSdkVersion:', '')
 | 
					 | 
				
			||||||
                                  + ' is not a valid targetSdkVersion!')
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    apk['targetSdkVersion'] = m.group(1)
 | 
					 | 
				
			||||||
            elif line.startswith("maxSdkVersion:"):
 | 
					 | 
				
			||||||
                apk['maxSdkVersion'] = re.match(APK_SDK_VERSION_PAT, line).group(1)
 | 
					 | 
				
			||||||
            elif line.startswith("native-code:"):
 | 
					 | 
				
			||||||
                apk['nativecode'] = []
 | 
					 | 
				
			||||||
                for arch in line[13:].split(' '):
 | 
					 | 
				
			||||||
                    apk['nativecode'].append(arch[1:-1])
 | 
					 | 
				
			||||||
            elif line.startswith('uses-permission:'):
 | 
					 | 
				
			||||||
                perm_match = re.match(APK_PERMISSION_PAT, line).groupdict()
 | 
					 | 
				
			||||||
                if perm_match['maxSdkVersion']:
 | 
					 | 
				
			||||||
                    perm_match['maxSdkVersion'] = int(perm_match['maxSdkVersion'])
 | 
					 | 
				
			||||||
                permission = UsesPermission(
 | 
					 | 
				
			||||||
                    perm_match['name'],
 | 
					 | 
				
			||||||
                    perm_match['maxSdkVersion']
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                apk['uses-permission'].append(permission)
 | 
					 | 
				
			||||||
            elif line.startswith('uses-permission-sdk-23:'):
 | 
					 | 
				
			||||||
                perm_match = re.match(APK_PERMISSION_PAT, line).groupdict()
 | 
					 | 
				
			||||||
                if perm_match['maxSdkVersion']:
 | 
					 | 
				
			||||||
                    perm_match['maxSdkVersion'] = int(perm_match['maxSdkVersion'])
 | 
					 | 
				
			||||||
                permission_sdk_23 = UsesPermissionSdk23(
 | 
					 | 
				
			||||||
                    perm_match['name'],
 | 
					 | 
				
			||||||
                    perm_match['maxSdkVersion']
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                apk['uses-permission-sdk-23'].append(permission_sdk_23)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            elif line.startswith('uses-feature:'):
 | 
					 | 
				
			||||||
                feature = re.match(APK_FEATURE_PAT, line).group(1)
 | 
					 | 
				
			||||||
                # Filter out this, it's only added with the latest SDK tools and
 | 
					 | 
				
			||||||
                # causes problems for lots of apps.
 | 
					 | 
				
			||||||
                if feature != "android.hardware.screen.portrait" \
 | 
					 | 
				
			||||||
                        and feature != "android.hardware.screen.landscape":
 | 
					 | 
				
			||||||
                    if feature.startswith("android.feature."):
 | 
					 | 
				
			||||||
                        feature = feature[16:]
 | 
					 | 
				
			||||||
                    apk['features'].add(feature)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if 'minSdkVersion' not in apk:
 | 
					        if 'minSdkVersion' not in apk:
 | 
				
			||||||
            logging.warn("No SDK version information found in {0}".format(apkfile))
 | 
					            logging.warn("No SDK version information found in {0}".format(apkfile))
 | 
				
			||||||
| 
						 | 
					@ -1029,7 +1146,7 @@ def scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk):
 | 
				
			||||||
        apk['sig'] = getsig(os.path.join(os.getcwd(), apkfile))
 | 
					        apk['sig'] = getsig(os.path.join(os.getcwd(), apkfile))
 | 
				
			||||||
        if not apk['sig']:
 | 
					        if not apk['sig']:
 | 
				
			||||||
            logging.critical("Failed to get apk signature")
 | 
					            logging.critical("Failed to get apk signature")
 | 
				
			||||||
            sys.exit(1)
 | 
					            return True, None, False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        apkzip = zipfile.ZipFile(apkfile, 'r')
 | 
					        apkzip = zipfile.ZipFile(apkfile, 'r')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1068,10 +1185,8 @@ def scan_apk(apkcache, apkfilename, repodir, knownapks, use_date_from_apk):
 | 
				
			||||||
                with open(icondest, 'wb') as f:
 | 
					                with open(icondest, 'wb') as f:
 | 
				
			||||||
                    f.write(get_icon_bytes(apkzip, iconsrc))
 | 
					                    f.write(get_icon_bytes(apkzip, iconsrc))
 | 
				
			||||||
                apk['icons'][density] = iconfilename
 | 
					                apk['icons'][density] = iconfilename
 | 
				
			||||||
 | 
					            except (zipfile.BadZipFile, ValueError, KeyError) as e:
 | 
				
			||||||
            except Exception as e:
 | 
					                logging.warning("Error retrieving icon file: %s" % (icondest))
 | 
				
			||||||
                logging.warn("Error retrieving icon file: %s" % (e))
 | 
					 | 
				
			||||||
                del apk['icons'][density]
 | 
					 | 
				
			||||||
                del apk['icons_src'][density]
 | 
					                del apk['icons_src'][density]
 | 
				
			||||||
                empty_densities.append(density)
 | 
					                empty_densities.append(density)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										92
									
								
								tests/androguard_test.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								tests/androguard_test.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import inspect
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import optparse
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import tempfile
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					import yaml
 | 
				
			||||||
 | 
					from binascii import unhexlify
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					localmodule = os.path.realpath(
 | 
				
			||||||
 | 
					    os.path.join(os.path.dirname(inspect.getfile(inspect.currentframe())), '..'))
 | 
				
			||||||
 | 
					print('localmodule: ' + localmodule)
 | 
				
			||||||
 | 
					if localmodule not in sys.path:
 | 
				
			||||||
 | 
					    sys.path.insert(0, localmodule)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import fdroidserver.common
 | 
				
			||||||
 | 
					import fdroidserver.metadata
 | 
				
			||||||
 | 
					import fdroidserver.update
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UpdateTest(unittest.TestCase):
 | 
				
			||||||
 | 
					    '''fdroid androguard manual tests'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def testScanMetadataAndroguardAAPT(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _create_apkmetadata_object(apkName):
 | 
				
			||||||
 | 
					            '''Create an empty apk metadata object'''
 | 
				
			||||||
 | 
					            apk = {}
 | 
				
			||||||
 | 
					            apk['apkName'] = apkName
 | 
				
			||||||
 | 
					            apk['uses-permission'] = []
 | 
				
			||||||
 | 
					            apk['uses-permission-sdk-23'] = []
 | 
				
			||||||
 | 
					            apk['features'] = []
 | 
				
			||||||
 | 
					            apk['icons_src'] = {}
 | 
				
			||||||
 | 
					            return apk
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        config = dict()
 | 
				
			||||||
 | 
					        fdroidserver.common.fill_config_defaults(config)
 | 
				
			||||||
 | 
					        fdroidserver.update.config = config
 | 
				
			||||||
 | 
					        os.chdir(os.path.dirname(__file__))
 | 
				
			||||||
 | 
					        if os.path.basename(os.getcwd()) != 'tests':
 | 
				
			||||||
 | 
					            raise Exception('This test must be run in the "tests/" subdir')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config['ndk_paths'] = dict()
 | 
				
			||||||
 | 
					        config['accepted_formats'] = ['json', 'txt', 'yml']
 | 
				
			||||||
 | 
					        fdroidserver.common.config = config
 | 
				
			||||||
 | 
					        fdroidserver.update.config = config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fdroidserver.update.options = type('', (), {})()
 | 
				
			||||||
 | 
					        fdroidserver.update.options.clean = True
 | 
				
			||||||
 | 
					        fdroidserver.update.options.delete_unknown = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(fdroidserver.common.set_command_in_config('aapt'))
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            from androguard.core.bytecodes.apk import APK
 | 
				
			||||||
 | 
					        except ImportError:
 | 
				
			||||||
 | 
					            raise Exception("androguard not installed!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        apkList = ['../info.guardianproject.urzip.apk', '../org.dyndns.fules.ck_20.apk']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for apkName in apkList:
 | 
				
			||||||
 | 
					            logging.debug("Processing " + apkName)
 | 
				
			||||||
 | 
					            apkfile = os.path.join('repo', apkName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            apkaapt = _create_apkmetadata_object(apkName)
 | 
				
			||||||
 | 
					            logging.debug("Using AAPT for metadata")
 | 
				
			||||||
 | 
					            fdroidserver.update.scan_apk_aapt(apkaapt, apkfile)
 | 
				
			||||||
 | 
					            # avoid AAPT application name bug
 | 
				
			||||||
 | 
					            del apkaapt['name']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            apkandroguard = _create_apkmetadata_object(apkName)
 | 
				
			||||||
 | 
					            logging.debug("Using androguard for metadata")
 | 
				
			||||||
 | 
					            fdroidserver.update.scan_apk_androguard(apkandroguard, apkfile)
 | 
				
			||||||
 | 
					            # avoid AAPT application name bug
 | 
				
			||||||
 | 
					            del apkandroguard['name']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.maxDiff = None
 | 
				
			||||||
 | 
					            self.assertEqual(apkaapt, apkandroguard)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    parser = optparse.OptionParser()
 | 
				
			||||||
 | 
					    parser.add_option("-v", "--verbose", action="store_true", default=False,
 | 
				
			||||||
 | 
					                      help="Spew out even more information than normal")
 | 
				
			||||||
 | 
					    (fdroidserver.common.options, args) = parser.parse_args(['--verbose'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    newSuite = unittest.TestSuite()
 | 
				
			||||||
 | 
					    newSuite.addTest(unittest.makeSuite(UpdateTest))
 | 
				
			||||||
 | 
					    unittest.main()
 | 
				
			||||||
							
								
								
									
										20
									
								
								tests/metadata/apk/info.guardianproject.urzip.yaml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/metadata/apk/info.guardianproject.urzip.yaml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					antiFeatures: !!set {}
 | 
				
			||||||
 | 
					features: []
 | 
				
			||||||
 | 
					hash: abfb3adb7496611749e7abfb014c5c789e3a02489e48a5c3665110d1b1acd931
 | 
				
			||||||
 | 
					hashType: sha256
 | 
				
			||||||
 | 
					icon: info.guardianproject.urzip.100.png
 | 
				
			||||||
 | 
					icons:
 | 
				
			||||||
 | 
					  '0': info.guardianproject.urzip.100.png
 | 
				
			||||||
 | 
					  '160': info.guardianproject.urzip.100.png
 | 
				
			||||||
 | 
					icons_src:
 | 
				
			||||||
 | 
					  '-1': res/drawable/ic_launcher.png
 | 
				
			||||||
 | 
					  '160': res/drawable/ic_launcher.png
 | 
				
			||||||
 | 
					minSdkVersion: '4'
 | 
				
			||||||
 | 
					packageName: info.guardianproject.urzip
 | 
				
			||||||
 | 
					sig: e0ecb5fc2d63088e4a07ae410a127722
 | 
				
			||||||
 | 
					size: 9969
 | 
				
			||||||
 | 
					targetSdkVersion: '18'
 | 
				
			||||||
 | 
					uses-permission: []
 | 
				
			||||||
 | 
					uses-permission-sdk-23: []
 | 
				
			||||||
 | 
					versionCode: 100
 | 
				
			||||||
 | 
					versionName: '0.1'
 | 
				
			||||||
							
								
								
									
										41
									
								
								tests/metadata/apk/org.dyndns.fules.ck.yaml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								tests/metadata/apk/org.dyndns.fules.ck.yaml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					antiFeatures: !!set {}
 | 
				
			||||||
 | 
					features: []
 | 
				
			||||||
 | 
					hash: 897486e1f857c6c0ee32ccbad0e1b8cd82f6d0e65a44a23f13f852d2b63a18c8
 | 
				
			||||||
 | 
					hashType: sha256
 | 
				
			||||||
 | 
					icon: org.dyndns.fules.ck.20.png
 | 
				
			||||||
 | 
					icons:
 | 
				
			||||||
 | 
					  '0': org.dyndns.fules.ck.20.png
 | 
				
			||||||
 | 
					  '120': org.dyndns.fules.ck.20.png
 | 
				
			||||||
 | 
					  '160': org.dyndns.fules.ck.20.png
 | 
				
			||||||
 | 
					  '240': org.dyndns.fules.ck.20.png
 | 
				
			||||||
 | 
					icons_src:
 | 
				
			||||||
 | 
					  '-1': res/drawable-mdpi-v4/icon_launcher.png
 | 
				
			||||||
 | 
					  '120': res/drawable-ldpi-v4/icon_launcher.png
 | 
				
			||||||
 | 
					  '160': res/drawable-mdpi-v4/icon_launcher.png
 | 
				
			||||||
 | 
					  '240': res/drawable-hdpi-v4/icon_launcher.png
 | 
				
			||||||
 | 
					minSdkVersion: '7'
 | 
				
			||||||
 | 
					nativecode:
 | 
				
			||||||
 | 
					- arm64-v8a
 | 
				
			||||||
 | 
					- armeabi
 | 
				
			||||||
 | 
					- armeabi-v7a
 | 
				
			||||||
 | 
					- mips
 | 
				
			||||||
 | 
					- mips64
 | 
				
			||||||
 | 
					- x86
 | 
				
			||||||
 | 
					- x86_64
 | 
				
			||||||
 | 
					packageName: org.dyndns.fules.ck
 | 
				
			||||||
 | 
					sig: 9bf7a6a67f95688daec75eab4b1436ac
 | 
				
			||||||
 | 
					size: 132453
 | 
				
			||||||
 | 
					targetSdkVersion: '8'
 | 
				
			||||||
 | 
					uses-permission:
 | 
				
			||||||
 | 
					- !!python/object/new:fdroidserver.update.UsesPermission
 | 
				
			||||||
 | 
					  - android.permission.BIND_INPUT_METHOD
 | 
				
			||||||
 | 
					  - null
 | 
				
			||||||
 | 
					- !!python/object/new:fdroidserver.update.UsesPermission
 | 
				
			||||||
 | 
					  - android.permission.READ_EXTERNAL_STORAGE
 | 
				
			||||||
 | 
					  - null
 | 
				
			||||||
 | 
					- !!python/object/new:fdroidserver.update.UsesPermission
 | 
				
			||||||
 | 
					  - android.permission.VIBRATE
 | 
				
			||||||
 | 
					  - null
 | 
				
			||||||
 | 
					uses-permission-sdk-23: []
 | 
				
			||||||
 | 
					versionCode: 20
 | 
				
			||||||
 | 
					versionName: v1.6pre2
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								tests/org.dyndns.fules.ck_20.apk
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tests/org.dyndns.fules.ck_20.apk
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -224,6 +224,54 @@ class UpdateTest(unittest.TestCase):
 | 
				
			||||||
                self.assertIsNone(apk.get('obbMainFile'))
 | 
					                self.assertIsNone(apk.get('obbMainFile'))
 | 
				
			||||||
                self.assertIsNone(apk.get('obbPatchFile'))
 | 
					                self.assertIsNone(apk.get('obbPatchFile'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def testScanApkMetadata(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _build_yaml_representer(dumper, data):
 | 
				
			||||||
 | 
					            '''Creates a YAML representation of a Build instance'''
 | 
				
			||||||
 | 
					            return dumper.represent_dict(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config = dict()
 | 
				
			||||||
 | 
					        fdroidserver.common.fill_config_defaults(config)
 | 
				
			||||||
 | 
					        fdroidserver.update.config = config
 | 
				
			||||||
 | 
					        os.chdir(os.path.dirname(__file__))
 | 
				
			||||||
 | 
					        if os.path.basename(os.getcwd()) != 'tests':
 | 
				
			||||||
 | 
					            raise Exception('This test must be run in the "tests/" subdir')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        config['ndk_paths'] = dict()
 | 
				
			||||||
 | 
					        config['accepted_formats'] = ['json', 'txt', 'yml']
 | 
				
			||||||
 | 
					        fdroidserver.common.config = config
 | 
				
			||||||
 | 
					        fdroidserver.update.config = config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fdroidserver.update.options = type('', (), {})()
 | 
				
			||||||
 | 
					        fdroidserver.update.options.clean = True
 | 
				
			||||||
 | 
					        fdroidserver.update.options.delete_unknown = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for icon_dir in fdroidserver.update.get_all_icon_dirs('repo'):
 | 
				
			||||||
 | 
					            if not os.path.exists(icon_dir):
 | 
				
			||||||
 | 
					                os.makedirs(icon_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        knownapks = fdroidserver.common.KnownApks()
 | 
				
			||||||
 | 
					        apkList = ['../urzip.apk', '../org.dyndns.fules.ck_20.apk']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for apkName in apkList:
 | 
				
			||||||
 | 
					            _, apk, cachechanged = fdroidserver.update.scan_apk({}, apkName, 'repo', knownapks, False)
 | 
				
			||||||
 | 
					            # Don't care about the date added to the repo and relative apkName
 | 
				
			||||||
 | 
					            del apk['added']
 | 
				
			||||||
 | 
					            del apk['apkName']
 | 
				
			||||||
 | 
					            # avoid AAPT application name bug
 | 
				
			||||||
 | 
					            del apk['name']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            savepath = os.path.join('metadata', 'apk', apk['packageName'] + '.yaml')
 | 
				
			||||||
 | 
					            # Uncomment to save APK metadata
 | 
				
			||||||
 | 
					            # with open(savepath, 'w') as f:
 | 
				
			||||||
 | 
					            #     yaml.add_representer(fdroidserver.metadata.Build, _build_yaml_representer)
 | 
				
			||||||
 | 
					            #     yaml.dump(apk, f, default_flow_style=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            with open(savepath, 'r') as f:
 | 
				
			||||||
 | 
					                frompickle = yaml.load(f)
 | 
				
			||||||
 | 
					            self.maxDiff = None
 | 
				
			||||||
 | 
					            self.assertEqual(apk, frompickle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_scan_invalid_apk(self):
 | 
					    def test_scan_invalid_apk(self):
 | 
				
			||||||
        os.chdir(os.path.join(localmodule, 'tests'))
 | 
					        os.chdir(os.path.join(localmodule, 'tests'))
 | 
				
			||||||
        if os.path.basename(os.getcwd()) != 'tests':
 | 
					        if os.path.basename(os.getcwd()) != 'tests':
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue