diff --git a/fdroidserver/common.py b/fdroidserver/common.py index bd831f1e..06d40faa 100644 --- a/fdroidserver/common.py +++ b/fdroidserver/common.py @@ -57,6 +57,9 @@ from fdroidserver.exception import FDroidException, VCSException, NoSubmodulesEx BuildException, VerificationException from .asynchronousfilereader import AsynchronousFileReader +# this is the build-tools version, aapt has a separate version that +# has to be manually set in test_aapt_version() +MINIMUM_AAPT_VERSION = '26.0.0' # A signature block file with a .DSA, .RSA, or .EC extension CERT_PATH_REGEX = re.compile(r'^META-INF/.*\.(DSA|EC|RSA)$') @@ -84,7 +87,7 @@ default_config = { 'r16': None, }, 'qt_sdk_path': None, - 'build_tools': "25.0.2", + 'build_tools': MINIMUM_AAPT_VERSION, 'force_build_tools': False, 'java_paths': None, 'ant': "ant", @@ -397,13 +400,13 @@ def test_aapt_version(aapt): # the Debian package has the version string like "v0.2-23.0.2" too_old = False if '.' in bugfix: - if LooseVersion(bugfix) < LooseVersion('24.0.0'): + if LooseVersion(bugfix) < LooseVersion(MINIMUM_AAPT_VERSION): too_old = True - elif LooseVersion('.'.join((major, minor, bugfix))) < LooseVersion('0.2.2964546'): + elif LooseVersion('.'.join((major, minor, bugfix))) < LooseVersion('0.2.4062713'): too_old = True if too_old: - logging.warning(_("'{aapt}' is too old, fdroid requires build-tools-24.0.0 or newer!") - .format(aapt=aapt)) + logging.warning(_("'{aapt}' is too old, fdroid requires build-tools-{version} or newer!") + .format(aapt=aapt, version=MINIMUM_AAPT_VERSION)) else: logging.warning(_('Unknown version of aapt, might cause problems: ') + output) @@ -2463,7 +2466,7 @@ def sign_apk(unsigned_path, signed_path, keyalias): if get_minSdkVersion_aapt(unsigned_path) < 18: signature_algorithm = ['-sigalg', 'SHA1withRSA', '-digestalg', 'SHA1'] else: - signature_algorithm = ['-sigalg', 'SHA256withRSA', '-digestalg', 'SHA256'] + signature_algorithm = ['-sigalg', 'SHA256withRSA', '-digestalg', 'SHA-256'] p = FDroidPopen([config['jarsigner'], '-keystore', config['keystore'], '-storepass:env', 'FDROID_KEY_STORE_PASS', diff --git a/fdroidserver/nightly.py b/fdroidserver/nightly.py index 249cd2e4..1e150c80 100644 --- a/fdroidserver/nightly.py +++ b/fdroidserver/nightly.py @@ -47,7 +47,7 @@ DISTINGUISHED_NAME = 'CN=Android Debug,O=Android,C=US' NIGHTLY = '-nightly' -def _ssh_key_from_debug_keystore(): +def _ssh_key_from_debug_keystore(keystore=KEYSTORE_FILE): tmp_dir = tempfile.mkdtemp(prefix='.') privkey = os.path.join(tmp_dir, '.privkey') key_pem = os.path.join(tmp_dir, '.key.pem') @@ -55,7 +55,7 @@ def _ssh_key_from_debug_keystore(): _config = dict() common.fill_config_defaults(_config) subprocess.check_call([_config['keytool'], '-importkeystore', - '-srckeystore', KEYSTORE_FILE, '-srcalias', KEY_ALIAS, + '-srckeystore', keystore, '-srcalias', KEY_ALIAS, '-srcstorepass', PASSWORD, '-srckeypass', PASSWORD, '-destkeystore', p12, '-destalias', KEY_ALIAS, '-deststorepass', PASSWORD, '-destkeypass', PASSWORD, @@ -87,6 +87,8 @@ def main(): parser = ArgumentParser(usage="%(prog)s") common.setup_global_opts(parser) + parser.add_argument("--keystore", default=KEYSTORE_FILE, + help=_("Specify which debug keystore file to use.")) parser.add_argument("--show-secret-var", action="store_true", default=False, help=_("Print the secret variable to the terminal for easy copy/paste")) parser.add_argument("--file", default='app/build/outputs/apk/*.apk', @@ -291,19 +293,19 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base, shutil.rmtree(os.path.dirname(ssh_private_key_file)) else: - if not os.path.isfile(KEYSTORE_FILE): - androiddir = os.path.dirname(KEYSTORE_FILE) + if not os.path.isfile(options.keystore): + androiddir = os.path.dirname(options.keystore) if not os.path.exists(androiddir): os.mkdir(androiddir) logging.info(_('created {path}').format(path=androiddir)) - logging.error(_('{path} does not exist! Create it by running:').format(path=KEYSTORE_FILE) - + '\n keytool -genkey -v -keystore ' + KEYSTORE_FILE + ' -storepass android \\' + logging.error(_('{path} does not exist! Create it by running:').format(path=options.keystore) + + '\n keytool -genkey -v -keystore ' + options.keystore + ' -storepass android \\' + '\n -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 \\' + '\n -dname "CN=Android Debug,O=Android,C=US"') sys.exit(1) ssh_dir = os.path.join(os.getenv('HOME'), '.ssh') os.makedirs(os.path.dirname(ssh_dir), exist_ok=True) - privkey = _ssh_key_from_debug_keystore() + privkey = _ssh_key_from_debug_keystore(options.keystore) ssh_private_key_file = os.path.join(ssh_dir, os.path.basename(privkey)) shutil.move(privkey, ssh_private_key_file) shutil.move(privkey + '.pub', ssh_private_key_file + '.pub') @@ -311,10 +313,10 @@ Last updated: {date}'''.format(repo_git_base=repo_git_base, shutil.rmtree(os.path.dirname(privkey)) if options.show_secret_var: - with open(KEYSTORE_FILE, 'rb') as fp: + with open(options.keystore, 'rb') as fp: debug_keystore = base64.standard_b64encode(fp.read()).decode('ascii') print(_('\n{path} encoded for the DEBUG_KEYSTORE secret variable:') - .format(path=KEYSTORE_FILE)) + .format(path=options.keystore)) print(debug_keystore) os.umask(umask) diff --git a/tests/common.TestCase b/tests/common.TestCase index 3b4cc5e9..330d37a7 100755 --- a/tests/common.TestCase +++ b/tests/common.TestCase @@ -521,6 +521,18 @@ class CommonTest(unittest.TestCase): self.assertFalse(os.path.isfile(unsigned)) self.assertTrue(fdroidserver.common.verify_apk_signature(signed)) + # now sign an APK with minSdkVersion >= 18 + unsigned = os.path.join(testdir, 'duplicate.permisssions_9999999-unsigned.apk') + signed = os.path.join(testdir, 'duplicate.permisssions_9999999.apk') + shutil.copy(os.path.join(self.basedir, 'repo', 'duplicate.permisssions_9999999.apk'), + os.path.join(unsigned)) + fdroidserver.common.apk_strip_signatures(unsigned, strip_manifest=True) + 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)) + self.assertEqual(18, fdroidserver.common.get_minSdkVersion_aapt(signed)) + def test_get_api_id_aapt(self): config = dict() diff --git a/tests/metadata/duplicate.permisssions.yml b/tests/metadata/duplicate.permisssions.yml new file mode 100644 index 00000000..3401c235 --- /dev/null +++ b/tests/metadata/duplicate.permisssions.yml @@ -0,0 +1,4 @@ +Categories: +- tests +Name: Duplicate Permisssions +Summary: 'Test app for all possible ' diff --git a/tests/repo/duplicate.permisssions_9999999.apk b/tests/repo/duplicate.permisssions_9999999.apk new file mode 100644 index 00000000..a7510f3a Binary files /dev/null and b/tests/repo/duplicate.permisssions_9999999.apk differ diff --git a/tests/repo/index-v1.json b/tests/repo/index-v1.json index 17cfff83..b5a4c6ca 100644 --- a/tests/repo/index-v1.json +++ b/tests/repo/index-v1.json @@ -21,6 +21,19 @@ ] }, "apps": [ + { + "categories": [ + "tests" + ], + "suggestedVersionCode": "9999999", + "license": "Unknown", + "name": "Duplicate Permisssions", + "summary": "Test app for all possible ", + "added": 1513900800000, + "icon": "duplicate.permisssions.9999999.png", + "packageName": "duplicate.permisssions", + "lastUpdated": 1513900800000 + }, { "categories": [ "System" @@ -271,6 +284,62 @@ "versionName": "1.2" } ], + "duplicate.permisssions": [ + { + "added": 1513900800000, + "apkName": "duplicate.permisssions_9999999.apk", + "hash": "9ffc7e9b2740ce664059194805b2fbfc08b7970c8448a22b8bd828dfd6ad161c", + "hashType": "sha256", + "minSdkVersion": "18", + "packageName": "duplicate.permisssions", + "sig": "2d337e40aef77564bf62781ac424595c", + "signer": "f49af3f11efddf20dffd70f5e3117b9976674167adca280e6b1932a0601b26f6", + "size": 11988, + "targetSdkVersion": "27", + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ], + [ + "android.permission.CHANGE_WIFI_MULTICAST_STATE", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + 18 + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + 18 + ] + ], + "uses-permission-sdk-23": [ + [ + "android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", + 27 + ], + [ + "android.permission.REQUEST_INSTALL_PACKAGES", + null + ] + ], + "versionCode": 9999999, + "versionName": "0.3-7-gb817ac8" + } + ], "fake.ota.update": [ { "added": 1457568000000, diff --git a/tests/repo/index.xml b/tests/repo/index.xml index 1c696042..3209f8bf 100644 --- a/tests/repo/index.xml +++ b/tests/repo/index.xml @@ -8,6 +8,38 @@ + + duplicate.permisssions + 2017-12-22 + 2017-12-22 + Duplicate Permisssions + Test app for all possible <uses-permissions> + duplicate.permisssions.9999999.png + <p>No description available</p> + Unknown + tests + tests + + + + + 9999999 + + 0.3-7-gb817ac8 + 9999999 + duplicate.permisssions_9999999.apk + 9ffc7e9b2740ce664059194805b2fbfc08b7970c8448a22b8bd828dfd6ad161c + 11988 + 18 + 27 + 2017-12-22 + 2d337e40aef77564bf62781ac424595c + ACCESS_NETWORK_STATE,ACCESS_WIFI_STATE,CHANGE_WIFI_MULTICAST_STATE,INTERNET,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + + + + + fake.ota.update 2016-03-10 diff --git a/tests/stats/known_apks.txt b/tests/stats/known_apks.txt index fbab3620..ef90c797 100644 --- a/tests/stats/known_apks.txt +++ b/tests/stats/known_apks.txt @@ -1,7 +1,8 @@ -com.politedroid_3.apk repo/com.politedroid 2017-06-23 -com.politedroid_4.apk repo/com.politedroid 2017-06-23 -com.politedroid_5.apk repo/com.politedroid 2017-06-23 -com.politedroid_6.apk repo/com.politedroid 2017-06-23 +com.politedroid_3.apk com.politedroid 2017-06-23 +com.politedroid_4.apk com.politedroid 2017-06-23 +com.politedroid_5.apk com.politedroid 2017-06-23 +com.politedroid_6.apk com.politedroid 2017-06-23 +duplicate.permisssions_9999999.apk duplicate.permisssions 2017-12-22 fake.ota.update_1234.zip fake.ota.update 2016-03-10 obb.main.oldversion_1444412523.apk obb.main.oldversion 2013-12-31 obb.main.twoversions_1101613.apk obb.main.twoversions 2015-10-12 diff --git a/tests/update.TestCase b/tests/update.TestCase index db463a89..94bf507d 100755 --- a/tests/update.TestCase +++ b/tests/update.TestCase @@ -253,14 +253,14 @@ class UpdateTest(unittest.TestCase): apps = fdroidserver.metadata.read_metadata(xref=True) knownapks = fdroidserver.common.KnownApks() apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False) - self.assertEqual(len(apks), 11) + self.assertEqual(len(apks), 12) apk = apks[0] self.assertEqual(apk['packageName'], 'com.politedroid') self.assertEqual(apk['versionCode'], 3) self.assertEqual(apk['minSdkVersion'], '3') self.assertEqual(apk['targetSdkVersion'], '3') self.assertFalse('maxSdkVersion' in apk) - apk = apks[4] + apk = apks[5] self.assertEqual(apk['packageName'], 'obb.main.oldversion') self.assertEqual(apk['versionCode'], 1444412523) self.assertEqual(apk['minSdkVersion'], '4') @@ -527,7 +527,7 @@ class UpdateTest(unittest.TestCase): knownapks = fdroidserver.common.KnownApks() apks, cachechanged = fdroidserver.update.process_apks({}, 'repo', knownapks, False) fdroidserver.update.translate_per_build_anti_features(apps, apks) - self.assertEqual(len(apks), 11) + self.assertEqual(len(apks), 12) foundtest = False for apk in apks: if apk['packageName'] == 'com.politedroid' and apk['versionCode'] == 3: