1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-08-18 12:20:10 +02:00

Merge branch 'master' into 'master'

Three random fixes

See merge request fdroid/fdroidserver!496
This commit is contained in:
Hans-Christoph Steiner 2018-05-03 12:11:48 +00:00
commit 62a187607d
4 changed files with 81 additions and 43 deletions

View File

@ -1955,6 +1955,36 @@ def use_androguard():
use_androguard.show_path = True
def _get_androguard_APK(apkfile):
try:
from androguard.core.bytecodes.apk import APK
except ImportError:
raise FDroidException("androguard library is not installed and aapt not present")
return APK(apkfile)
def ensure_final_value(packageName, arsc, value):
"""Ensure incoming value is always the value, not the resid
androguard will sometimes return the Android "resId" aka
Resource ID instead of the actual value. This checks whether
the value is actually a resId, then performs the Android
Resource lookup as needed.
"""
if value:
returnValue = value
if value[0] == '@':
try: # can be a literal value or a resId
res_id = int('0x' + value[1:], 16)
res_id = arsc.get_id(packageName, res_id)[1]
returnValue = arsc.get_string(packageName, res_id)[1]
except ValueError:
pass
return returnValue
def is_apk_and_debuggable_aapt(apkfile):
p = SdkToolsPopen(['aapt', 'dump', 'xmltree', apkfile, 'AndroidManifest.xml'],
output=False)
@ -1967,12 +1997,7 @@ def is_apk_and_debuggable_aapt(apkfile):
def is_apk_and_debuggable_androguard(apkfile):
try:
from androguard.core.bytecodes.apk import APK
except ImportError:
raise FDroidException("androguard library is not installed and aapt not present")
apkobject = APK(apkfile)
apkobject = _get_androguard_APK(apkfile)
if apkobject.is_valid_APK():
debuggable = apkobject.get_element("application", "debuggable")
if debuggable is not None:
@ -1994,13 +2019,31 @@ def is_apk_and_debuggable(apkfile):
return is_apk_and_debuggable_aapt(apkfile)
def get_apk_id_aapt(apkfile):
"""Extrat identification information from APK using aapt.
def get_apk_id(apkfile):
"""Extract identification information from APK using aapt.
:param apkfile: path to an APK file.
:returns: triplet (appid, version code, version name)
"""
r = re.compile("^package: name='(?P<appid>.*)' versionCode='(?P<vercode>.*)' versionName='(?P<vername>.*)'.*")
if use_androguard():
return get_apk_id_androguard(apkfile)
else:
return get_apk_id_aapt(apkfile)
def get_apk_id_androguard(apkfile):
if not os.path.exists(apkfile):
raise FDroidException(_("Reading packageName/versionCode/versionName failed, APK invalid: '{apkfilename}'")
.format(apkfilename=apkfile))
a = _get_androguard_APK(apkfile)
versionName = ensure_final_value(a.package, a.get_android_resources(), a.get_androidversion_name())
if not versionName:
versionName = '' # versionName is expected to always be a str
return a.package, a.get_androidversion_code(), versionName
def get_apk_id_aapt(apkfile):
r = re.compile("^package: name='(?P<appid>.*)' versionCode='(?P<vercode>.*)' versionName='(?P<vername>.*?)'(?: platformBuildVersionName='.*')?")
p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
for line in p.output.splitlines():
m = r.match(line)
@ -2665,12 +2708,20 @@ def verify_old_apk_signature(apk):
jarsigner passes unsigned APKs as "verified"! So this has to turn
on -strict then check for result 4.
Just to be safe, this never reuses the file, and locks down the
file permissions while in use. That should prevent a bad actor
from changing the settings during operation.
:returns: boolean whether the APK was verified
"""
_java_security = os.path.join(os.getcwd(), '.java.security')
if os.path.exists(_java_security):
os.remove(_java_security)
with open(_java_security, 'w') as fp:
fp.write('jdk.jar.disabledAlgorithms=MD2, RSA keySize < 1024')
os.chmod(_java_security, 0o400)
try:
cmd = [
@ -2685,6 +2736,10 @@ def verify_old_apk_signature(apk):
else:
logging.debug(_('JAR signature verified: {path}').format(path=apk))
return True
finally:
if os.path.exists(_java_security):
os.chmod(_java_security, 0o600)
os.remove(_java_security)
logging.error(_('Old APK signature failed to verify: {path}').format(path=apk)
+ '\n' + output.decode('utf-8'))

View File

@ -36,7 +36,7 @@ def extract_signature(apkpath):
raise FDroidException("no valid signature in '{}'".format(apkpath))
logging.debug('signature okay: %s', apkpath)
appid, vercode, _ignored = common.get_apk_id_aapt(apkpath)
appid, vercode, _ignored = common.get_apk_id(apkpath)
sigdir = common.metadata_get_sigdir(appid, vercode)
if not os.path.exists(sigdir):
os.makedirs(sigdir)

View File

@ -1181,27 +1181,6 @@ def scan_apk_aapt(apk, apkfile):
apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name)
def _ensure_final_value(packageName, arsc, value):
"""Ensure incoming value is always the value, not the resid
androguard will sometimes return the Android "resId" aka
Resource ID instead of the actual value. This checks whether
the value is actually a resId, then performs the Android
Resource lookup as needed.
"""
if value:
returnValue = value
if value[0] == '@':
try: # can be a literal value or a resId
res_id = int(value.replace("@", "0x"), 16)
res_id = arsc.get_id(packageName, res_id)[1]
returnValue = arsc.get_string(packageName, res_id)[1]
except ValueError:
pass
return returnValue
def _sanitize_sdk_version(value):
"""Sanitize the raw values from androguard to handle bad values
@ -1250,8 +1229,8 @@ def scan_apk_androguard(apk, apkfile):
apk['versionCode'] = int(apkobject.get_androidversion_code())
apk['name'] = apkobject.get_app_name()
apk['versionName'] = _ensure_final_value(apk['packageName'], arsc,
apkobject.get_androidversion_name())
apk['versionName'] = common.ensure_final_value(apk['packageName'], arsc,
apkobject.get_androidversion_name())
minSdkVersion = _sanitize_sdk_version(apkobject.get_min_sdk_version())
if minSdkVersion is not None:

View File

@ -533,7 +533,7 @@ class CommonTest(unittest.TestCase):
self.assertTrue(fdroidserver.common.verify_apk_signature(signed))
self.assertEqual(18, fdroidserver.common.get_minSdkVersion_aapt(signed))
def test_get_api_id_aapt(self):
def test_get_api_id(self):
config = dict()
fdroidserver.common.fill_config_defaults(config)
@ -543,8 +543,6 @@ class CommonTest(unittest.TestCase):
testcases = [
('repo/obb.main.twoversions_1101613.apk', 'obb.main.twoversions', '1101613', '0.1'),
('OBBMainPatchCurrent.apk', 'obb.mainpatch.current', '1619', '0.1'),
('OBBMainTwoVersions.apk', 'obb.main.twoversions', '1101613', '0.1'),
('org.bitbucket.tickytacky.mirrormirror_1.apk', 'org.bitbucket.tickytacky.mirrormirror', '1', '1.0'),
('org.bitbucket.tickytacky.mirrormirror_2.apk', 'org.bitbucket.tickytacky.mirrormirror', '2', '1.0.1'),
('org.bitbucket.tickytacky.mirrormirror_3.apk', 'org.bitbucket.tickytacky.mirrormirror', '3', '1.0.2'),
@ -555,12 +553,11 @@ class CommonTest(unittest.TestCase):
('urzip-badsig.apk', 'info.guardianproject.urzip', '100', '0.1'),
('urzip-release.apk', 'info.guardianproject.urzip', '100', '0.1'),
('urzip-release-unsigned.apk', 'info.guardianproject.urzip', '100', '0.1'),
('urzip-πÇÇπÇÇ现代汉语通用字-български-عربي1234.apk', 'info.guardianproject.urzip', '100', '0.1'),
('repo/com.politedroid_3.apk', 'com.politedroid', '3', '1.2'),
('repo/com.politedroid_4.apk', 'com.politedroid', '4', '1.3'),
('repo/com.politedroid_5.apk', 'com.politedroid', '5', '1.4'),
('repo/com.politedroid_6.apk', 'com.politedroid', '6', '1.5'),
('repo/duplicate.permisssions_9999999.apk', 'duplicate.permisssions', '9999999', '0.3-7-gb817ac8'),
('repo/duplicate.permisssions_9999999.apk', 'duplicate.permisssions', '9999999', ''),
('repo/info.zwanenburg.caffeinetile_4.apk', 'info.zwanenburg.caffeinetile', '4', '1.3'),
('repo/obb.main.oldversion_1444412523.apk', 'obb.main.oldversion', '1444412523', '0.1'),
('repo/obb.mainpatch.current_1619_another-release-key.apk', 'obb.mainpatch.current', '1619', '0.1'),
@ -571,13 +568,20 @@ class CommonTest(unittest.TestCase):
('repo/urzip-; Рахма́нинов, [rɐxˈmanʲɪnəf] سيرجي_رخمانينوف 谢尔盖·.apk', 'info.guardianproject.urzip', '100', '0.1'),
]
for apkfilename, appid, versionCode, versionName in testcases:
a, vc, vn = fdroidserver.common.get_apk_id_aapt(apkfilename)
self.assertEqual(appid, a)
self.assertEqual(versionCode, vc)
self.assertEqual(versionName, vn)
print('\n\nAPKFILENAME\n', apkfilename)
if 'aapt' in config:
a, vc, vn = fdroidserver.common.get_apk_id_aapt(apkfilename)
self.assertEqual(appid, a)
self.assertEqual(versionCode, vc)
self.assertEqual(versionName, vn)
if fdroidserver.common.use_androguard():
a, vc, vn = fdroidserver.common.get_apk_id_androguard(apkfilename)
self.assertEqual(appid, a)
self.assertEqual(versionCode, vc)
self.assertEqual(versionName, vn)
with self.assertRaises(FDroidException):
fdroidserver.common.get_apk_id_aapt('nope')
fdroidserver.common.get_apk_id('nope')
def test_get_minSdkVersion_aapt(self):