add strict, tested validation of Android/F-Droid package names

Android has stricter rules than Java for Package Names, but anything the
Python regex thinks is valid must be valid according to Java's rules too.

https://developer.android.com/studio/build/application-id
This commit is contained in:
Hans-Christoph Steiner 2018-09-07 14:17:39 +02:00
parent 3ab66efcfe
commit 9d12b1dc61
7 changed files with 329 additions and 14 deletions

View file

@ -75,6 +75,10 @@ VERCODE_OPERATION_RE = re.compile(r'^([ 0-9/*+-]|%c)+$')
CERT_PATH_REGEX = re.compile(r'^META-INF/.*\.(DSA|EC|RSA)$')
APK_NAME_REGEX = re.compile(r'^([a-zA-Z][\w.]*)_(-?[0-9]+)_?([0-9a-f]{7})?\.apk')
STANDARD_FILE_NAME_REGEX = re.compile(r'^(\w[\w.]*)_(-?[0-9]+)\.\w+')
FDROID_PACKAGE_NAME_REGEX = re.compile(r'''^[a-f0-9]+$''', re.IGNORECASE)
STRICT_APPLICATION_ID_REGEX = re.compile(r'''(?:^[a-z_]+(?:\d*[a-zA-Z_]*)*)(?:\.[a-z_]+(?:\d*[a-zA-Z_]*)*)*$''')
VALID_APPLICATION_ID_REGEX = re.compile(r'''(?:^[a-z_]+(?:\d*[a-zA-Z_]*)*)(?:\.[a-z_]+(?:\d*[a-zA-Z_]*)*)*$''',
re.IGNORECASE)
MAX_VERSION_CODE = 0x7fffffff # Java's Integer.MAX_VALUE (2147483647)
@ -1516,8 +1520,12 @@ def parse_androidmanifests(paths, app):
if max_version is None:
max_version = "Unknown"
if max_package and not is_valid_java_package_name(max_package):
raise FDroidException(_("Invalid package name {0}").format(max_package))
if max_package:
msg = _("Invalid package name {0}").format(max_package)
if not is_valid_package_name(max_package):
raise FDroidException(msg)
elif not is_strict_application_id(max_package):
logging.warning(msg)
return (max_version, max_vercode, max_package)
@ -1530,12 +1538,25 @@ def is_valid_package_name(name):
files use the SHA-256 sum.
"""
return re.match("^([a-f0-9]+|[A-Za-z_][A-Za-z_0-9.]+)$", name)
return VALID_APPLICATION_ID_REGEX.match(name) is not None \
or FDROID_PACKAGE_NAME_REGEX.match(name) is not None
def is_valid_java_package_name(name):
"""Check whether name is a valid Java package name aka Application ID"""
return re.match("^[A-Za-z_][A-Za-z_0-9.]+$", name)
def is_strict_application_id(name):
"""Check whether name is a valid Android Application ID
The Android ApplicationID is basically a Java Package Name, but
with more restrictive naming rules:
* It must have at least two segments (one or more dots).
* Each segment must start with a letter.
* All characters must be alphanumeric or an underscore [a-zA-Z0-9_].
https://developer.android.com/studio/build/application-id
"""
return STRICT_APPLICATION_ID_REGEX.match(name) is not None \
and '.' in name
def getsrclib(spec, srclib_dir, subdir=None, basepath=False,

View file

@ -488,7 +488,13 @@ def check_for_unsupported_metadata_files(basedir=""):
if not exists:
print(_('"%s/" has no matching metadata file!') % f)
return_value = True
elif not os.path.splitext(f)[1][1:] in formats:
elif os.path.splitext(f)[1][1:] in formats:
packageName = os.path.splitext(os.path.basename(f))[0]
if not common.is_valid_package_name(packageName):
print('"' + packageName + '" is an invalid package name!\n'
+ 'https://developer.android.com/studio/build/application-id')
return_value = True
else:
print('"' + f.replace(basedir, '')
+ '" is not a supported file format: (' + ','.join(formats) + ')')
return_value = True

View file

@ -1067,9 +1067,12 @@ def scan_apk(apk_file):
else:
scan_apk_aapt(apk, apk_file)
if not common.is_valid_java_package_name(apk['packageName']):
if not common.is_valid_package_name(apk['packageName']):
raise BuildException(_("{appid} from {path} is not a valid Java Package Name!")
.format(appid=apk['packageName'], path=apk_file))
elif not common.is_strict_application_id(apk['packageName']):
logging.warning(_("{appid} from {path} is not a valid Java Package Name!")
.format(appid=apk['packageName'], path=apk_file))
# Get the signature, or rather the signing key fingerprints
logging.debug('Getting signature of {0}'.format(os.path.basename(apk_file)))