diff --git a/fdroidserver/common.py b/fdroidserver/common.py index 586867a6..2a59152a 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -3047,6 +3047,19 @@ def apk_extract_signatures(apkpath, outdir, manifest=True): out_file.write(in_apk.read(f.filename)) +def get_min_sdk_version(apk): + """ + This wraps the androguard function to always return and int and fall back to 1 + if we can't get a valid minsdk version + :param apk: androguard apk object + :return: minsdk as int + """ + try: + return int(apk.get_min_sdk_version()) + except TypeError: + return 1 + + def sign_apk(unsigned_path, signed_path, keyalias): """Sign and zipalign an unsigned APK, then save to a new file, deleting the unsigned @@ -3068,7 +3081,7 @@ def sign_apk(unsigned_path, signed_path, keyalias): """ apk = _get_androguard_APK(unsigned_path) - if int(apk.get_target_sdk_version()) >= 30: + if apk.get_effective_target_sdk_version() >= 30: if config['keystore'] == 'NONE': # NOTE: apksigner doesn't like -providerName/--provider-name at all, don't use # apksigner documents the options as --ks-provider-class and --ks-provider-arg @@ -3098,7 +3111,7 @@ def sign_apk(unsigned_path, signed_path, keyalias): os.remove(unsigned_path) else: - if int(apk.get_min_sdk_version()) < 18: + if get_min_sdk_version(apk) < 18: signature_algorithm = ['-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1'] else: signature_algorithm = ['-sigalg', 'SHA256withRSA', '-digestalg', 'SHA-256'] diff --git a/tests/common.TestCase b/tests/common.TestCase index 98815d5b..ca06de8b 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -697,6 +697,37 @@ class CommonTest(unittest.TestCase): # verify it has a v2 signature self.assertTrue(fdroidserver.common._get_androguard_APK(signed).is_signed_v2()) + def test_sign_no_targetsdk(self): + fdroidserver.common.config = None + config = fdroidserver.common.read_config(fdroidserver.common.options) + if not fdroidserver.common.find_apksigner(): + self.skipTest('SKIPPING as apksigner is not installed!') + config['jarsigner'] = fdroidserver.common.find_sdk_tools_cmd('jarsigner') + config['keyalias'] = 'sova' + config['keystorepass'] = 'r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=' + config['keypass'] = 'r9aquRHYoI8+dYz6jKrLntQ5/NJNASFBacJh7Jv2BlI=' + config['keystore'] = os.path.join(self.basedir, 'keystore.jks') + testdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=self.tmpdir) + + shutil.copy(os.path.join(self.basedir, 'no_targetsdk_minsdk30_unsigned.apk'), testdir) + unsigned = os.path.join(testdir, 'no_targetsdk_minsdk30_unsigned.apk') + signed = os.path.join(testdir, 'no_targetsdk_minsdk30_signed.apk') + + fdroidserver.common.sign_apk(unsigned, signed, config['keyalias']) + self.assertTrue(fdroidserver.common.verify_apk_signature(signed)) + self.assertTrue(fdroidserver.common._get_androguard_APK(signed).is_signed_v2()) + + shutil.copy(os.path.join(self.basedir, 'no_targetsdk_minsdk1_unsigned.apk'), testdir) + unsigned = os.path.join(testdir, 'no_targetsdk_minsdk1_unsigned.apk') + signed = os.path.join(testdir, 'no_targetsdk_minsdk1_signed.apk') + + self.assertFalse(fdroidserver.common.verify_apk_signature(unsigned)) + fdroidserver.common.sign_apk(unsigned, signed, config['keyalias']) + + self.assertTrue(os.path.isfile(signed)) + self.assertFalse(os.path.isfile(unsigned)) + self.assertTrue(fdroidserver.common.verify_apk_signature(signed)) + def test_get_apk_id(self): config = dict() fdroidserver.common.fill_config_defaults(config) @@ -796,11 +827,11 @@ class CommonTest(unittest.TestCase): """This is a sanity test that androguard isn't broken""" def get_minSdkVersion(apkfile): apk = fdroidserver.common._get_androguard_APK(apkfile) - return int(apk.get_min_sdk_version()) + return fdroidserver.common.get_min_sdk_version(apk) def get_targetSdkVersion(apkfile): apk = fdroidserver.common._get_androguard_APK(apkfile) - return int(apk.get_target_sdk_version()) + return apk.get_effective_target_sdk_version() self.assertEqual(4, get_minSdkVersion('bad-unicode-πÇÇ现代通用字-български-عربي1.apk')) self.assertEqual(14, get_minSdkVersion('org.bitbucket.tickytacky.mirrormirror_1.apk')) @@ -826,6 +857,8 @@ class CommonTest(unittest.TestCase): self.assertEqual(4, get_minSdkVersion('repo/urzip-; Рахма́, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢·.apk')) self.assertEqual(30, get_targetSdkVersion('minimal_targetsdk_30_unsigned.apk')) + self.assertEqual(1, get_targetSdkVersion('no_targetsdk_minsdk1_unsigned.apk')) + self.assertEqual(30, get_targetSdkVersion('no_targetsdk_minsdk30_unsigned.apk')) def test_apk_release_name(self): appid, vercode, sigfp = fdroidserver.common.apk_parse_release_filename('com.serwylo.lexica_905.apk') diff --git a/tests/no_targetsdk_minsdk1_unsigned.apk b/tests/no_targetsdk_minsdk1_unsigned.apk new file mode 100644 index 00000000..225e52bc Binary files /dev/null and b/tests/no_targetsdk_minsdk1_unsigned.apk differ diff --git a/tests/no_targetsdk_minsdk30_unsigned.apk b/tests/no_targetsdk_minsdk30_unsigned.apk new file mode 100644 index 00000000..ae8e86b5 Binary files /dev/null and b/tests/no_targetsdk_minsdk30_unsigned.apk differ