mirror of
https://gitlab.com/fdroid/fdroidserver.git
synced 2024-09-17 18:50:11 +02:00
Merge branch 'master' into 'master'
update: make icon extraction less dependent on aapt Closes fdroid-website#192 See merge request fdroid/fdroidserver!469
This commit is contained in:
commit
4197a4a64a
@ -164,7 +164,7 @@ regex_checks = {
|
|||||||
_("Unnecessary leading space")),
|
_("Unnecessary leading space")),
|
||||||
(re.compile(r'.*\s$'),
|
(re.compile(r'.*\s$'),
|
||||||
_("Unnecessary trailing space")),
|
_("Unnecessary trailing space")),
|
||||||
(re.compile(r'.*<(iframe|link|script).*'),
|
(re.compile(r'.*<(applet|base|body|button|embed|form|head|html|iframe|img|input|link|object|picture|script|source|style|svg|video).*', re.IGNORECASE),
|
||||||
_("Forbidden HTML tags")),
|
_("Forbidden HTML tags")),
|
||||||
(re.compile(r'''.*\s+src=["']javascript:.*'''),
|
(re.compile(r'''.*\s+src=["']javascript:.*'''),
|
||||||
_("Javascript in HTML src attributes")),
|
_("Javascript in HTML src attributes")),
|
||||||
|
@ -53,9 +53,7 @@ UNSET_VERSION_CODE = -0x100000000
|
|||||||
APK_NAME_PAT = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
|
APK_NAME_PAT = re.compile(".*name='([a-zA-Z0-9._]*)'.*")
|
||||||
APK_VERCODE_PAT = re.compile(".*versionCode='([0-9]*)'.*")
|
APK_VERCODE_PAT = re.compile(".*versionCode='([0-9]*)'.*")
|
||||||
APK_VERNAME_PAT = re.compile(".*versionName='([^']*)'.*")
|
APK_VERNAME_PAT = re.compile(".*versionName='([^']*)'.*")
|
||||||
APK_LABEL_PAT = re.compile(".*label='(.*?)'(\n| [a-z]*?=).*")
|
APK_LABEL_ICON_PAT = re.compile(".*\s+label='(.*)'\s+icon='(.*)'")
|
||||||
APK_ICON_PAT = re.compile(".*application-icon-([0-9]+):'([^']+?)'.*")
|
|
||||||
APK_ICON_PAT_NODPI = re.compile(".*icon='([^']+?)'.*")
|
|
||||||
APK_SDK_VERSION_PAT = re.compile(".*'([0-9]*)'.*")
|
APK_SDK_VERSION_PAT = re.compile(".*'([0-9]*)'.*")
|
||||||
APK_PERMISSION_PAT = \
|
APK_PERMISSION_PAT = \
|
||||||
re.compile(".*(name='(?P<name>.*?)')(.*maxSdkVersion='(?P<maxSdkVersion>.*?)')?.*")
|
re.compile(".*(name='(?P<name>.*?)')(.*maxSdkVersion='(?P<maxSdkVersion>.*?)')?.*")
|
||||||
@ -1080,6 +1078,27 @@ def scan_apk(apk_file):
|
|||||||
return apk
|
return apk
|
||||||
|
|
||||||
|
|
||||||
|
def _get_apk_icons_src(apkfile, icon_name):
|
||||||
|
"""Extract the paths to the app icon in all available densities
|
||||||
|
|
||||||
|
"""
|
||||||
|
icons_src = dict()
|
||||||
|
density_re = re.compile('^res/(.*)/' + icon_name + '\.(png|xml)$')
|
||||||
|
with zipfile.ZipFile(apkfile) as zf:
|
||||||
|
for filename in zf.namelist():
|
||||||
|
m = density_re.match(filename)
|
||||||
|
if m:
|
||||||
|
folder = m.group(1).split('-')
|
||||||
|
if len(folder) > 1:
|
||||||
|
density = screen_resolutions[folder[1]]
|
||||||
|
else:
|
||||||
|
density = '160'
|
||||||
|
icons_src[density] = m.group(0)
|
||||||
|
if icons_src.get('-1') is None:
|
||||||
|
icons_src['-1'] = icons_src['160']
|
||||||
|
return icons_src
|
||||||
|
|
||||||
|
|
||||||
def scan_apk_aapt(apk, apkfile):
|
def scan_apk_aapt(apk, apkfile):
|
||||||
p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
|
p = SdkToolsPopen(['aapt', 'dump', 'badging', apkfile], output=False)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
@ -1092,6 +1111,7 @@ def scan_apk_aapt(apk, apkfile):
|
|||||||
else:
|
else:
|
||||||
logging.error(_("Failed to get apk information, skipping {path}").format(path=apkfile))
|
logging.error(_("Failed to get apk information, skipping {path}").format(path=apkfile))
|
||||||
raise BuildException(_("Invalid APK"))
|
raise BuildException(_("Invalid APK"))
|
||||||
|
icon_name = None
|
||||||
for line in p.output.splitlines():
|
for line in p.output.splitlines():
|
||||||
if line.startswith("package:"):
|
if line.startswith("package:"):
|
||||||
try:
|
try:
|
||||||
@ -1101,25 +1121,13 @@ def scan_apk_aapt(apk, apkfile):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise FDroidException("Package matching failed: " + str(e) + "\nLine was: " + line)
|
raise FDroidException("Package matching failed: " + str(e) + "\nLine was: " + line)
|
||||||
elif line.startswith("application:"):
|
elif line.startswith("application:"):
|
||||||
apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
|
m = re.match(APK_LABEL_ICON_PAT, line)
|
||||||
# Keep path to non-dpi icon in case we need it
|
if m:
|
||||||
match = re.match(APK_ICON_PAT_NODPI, line)
|
apk['name'] = m.group(1)
|
||||||
if match:
|
icon_name = os.path.splitext(os.path.basename(m.group(2)))[0]
|
||||||
apk['icons_src']['-1'] = match.group(1)
|
elif not apk.get('name') and line.startswith("launchable-activity:"):
|
||||||
elif line.startswith("launchable-activity:"):
|
|
||||||
# Only use launchable-activity as fallback to application
|
# Only use launchable-activity as fallback to application
|
||||||
if not apk['name']:
|
apk['name'] = re.match(APK_LABEL_ICON_PAT, line).group(1)
|
||||||
apk['name'] = re.match(APK_LABEL_PAT, line).group(1)
|
|
||||||
if '-1' not in apk['icons_src']:
|
|
||||||
match = re.match(APK_ICON_PAT_NODPI, line)
|
|
||||||
if match:
|
|
||||||
apk['icons_src']['-1'] = match.group(1)
|
|
||||||
elif line.startswith("application-icon-"):
|
|
||||||
match = re.match(APK_ICON_PAT, line)
|
|
||||||
if match:
|
|
||||||
density = match.group(1)
|
|
||||||
path = match.group(2)
|
|
||||||
apk['icons_src'][density] = path
|
|
||||||
elif line.startswith("sdkVersion:"):
|
elif line.startswith("sdkVersion:"):
|
||||||
m = re.match(APK_SDK_VERSION_PAT, line)
|
m = re.match(APK_SDK_VERSION_PAT, line)
|
||||||
if m is None:
|
if m is None:
|
||||||
@ -1170,6 +1178,7 @@ def scan_apk_aapt(apk, apkfile):
|
|||||||
if feature.startswith("android.feature."):
|
if feature.startswith("android.feature."):
|
||||||
feature = feature[16:]
|
feature = feature[16:]
|
||||||
apk['features'].add(feature)
|
apk['features'].add(feature)
|
||||||
|
apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name)
|
||||||
|
|
||||||
|
|
||||||
def scan_apk_androguard(apk, apkfile):
|
def scan_apk_androguard(apk, apkfile):
|
||||||
@ -1215,22 +1224,7 @@ def scan_apk_androguard(apk, apkfile):
|
|||||||
|
|
||||||
icon_id = int(apkobject.get_element("application", "icon").replace("@", "0x"), 16)
|
icon_id = int(apkobject.get_element("application", "icon").replace("@", "0x"), 16)
|
||||||
icon_name = arsc.get_id(apk['packageName'], icon_id)[1]
|
icon_name = arsc.get_id(apk['packageName'], icon_id)[1]
|
||||||
|
apk['icons_src'] = _get_apk_icons_src(apkfile, icon_name)
|
||||||
density_re = re.compile("^res/(.*)/" + icon_name + ".*$")
|
|
||||||
|
|
||||||
for file in apkobject.get_files():
|
|
||||||
d_re = density_re.match(file)
|
|
||||||
if d_re:
|
|
||||||
folder = d_re.group(1).split('-')
|
|
||||||
if len(folder) > 1:
|
|
||||||
resolution = folder[1]
|
|
||||||
else:
|
|
||||||
resolution = 'mdpi'
|
|
||||||
density = screen_resolutions[resolution]
|
|
||||||
apk['icons_src'][density] = d_re.group(0)
|
|
||||||
|
|
||||||
if apk['icons_src'].get('-1') is None:
|
|
||||||
apk['icons_src']['-1'] = apk['icons_src']['160']
|
|
||||||
|
|
||||||
arch_re = re.compile("^lib/(.*)/.*$")
|
arch_re = re.compile("^lib/(.*)/.*$")
|
||||||
arch = set([arch_re.match(file).group(1) for file in apkobject.get_files() if arch_re.match(file)])
|
arch = set([arch_re.match(file).group(1) for file in apkobject.get_files() if arch_re.match(file)])
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
|
# http://www.drdobbs.com/testing/unit-testing-with-python/240165163
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
import logging
|
||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@ -23,6 +24,14 @@ import fdroidserver.lint
|
|||||||
class LintTest(unittest.TestCase):
|
class LintTest(unittest.TestCase):
|
||||||
'''fdroidserver/lint.py'''
|
'''fdroidserver/lint.py'''
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
self.basedir = os.path.join(localmodule, 'tests')
|
||||||
|
self.tmpdir = os.path.abspath(os.path.join(self.basedir, '..', '.testfiles'))
|
||||||
|
if not os.path.exists(self.tmpdir):
|
||||||
|
os.makedirs(self.tmpdir)
|
||||||
|
os.chdir(self.basedir)
|
||||||
|
|
||||||
def test_check_for_unsupported_metadata_files(self):
|
def test_check_for_unsupported_metadata_files(self):
|
||||||
config = dict()
|
config = dict()
|
||||||
fdroidserver.common.fill_config_defaults(config)
|
fdroidserver.common.fill_config_defaults(config)
|
||||||
@ -31,8 +40,8 @@ class LintTest(unittest.TestCase):
|
|||||||
fdroidserver.lint.config = config
|
fdroidserver.lint.config = config
|
||||||
self.assertTrue(fdroidserver.lint.check_for_unsupported_metadata_files())
|
self.assertTrue(fdroidserver.lint.check_for_unsupported_metadata_files())
|
||||||
|
|
||||||
tmpdir = os.path.join(localmodule, '.testfiles')
|
tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name,
|
||||||
tmptestsdir = tempfile.mkdtemp(prefix=inspect.currentframe().f_code.co_name, dir=tmpdir)
|
dir=self.tmpdir)
|
||||||
self.assertFalse(fdroidserver.lint.check_for_unsupported_metadata_files(tmptestsdir + '/'))
|
self.assertFalse(fdroidserver.lint.check_for_unsupported_metadata_files(tmptestsdir + '/'))
|
||||||
shutil.copytree(os.path.join(localmodule, 'tests', 'metadata'),
|
shutil.copytree(os.path.join(localmodule, 'tests', 'metadata'),
|
||||||
os.path.join(tmptestsdir, 'metadata'),
|
os.path.join(tmptestsdir, 'metadata'),
|
||||||
@ -42,6 +51,24 @@ class LintTest(unittest.TestCase):
|
|||||||
os.path.join(tmptestsdir, 'metadata'))
|
os.path.join(tmptestsdir, 'metadata'))
|
||||||
self.assertTrue(fdroidserver.lint.check_for_unsupported_metadata_files(tmptestsdir + '/'))
|
self.assertTrue(fdroidserver.lint.check_for_unsupported_metadata_files(tmptestsdir + '/'))
|
||||||
|
|
||||||
|
def test_forbidden_html_tags(self):
|
||||||
|
config = dict()
|
||||||
|
fdroidserver.common.fill_config_defaults(config)
|
||||||
|
fdroidserver.common.config = config
|
||||||
|
fdroidserver.lint.config = config
|
||||||
|
|
||||||
|
app = {
|
||||||
|
'Name': 'Bad App',
|
||||||
|
'Summary': 'We pwn you',
|
||||||
|
'Description': 'This way: <style><img src="</style><img src=x onerror=alert(1)//">',
|
||||||
|
}
|
||||||
|
|
||||||
|
anywarns = False
|
||||||
|
for warn in fdroidserver.lint.check_regexes(app):
|
||||||
|
anywarns = True
|
||||||
|
logging.debug(warn)
|
||||||
|
self.assertTrue(anywarns)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = optparse.OptionParser()
|
parser = optparse.OptionParser()
|
||||||
|
Loading…
Reference in New Issue
Block a user