From: Hans-Christoph Steiner Date: Thu, 26 Apr 2018 11:17:25 +0000 (+0200) Subject: handle bad SDK Version values in APKs X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=fdroidserver.git;a=commitdiff_plain;h=e17815e9f066ba40fedb6db2786f861b696b7585 handle bad SDK Version values in APKs Even though it is invalid to have *SdkVersion in AndroidManifest.xml set as anything but an integer, sometimes people manage to get something in there. `fdroid update` needs to be able to handle all that. * https://developer.android.com/guide/topics/manifest/uses-sdk-element#min * https://gitlab.com/souch/SMSbypass/blob/v0.9/app/src/main/AndroidManifest.xml#L29 * https://gitlab.com/souch/SMSbypass/blob/v0.9/app/src/main/res/values/strings.xml#L27 admin#65 --- diff --git a/fdroidserver/update.py b/fdroidserver/update.py index 830a2252..b108f38a 100644 --- a/fdroidserver/update.py +++ b/fdroidserver/update.py @@ -1181,6 +1181,25 @@ def scan_apk_aapt(apk, apkfile): apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name) +def _sanitize_sdk_version(value): + """Sanitize the raw values from androguard to handle bad values + + minSdkVersion/targetSdkVersion/maxSdkVersion must be integers, + but that doesn't stop devs from doing strange things like + setting them using Android XML strings. + + https://gitlab.com/souch/SMSbypass/blob/v0.9/app/src/main/AndroidManifest.xml#L29 + https://gitlab.com/souch/SMSbypass/blob/v0.9/app/src/main/res/values/strings.xml#L27 + """ + try: + sdk_version = int(value) + if sdk_version > 0: + return str(sdk_version) # heinous, but this is still str in the codebase + except (TypeError, ValueError): + pass + return None + + def scan_apk_androguard(apk, apkfile): try: from androguard.core.bytecodes.apk import APK @@ -1221,12 +1240,17 @@ def scan_apk_androguard(apk, apkfile): except ValueError: pass - if apkobject.get_max_sdk_version() is not None: - apk['maxSdkVersion'] = apkobject.get_max_sdk_version() - if apkobject.get_min_sdk_version() is not None: - apk['minSdkVersion'] = apkobject.get_min_sdk_version() - if apkobject.get_target_sdk_version() is not None: - apk['targetSdkVersion'] = apkobject.get_target_sdk_version() + minSdkVersion = _sanitize_sdk_version(apkobject.get_min_sdk_version()) + if minSdkVersion is not None: + apk['minSdkVersion'] = minSdkVersion + + targetSdkVersion = _sanitize_sdk_version(apkobject.get_target_sdk_version()) + if targetSdkVersion is not None: + apk['targetSdkVersion'] = targetSdkVersion + + maxSdkVersion = _sanitize_sdk_version(apkobject.get_max_sdk_version()) + if maxSdkVersion is not None: + apk['maxSdkVersion'] = maxSdkVersion icon_id_str = apkobject.get_element("application", "icon") if icon_id_str: diff --git a/tests/metadata/souch.smsbypass.txt b/tests/metadata/souch.smsbypass.txt new file mode 100644 index 00000000..6b16e050 --- /dev/null +++ b/tests/metadata/souch.smsbypass.txt @@ -0,0 +1,52 @@ +Categories:Phone & SMS +License:GPL-3.0 +Web Site:https://gitlab.com/souch/SMSbypass +Source Code:https://gitlab.com/souch/SMSbypass/tree/HEAD +Issue Tracker:https://gitlab.com/souch/SMSbypass/issues +Donate:http://rodolphe.souchaud.free.fr/donate +FlattrID:cad90e036b975ed129a3ce80a0750466 + +Auto Name:Battery level +Summary:Filter SMS and show them in a fake app +Description: +In order to keep away curious eyes, SMS-bypass filters incoming SMS messages +before they reach your inbox. Based on bughunter2.smsfilter. + +Features: + +* Discrete fake app "Battery level": Long tap on Battery percentage will show SMS. +* Filter incoming SMS specified address: redirect the SMS to SMS-bypass messages list; remove SMS arrival sound or vibration; show a discreet notification icon (battery level); vibrate if checked in settings +* Add contact from contact list +* Export messages to a text file +. + +Repo Type:git +Repo:https://gitlab.com/souch/SMSbypass.git + +Build:0.8,5 + commit=v0.8 + subdir=app + gradle=yes + prebuild=sed -i -e '/minSdkVersion/amaxSdkVersion 19\n' build.gradle + +Build:0.8b,6 + disable=don't build, just use as template for AUM, correct VC is 8 + commit=2bd6164ff6391906af2af2b484de69a4ff926a01 + subdir=app + gradle=yes + +Build:0.8.1,8 + disable=mistagged + commit=v0.8.1 + subdir=app + gradle=yes + +Build:0.9,9 + commit=v0.9 + subdir=app + gradle=yes + +Auto Update Mode:Version v%v +Update Check Mode:Tags +Current Version:0.9 +Current Version Code:9 diff --git a/tests/repo/index-v1.json b/tests/repo/index-v1.json index cda10cf2..912f610c 100644 --- a/tests/repo/index-v1.json +++ b/tests/repo/index-v1.json @@ -21,6 +21,26 @@ ] }, "apps": [ + { + "categories": [ + "Phone & SMS" + ], + "suggestedVersionName": "0.9", + "suggestedVersionCode": "9", + "description": "

In order to keep away curious eyes, SMS-bypass filters incoming SMS messages before they reach your inbox. Based on bughunter2.smsfilter.

Features:

", + "donate": "http://rodolphe.souchaud.free.fr/donate", + "flattrID": "cad90e036b975ed129a3ce80a0750466", + "issueTracker": "https://gitlab.com/souch/SMSbypass/issues", + "license": "GPL-3.0", + "name": "Battery level", + "sourceCode": "https://gitlab.com/souch/SMSbypass/tree/HEAD", + "summary": "Filter SMS and show them in a fake app", + "webSite": "https://gitlab.com/souch/SMSbypass", + "added": 1524700800000, + "icon": "souch.smsbypass.9.png", + "packageName": "souch.smsbypass", + "lastUpdated": 1524700800000 + }, { "categories": [ "tests" @@ -525,6 +545,48 @@ "versionCode": 1619, "versionName": "0.1" } + ], + "souch.smsbypass": [ + { + "added": 1524700800000, + "apkName": "souch.smsbypass_9.apk", + "hash": "80b0ae68a1189baa3ee6717092e3dbf1a4210165f7f7e5f2f9616bd63a2ec01d", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "souch.smsbypass", + "sig": "e50c99753cd45e2736d52cb49be07581", + "signer": "d3aec784b1fd71549fc22c999789122e3639895db6bd585da5835fbe3db6985c", + "size": 81295, + "targetSdkVersion": "18", + "uses-permission": [ + [ + "android.permission.RECEIVE_SMS", + null + ], + [ + "android.permission.SEND_SMS", + null + ], + [ + "android.permission.READ_CONTACTS", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ] + ], + "versionCode": 9, + "versionName": "0.9" + } ] } -} +} \ No newline at end of file diff --git a/tests/repo/index.xml b/tests/repo/index.xml index ef6988de..9b6ef50a 100644 --- a/tests/repo/index.xml +++ b/tests/repo/index.xml @@ -8,6 +8,37 @@ + + souch.smsbypass + 2018-04-26 + 2018-04-26 + Battery level + Filter SMS and show them in a fake app + souch.smsbypass.9.png + <p>In order to keep away curious eyes, SMS-bypass filters incoming SMS messages before they reach your inbox. Based on bughunter2.smsfilter.</p><p>Features:</p><ul><li> Discrete fake app "Battery level": Long tap on Battery percentage will show SMS.</li><li> Filter incoming SMS specified address: redirect the SMS to SMS-bypass messages list; remove SMS arrival sound or vibration; show a discreet notification icon (battery level); vibrate if checked in settings</li><li> Add contact from contact list</li><li> Export messages to a text file</li></ul> + GPL-3.0 + Phone & SMS + Phone & SMS + https://gitlab.com/souch/SMSbypass + https://gitlab.com/souch/SMSbypass/tree/HEAD + https://gitlab.com/souch/SMSbypass/issues + http://rodolphe.souchaud.free.fr/donate + cad90e036b975ed129a3ce80a0750466 + 0.9 + 9 + + 0.9 + 9 + souch.smsbypass_9.apk + 80b0ae68a1189baa3ee6717092e3dbf1a4210165f7f7e5f2f9616bd63a2ec01d + 81295 + 8 + 18 + 2018-04-26 + e50c99753cd45e2736d52cb49be07581 + READ_CONTACTS,READ_EXTERNAL_STORAGE,RECEIVE_SMS,SEND_SMS,VIBRATE,WRITE_EXTERNAL_STORAGE + + duplicate.permisssions 2017-12-22 diff --git a/tests/repo/souch.smsbypass_9.apk b/tests/repo/souch.smsbypass_9.apk new file mode 100644 index 00000000..ce96f299 Binary files /dev/null and b/tests/repo/souch.smsbypass_9.apk differ diff --git a/tests/stats/known_apks.txt b/tests/stats/known_apks.txt index ef90c797..392c68ff 100644 --- a/tests/stats/known_apks.txt +++ b/tests/stats/known_apks.txt @@ -10,4 +10,5 @@ obb.main.twoversions_1101615.apk obb.main.twoversions 2016-01-01 obb.main.twoversions_1101617.apk obb.main.twoversions 2016-06-20 obb.mainpatch.current_1619.apk obb.mainpatch.current 2016-04-23 obb.mainpatch.current_1619_another-release-key.apk obb.mainpatch.current 2017-06-01 +souch.smsbypass_9.apk souch.smsbypass 2018-04-26 urzip-; Рахма́нинов, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢尔盖·.apk info.guardianproject.urzip 2016-06-23 diff --git a/tests/update.TestCase b/tests/update.TestCase index eb59c3d0..6616669f 100755 --- a/tests/update.TestCase +++ b/tests/update.TestCase @@ -253,7 +253,7 @@ 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), 13) + self.assertEqual(len(apks), 14) apk = apks[0] self.assertEqual(apk['packageName'], 'com.politedroid') self.assertEqual(apk['versionCode'], 3) @@ -298,6 +298,10 @@ class UpdateTest(unittest.TestCase): if os.path.basename(os.getcwd()) != 'tests': raise Exception('This test must be run in the "tests/" subdir') + apk_info = fdroidserver.update.scan_apk('repo/souch.smsbypass_9.apk') + self.assertIsNone(apk_info.get('maxSdkVersion')) + self.assertEqual(apk_info.get('versionName'), '0.9') + apk_info = fdroidserver.update.scan_apk('repo/duplicate.permisssions_9999999.apk') self.assertEqual(apk_info['icons_src'], {'160': 'res/drawable/ic_launcher.png', '-1': 'res/drawable/ic_launcher.png'}) @@ -549,7 +553,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), 13) + self.assertEqual(len(apks), 14) foundtest = False for apk in apks: if apk['packageName'] == 'com.politedroid' and apk['versionCode'] == 3: