diff --git a/fdroidserver/checkupdates.py b/fdroidserver/checkupdates.py index 876dd2ae..d919c72b 100644 --- a/fdroidserver/checkupdates.py +++ b/fdroidserver/checkupdates.py @@ -30,6 +30,7 @@ import html from distutils.version import LooseVersion import logging import copy +import urllib.parse from . import _ from . import common @@ -48,6 +49,13 @@ def check_http(app): raise FDroidException('Missing Update Check Data') urlcode, codeex, urlver, verex = app.UpdateCheckData.split('|') + parsed = urllib.parse.urlparse(urlcode) + if not parsed.netloc or not parsed.scheme or parsed.scheme != 'https': + raise FDroidException(_('UpdateCheckData has invalid URL: {url}').format(url=urlcode)) + if urlver != '.': + parsed = urllib.parse.urlparse(urlver) + if not parsed.netloc or not parsed.scheme or parsed.scheme != 'https': + raise FDroidException(_('UpdateCheckData has invalid URL: {url}').format(url=urlcode)) vercode = "99999999" if len(urlcode) > 0: diff --git a/fdroidserver/lint.py b/fdroidserver/lint.py index b0a5cad7..13779747 100644 --- a/fdroidserver/lint.py +++ b/fdroidserver/lint.py @@ -21,6 +21,7 @@ import glob import os import re import sys +import urllib.parse from . import _ from . import common @@ -32,7 +33,7 @@ options = None def enforce_https(domain): - return (re.compile(r'.*[^sS]://[^/]*' + re.escape(domain) + r'(/.*)?'), + return (re.compile(r'^[^h][^t][^t][^p][^s]://[^/]*' + re.escape(domain) + r'(/.*)?', re.IGNORECASE), domain + " URLs should always use https://") @@ -51,6 +52,9 @@ https_enforcings = [ enforce_https('savannah.gnu.org'), enforce_https('git.savannah.gnu.org'), enforce_https('download.savannah.gnu.org'), + enforce_https('github.io'), + enforce_https('gitlab.io'), + enforce_https('githubusercontent.com'), ] @@ -126,6 +130,7 @@ regex_checks = { 'WebSite': http_checks, 'SourceCode': http_checks, 'Repo': https_enforcings, + 'UpdateCheckMode': https_enforcings, 'IssueTracker': http_checks + [ (re.compile(r'.*github\.com/[^/]+/[^/]+/*$'), _("/issues is missing")), @@ -203,6 +208,19 @@ def get_lastbuild(builds): return lastbuild +def check_update_check_data_url(app): + """UpdateCheckData must have a valid HTTPS URL to protect checkupdates runs + """ + if app.UpdateCheckData: + urlcode, codeex, urlver, verex = app.UpdateCheckData.split('|') + for url in (urlcode, urlver): + parsed = urllib.parse.urlparse(url) + if not parsed.scheme or not parsed.netloc: + yield _('UpdateCheckData not a valid URL: {url}').format(url=url) + if parsed.scheme != 'https': + yield _('UpdateCheckData must use HTTPS URL: {url}').format(url=url) + + def check_ucm_tags(app): lastbuild = get_lastbuild(app.builds) if (lastbuild is not None @@ -509,6 +527,7 @@ def main(): app_check_funcs = [ check_regexes, + check_update_check_data_url, check_ucm_tags, check_char_limits, check_old_links,