diff --git a/fdroidserver/verify.py b/fdroidserver/verify.py index 63540147..46963bb4 100644 --- a/fdroidserver/verify.py +++ b/fdroidserver/verify.py @@ -144,23 +144,44 @@ def write_json_report(url, remote_apk, unsigned_apk, compare_result): with open(jsonfile, 'w') as fp: json.dump(data, fp, sort_keys=True) - if output['verified']: - jsonfile = 'unsigned/verified.json' - data = get_verified_json(jsonfile) - packageName = output['local']['packageName'] + appid, version_code = os.path.basename(unsigned_apk[:-4]).rsplit('_', 1) + appid_base = unsigned_apk.rsplit('_', 1)[0] + apkReports = sorted( + glob.glob(f'{appid_base}_[0-9]*.json'), # don't include .json + key=lambda s: int(s[:-9].rsplit('_', 1)[1]), # numeric sort by versionCode + ) + with open(apkReports[-1]) as fp: + reports = json.load(fp) + appid_output = {'apkReports': apkReports} + most_recent = 0 + for report_time, run in reports.items(): + if float(report_time) > most_recent: + most_recent = float(report_time) + appid_output['lastRunVerified'] = run['verified'] + with open(f'{appid_base}.json', 'w') as fp: + json.dump(appid_output, fp, cls=common.Encoder, sort_keys=True) - if packageName not in data['packages']: - data['packages'][packageName] = [] - found = False - output_dump = json.dumps(output, sort_keys=True) - for p in data['packages'][packageName]: - if output_dump == json.dumps(p, sort_keys=True): - found = True - break - if not found: - data['packages'][packageName].insert(0, json.loads(output_dump)) - with open(jsonfile, 'w') as fp: - json.dump(data, fp, cls=common.Encoder, sort_keys=True) + if output['verified']: + write_verified_json(output) + + +def write_verified_json(output): + jsonfile = 'unsigned/verified.json' + data = get_verified_json(jsonfile) + packageName = output['local']['packageName'] + + if packageName not in data['packages']: + data['packages'][packageName] = [] + found = False + output_dump = json.dumps(output, sort_keys=True) + for p in data['packages'][packageName]: + if output_dump == json.dumps(p, sort_keys=True): + found = True + break + if not found: + data['packages'][packageName].insert(0, json.loads(output_dump)) + with open(jsonfile, 'w') as fp: + json.dump(data, fp, cls=common.Encoder, sort_keys=True) def main(): diff --git a/tests/test_verify.py b/tests/test_verify.py index adb24b29..f9da9092 100755 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -122,3 +122,50 @@ class VerifyTest(unittest.TestCase): secondpass = json.load(fp) self.assertEqual(firstpass, secondpass) + + @patch('fdroidserver.common.sha256sum') + @patch('fdroidserver.verify.write_verified_json', lambda s: s) + def test_write_json_report_appid_json(self, sha256sum): + sha256sum.return_value = ( + '70c2f776a2bac38a58a7d521f96ee0414c6f0fb1de973c3ca8b10862a009247d' + ) + os.mkdir('tmp') + os.mkdir('unsigned') + appid = 'com.politedroid' + apk_name = f'{appid}_6.apk' + remote_apk = 'tmp/' + apk_name + unsigned_apk = 'unsigned/' + apk_name + shutil.copy(basedir / 'repo' / apk_name, remote_apk) + shutil.copy(basedir / 'repo' / apk_name, unsigned_apk) + url = TEST_APP_ENTRY['1539780240.3885746']['url'] + with open(f'unsigned/{apk_name}.json', 'w') as fp: + json.dump(TEST_APP_ENTRY, fp) + + # make a fake existing report where the newer one broke verifiability + with open(f'unsigned/{appid}_16.apk.json', 'w') as fp: + json.dump( + { + "1444444444.4444444": { + 'local': {'versionCode': 16}, + 'verified': False, + }, + "1333333333.3333333": { + 'local': {'versionCode': 16}, + 'verified': True, + }, + }, + fp, + ) + + verify.write_json_report(url, remote_apk, unsigned_apk, {'fake': 'fail'}) + with open(f'unsigned/{appid}.json') as fp: + self.assertEqual( + { + 'apkReports': [ + 'unsigned/com.politedroid_6.apk.json', + 'unsigned/com.politedroid_16.apk.json', + ], + 'lastRunVerified': False, + }, + json.load(fp), + )