mirror of
https://github.com/f-droid/fdroidserver.git
synced 2025-11-05 15:00:30 +03:00
Merge branch 'lint-AntiFeatures-from-config' into 'master'
lint: Anti-Features validator uses names from config / plus tests, cleanups, and minor bugfixes See merge request fdroid/fdroidserver!1352
This commit is contained in:
commit
1b765d11e7
35 changed files with 1336 additions and 161 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -7,11 +7,11 @@ TAGS
|
|||
.ropeproject/
|
||||
|
||||
# files generated by build
|
||||
build/
|
||||
dist/
|
||||
/build/
|
||||
/dist/
|
||||
env/
|
||||
ENV/
|
||||
fdroidserver.egg-info/
|
||||
/fdroidserver.egg-info/
|
||||
pylint.parseable
|
||||
/.testfiles/
|
||||
README.rst
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ metadata_v0:
|
|||
image: registry.gitlab.com/fdroid/fdroidserver:buildserver
|
||||
variables:
|
||||
GIT_DEPTH: 1000
|
||||
RELEASE_COMMIT_ID: 58cfce106b6d68dc8ebde7842cf01225f5adfd1b # 2.2b
|
||||
RELEASE_COMMIT_ID: 0124b9dde99f9cab19c034cbc7d8cc6005a99b48 # 2.3a0
|
||||
script:
|
||||
- git fetch https://gitlab.com/fdroid/fdroidserver.git $RELEASE_COMMIT_ID
|
||||
- cd tests
|
||||
|
|
@ -125,6 +125,10 @@ ubuntu_lts_ppa:
|
|||
- apt-get update
|
||||
- apt-get dist-upgrade
|
||||
- apt-get install --install-recommends dexdump fdroidserver git jq python3-setuptools sdkmanager
|
||||
|
||||
# Test things work with a default branch other than 'master'
|
||||
- git config --global init.defaultBranch thisisnotmasterormain
|
||||
|
||||
- cd tests
|
||||
- ./run-tests
|
||||
|
||||
|
|
@ -584,12 +588,12 @@ docker:
|
|||
RELEASE_IMAGE: $CI_REGISTRY_IMAGE:buildserver
|
||||
script:
|
||||
# git ref names can contain many chars that are not allowed in docker tags
|
||||
- export TEST_IMAGE=$CI_REGISTRY_IMAGE:$(printf $CI_BUILD_REF_NAME | sed 's,[^a-zA-Z0-9_.-],_,g')
|
||||
- export TEST_IMAGE=$CI_REGISTRY_IMAGE:$(printf $CI_COMMIT_REF_NAME | sed 's,[^a-zA-Z0-9_.-],_,g')
|
||||
- cd buildserver
|
||||
- docker build -t $TEST_IMAGE --build-arg GIT_REV_PARSE_HEAD=$(git rev-parse HEAD) .
|
||||
- docker tag $TEST_IMAGE $RELEASE_IMAGE
|
||||
- docker tag $TEST_IMAGE ${RELEASE_IMAGE}-bullseye
|
||||
- echo $CI_BUILD_TOKEN | docker login -u gitlab-ci-token --password-stdin registry.gitlab.com
|
||||
- echo $CI_JOB_TOKEN | docker login -u gitlab-ci-token --password-stdin registry.gitlab.com
|
||||
# This avoids filling up gitlab.com free tier accounts with unused docker images.
|
||||
- if test -z "$FDROID_PUSH_DOCKER_IMAGE"; then
|
||||
echo "Skipping docker push to save quota on your gitlab namespace.";
|
||||
|
|
|
|||
16
MANIFEST.in
16
MANIFEST.in
|
|
@ -545,6 +545,22 @@ include tests/check-fdroid-apk
|
|||
include tests/checkupdates.TestCase
|
||||
include tests/common.TestCase
|
||||
include tests/config.py
|
||||
include tests/config/antiFeatures.yml
|
||||
include tests/config/de/antiFeatures.yml
|
||||
include tests/config/fa/antiFeatures.yml
|
||||
include tests/config/ic_antifeature_ads.xml
|
||||
include tests/config/ic_antifeature_disabledalgorithm.xml
|
||||
include tests/config/ic_antifeature_knownvuln.xml
|
||||
include tests/config/ic_antifeature_nonfreeadd.xml
|
||||
include tests/config/ic_antifeature_nonfreeassets.xml
|
||||
include tests/config/ic_antifeature_nonfreedep.xml
|
||||
include tests/config/ic_antifeature_nonfreenet.xml
|
||||
include tests/config/ic_antifeature_nosourcesince.xml
|
||||
include tests/config/ic_antifeature_nsfw.xml
|
||||
include tests/config/ic_antifeature_tracking.xml
|
||||
include tests/config/ic_antifeature_upstreamnonfree.xml
|
||||
include tests/config/ro/antiFeatures.yml
|
||||
include tests/config/zh-rCN/antiFeatures.yml
|
||||
include tests/corrupt-featureGraphic.png
|
||||
include tests/deploy.TestCase
|
||||
include tests/dummy-keystore.jks
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ def make_binary_transparency_log(
|
|||
else:
|
||||
if not os.path.exists(btrepo):
|
||||
os.mkdir(btrepo)
|
||||
gitrepo = git.Repo.init(btrepo)
|
||||
gitrepo = git.Repo.init(btrepo, initial_branch=deploy.GIT_BRANCH)
|
||||
|
||||
if not url:
|
||||
url = common.config['repo_url'].rstrip('/')
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ from . import apksigcopier, common
|
|||
# The path to this fdroidserver distribution
|
||||
FDROID_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
|
||||
# There needs to be a default, and this is the most common for software.
|
||||
DEFAULT_LOCALE = 'en-US'
|
||||
|
||||
# this is the build-tools version, aapt has a separate version that
|
||||
# has to be manually set in test_aapt_version()
|
||||
MINIMUM_AAPT_BUILD_TOOLS_VERSION = '26.0.0'
|
||||
|
|
@ -487,6 +490,52 @@ def read_config(opts=None):
|
|||
return config
|
||||
|
||||
|
||||
def file_entry(filename, hash_value=None):
|
||||
meta = {}
|
||||
meta["name"] = "/" + filename.split("/", 1)[1]
|
||||
meta["sha256"] = hash_value or common.sha256sum(filename)
|
||||
meta["size"] = os.stat(filename).st_size
|
||||
return meta
|
||||
|
||||
|
||||
def load_localized_config(name, repodir):
|
||||
"""Load localized config files and put them into internal dict format.
|
||||
|
||||
This will maintain the order as came from the data files, e.g
|
||||
YAML. The locale comes from unsorted paths on the filesystem, so
|
||||
that is separately sorted.
|
||||
|
||||
"""
|
||||
ret = dict()
|
||||
for f in Path().glob("config/**/{name}.yml".format(name=name)):
|
||||
locale = f.parts[1]
|
||||
if len(f.parts) == 2:
|
||||
locale = DEFAULT_LOCALE
|
||||
with open(f, encoding="utf-8") as fp:
|
||||
elem = yaml.safe_load(fp)
|
||||
for afname, field_dict in elem.items():
|
||||
if afname not in ret:
|
||||
ret[afname] = dict()
|
||||
for key, value in field_dict.items():
|
||||
if key not in ret[afname]:
|
||||
ret[afname][key] = dict()
|
||||
if key == "icon":
|
||||
icons_dir = os.path.join(repodir, 'icons')
|
||||
if not os.path.exists(icons_dir):
|
||||
os.mkdir(icons_dir)
|
||||
shutil.copy(os.path.join("config", value), icons_dir)
|
||||
ret[afname][key][locale] = file_entry(
|
||||
os.path.join(icons_dir, value)
|
||||
)
|
||||
else:
|
||||
ret[afname][key][locale] = value
|
||||
|
||||
for elem in ret.values():
|
||||
for afname in elem:
|
||||
elem[afname] = {locale: v for locale, v in sorted(elem[afname].items())}
|
||||
return ret
|
||||
|
||||
|
||||
def parse_human_readable_size(size):
|
||||
units = {
|
||||
'b': 1,
|
||||
|
|
@ -3866,7 +3915,7 @@ def get_app_display_name(app):
|
|||
if app.get('Name'):
|
||||
return app['Name']
|
||||
if app.get('localized'):
|
||||
localized = app['localized'].get('en-US')
|
||||
localized = app['localized'].get(DEFAULT_LOCALE)
|
||||
if not localized:
|
||||
for v in app['localized'].values():
|
||||
localized = v
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ config = None
|
|||
options = None
|
||||
start_timestamp = time.gmtime()
|
||||
|
||||
GIT_BRANCH = 'master'
|
||||
|
||||
BINARY_TRANSPARENCY_DIR = 'binary_transparency'
|
||||
|
||||
AUTO_S3CFG = '.fdroid-deploy-s3cfg'
|
||||
|
|
@ -407,7 +409,7 @@ def update_servergitmirrors(servergitmirrors, repo_section):
|
|||
elif 'identity_file' in config:
|
||||
ssh_cmd += ' -oIdentitiesOnly=yes -i "%s"' % config['identity_file']
|
||||
|
||||
repo = git.Repo.init(git_mirror_path)
|
||||
repo = git.Repo.init(git_mirror_path, initial_branch=GIT_BRANCH)
|
||||
|
||||
enabled_remotes = []
|
||||
for remote_url in servergitmirrors:
|
||||
|
|
@ -480,7 +482,9 @@ def update_servergitmirrors(servergitmirrors, repo_section):
|
|||
|
||||
logging.debug(_('Pushing to {url}').format(url=remote.url))
|
||||
with repo.git.custom_environment(GIT_SSH_COMMAND=ssh_cmd):
|
||||
pushinfos = remote.push('master', force=True, set_upstream=True, progress=progress)
|
||||
pushinfos = remote.push(
|
||||
GIT_BRANCH, force=True, set_upstream=True, progress=progress
|
||||
)
|
||||
for pushinfo in pushinfos:
|
||||
if pushinfo.flags & (git.remote.PushInfo.ERROR
|
||||
| git.remote.PushInfo.REJECTED
|
||||
|
|
@ -691,7 +695,7 @@ def push_binary_transparency(git_repo_path, git_remote):
|
|||
remote_path = os.path.abspath(git_repo_path)
|
||||
if not os.path.isdir(os.path.join(git_remote, '.git')):
|
||||
os.makedirs(git_remote, exist_ok=True)
|
||||
thumbdriverepo = git.Repo.init(git_remote)
|
||||
thumbdriverepo = git.Repo.init(git_remote, initial_branch=GIT_BRANCH)
|
||||
local = thumbdriverepo.create_remote('local', remote_path)
|
||||
else:
|
||||
thumbdriverepo = git.Repo(git_remote)
|
||||
|
|
@ -702,7 +706,7 @@ def push_binary_transparency(git_repo_path, git_remote):
|
|||
local.set_url(remote_path)
|
||||
else:
|
||||
local = thumbdriverepo.create_remote('local', remote_path)
|
||||
local.pull('master')
|
||||
local.pull(GIT_BRANCH)
|
||||
else:
|
||||
# from online machine to remote on a server on the internet
|
||||
gitrepo = git.Repo(git_repo_path)
|
||||
|
|
@ -713,7 +717,7 @@ def push_binary_transparency(git_repo_path, git_remote):
|
|||
origin.set_url(git_remote)
|
||||
else:
|
||||
origin = gitrepo.create_remote('origin', git_remote)
|
||||
origin.push('master')
|
||||
origin.push(GIT_BRANCH)
|
||||
|
||||
|
||||
def main():
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import re
|
|||
import shutil
|
||||
import tempfile
|
||||
import urllib.parse
|
||||
import yaml
|
||||
import zipfile
|
||||
import calendar
|
||||
import qrcode
|
||||
|
|
@ -43,7 +42,7 @@ from . import common
|
|||
from . import metadata
|
||||
from . import net
|
||||
from . import signindex
|
||||
from fdroidserver.common import FDroidPopen, FDroidPopenBytes, load_stats_fdroid_signing_key_fingerprints
|
||||
from fdroidserver.common import DEFAULT_LOCALE, FDroidPopen, FDroidPopenBytes, load_stats_fdroid_signing_key_fingerprints
|
||||
from fdroidserver.exception import FDroidException, VerificationException
|
||||
|
||||
|
||||
|
|
@ -472,37 +471,6 @@ def dict_diff(source, target):
|
|||
return result
|
||||
|
||||
|
||||
def file_entry(filename, hash_value=None):
|
||||
meta = {}
|
||||
meta["name"] = "/" + filename.split("/", 1)[1]
|
||||
meta["sha256"] = hash_value or common.sha256sum(filename)
|
||||
meta["size"] = os.stat(filename).st_size
|
||||
return meta
|
||||
|
||||
|
||||
def load_locale(name, repodir):
|
||||
lst = {}
|
||||
for yml in Path().glob("config/**/{name}.yml".format(name=name)):
|
||||
locale = yml.parts[1]
|
||||
if len(yml.parts) == 2:
|
||||
locale = "en-US"
|
||||
with open(yml, encoding="utf-8") as fp:
|
||||
elem = yaml.safe_load(fp)
|
||||
for akey, avalue in elem.items():
|
||||
if akey not in lst:
|
||||
lst[akey] = {}
|
||||
for key, value in avalue.items():
|
||||
if key not in lst[akey]:
|
||||
lst[akey][key] = {}
|
||||
if key == "icon":
|
||||
shutil.copy(os.path.join("config", value), os.path.join(repodir, "icons"))
|
||||
lst[akey][key][locale] = file_entry(os.path.join(repodir, "icons", value))
|
||||
else:
|
||||
lst[akey][key][locale] = value
|
||||
|
||||
return lst
|
||||
|
||||
|
||||
def convert_datetime(obj):
|
||||
if isinstance(obj, datetime):
|
||||
# Java prefers milliseconds
|
||||
|
|
@ -550,14 +518,14 @@ def package_metadata(app, repodir):
|
|||
):
|
||||
element_new = element[:1].lower() + element[1:]
|
||||
if element in app and app[element]:
|
||||
meta[element_new] = {"en-US": convert_datetime(app[element])}
|
||||
meta[element_new] = {DEFAULT_LOCALE: convert_datetime(app[element])}
|
||||
elif "localized" in app:
|
||||
localized = {k: v[element_new] for k, v in app["localized"].items() if element_new in v}
|
||||
if localized:
|
||||
meta[element_new] = localized
|
||||
|
||||
if "name" not in meta and app["AutoName"]:
|
||||
meta["name"] = {"en-US": app["AutoName"]}
|
||||
meta["name"] = {DEFAULT_LOCALE: app["AutoName"]}
|
||||
|
||||
# fdroidserver/metadata.py App default
|
||||
if meta["license"] == "Unknown":
|
||||
|
|
@ -568,7 +536,8 @@ def package_metadata(app, repodir):
|
|||
|
||||
# TODO handle different resolutions
|
||||
if app.get("icon"):
|
||||
meta["icon"] = {"en-US": file_entry(os.path.join(repodir, "icons", app["icon"]))}
|
||||
icon_path = os.path.join(repodir, "icons", app["icon"])
|
||||
meta["icon"] = {DEFAULT_LOCALE: common.file_entry(icon_path)}
|
||||
|
||||
if "iconv2" in app:
|
||||
meta["icon"] = app["iconv2"]
|
||||
|
|
@ -594,16 +563,16 @@ def convert_version(version, app, repodir):
|
|||
ver["file"]["ipfsCIDv1"] = ipfsCIDv1
|
||||
|
||||
if "srcname" in version:
|
||||
ver["src"] = file_entry(os.path.join(repodir, version["srcname"]))
|
||||
ver["src"] = common.file_entry(os.path.join(repodir, version["srcname"]))
|
||||
|
||||
if "obbMainFile" in version:
|
||||
ver["obbMainFile"] = file_entry(
|
||||
ver["obbMainFile"] = common.file_entry(
|
||||
os.path.join(repodir, version["obbMainFile"]),
|
||||
version["obbMainFileSha256"],
|
||||
)
|
||||
|
||||
if "obbPatchFile" in version:
|
||||
ver["obbPatchFile"] = file_entry(
|
||||
ver["obbPatchFile"] = common.file_entry(
|
||||
os.path.join(repodir, version["obbPatchFile"]),
|
||||
version["obbPatchFileSha256"],
|
||||
)
|
||||
|
|
@ -684,11 +653,13 @@ def convert_version(version, app, repodir):
|
|||
def v2_repo(repodict, repodir, archive):
|
||||
repo = {}
|
||||
|
||||
repo["name"] = {"en-US": repodict["name"]}
|
||||
repo["description"] = {"en-US": repodict["description"]}
|
||||
repo["icon"] = {"en-US": file_entry("{}/icons/{}".format(repodir, repodict["icon"]))}
|
||||
repo["name"] = {DEFAULT_LOCALE: repodict["name"]}
|
||||
repo["description"] = {DEFAULT_LOCALE: repodict["description"]}
|
||||
repo["icon"] = {
|
||||
DEFAULT_LOCALE: common.file_entry("%s/icons/%s" % (repodir, repodict["icon"]))
|
||||
}
|
||||
|
||||
config = load_locale("config", repodir)
|
||||
config = common.load_localized_config("config", repodir)
|
||||
if config:
|
||||
repo["name"] = config["archive" if archive else "repo"]["name"]
|
||||
repo["description"] = config["archive" if archive else "repo"]["description"]
|
||||
|
|
@ -702,15 +673,15 @@ def v2_repo(repodict, repodir, archive):
|
|||
|
||||
repo["timestamp"] = repodict["timestamp"]
|
||||
|
||||
antiFeatures = load_locale("antiFeatures", repodir)
|
||||
antiFeatures = common.load_localized_config("antiFeatures", repodir)
|
||||
if antiFeatures:
|
||||
repo["antiFeatures"] = antiFeatures
|
||||
|
||||
categories = load_locale("categories", repodir)
|
||||
categories = common.load_localized_config("categories", repodir)
|
||||
if categories:
|
||||
repo["categories"] = categories
|
||||
|
||||
channels = load_locale("channels", repodir)
|
||||
channels = common.load_localized_config("channels", repodir)
|
||||
if channels:
|
||||
repo["releaseChannels"] = channels
|
||||
|
||||
|
|
@ -735,7 +706,7 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
|||
|
||||
output = collections.OrderedDict()
|
||||
output["repo"] = v2_repo(repodict, repodir, archive)
|
||||
if requestsdict and requestsdict["install"] or requestsdict["uninstall"]:
|
||||
if requestsdict and (requestsdict["install"] or requestsdict["uninstall"]):
|
||||
output["repo"]["requests"] = requestsdict
|
||||
|
||||
# establish sort order of the index
|
||||
|
|
@ -792,7 +763,7 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
|||
else:
|
||||
json.dump(output, fp, default=_index_encoder_default, ensure_ascii=False)
|
||||
|
||||
entry["index"] = file_entry(index_file)
|
||||
entry["index"] = common.file_entry(index_file)
|
||||
entry["index"]["numPackages"] = len(output.get("packages", []))
|
||||
|
||||
indexes = sorted(Path().glob("tmp/{}*.json".format(repodir)), key=lambda x: x.name)
|
||||
|
|
@ -819,7 +790,7 @@ def make_v2(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
|||
else:
|
||||
json.dump(diff, fp, default=_index_encoder_default, ensure_ascii=False)
|
||||
|
||||
entry["diffs"][old["repo"]["timestamp"]] = file_entry(diff_file)
|
||||
entry["diffs"][old["repo"]["timestamp"]] = common.file_entry(diff_file)
|
||||
entry["diffs"][old["repo"]["timestamp"]]["numPackages"] = len(diff.get("packages", []))
|
||||
|
||||
json_name = "entry.json"
|
||||
|
|
@ -872,10 +843,10 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
|||
|
||||
appslist = []
|
||||
output['apps'] = appslist
|
||||
for packageName, appdict in apps.items():
|
||||
for packageName, app_dict in apps.items():
|
||||
d = collections.OrderedDict()
|
||||
appslist.append(d)
|
||||
for k, v in sorted(appdict.items()):
|
||||
for k, v in sorted(app_dict.items()):
|
||||
if not v:
|
||||
continue
|
||||
if k in ('Builds', 'metadatapath',
|
||||
|
|
@ -901,20 +872,20 @@ def make_v1(apps, packages, repodir, repodict, requestsdict, fdroid_signing_key_
|
|||
d[k] = v
|
||||
|
||||
# establish sort order in lists, sets, and localized dicts
|
||||
for app in output['apps']:
|
||||
localized = app.get('localized')
|
||||
for app_dict in output['apps']:
|
||||
localized = app_dict.get('localized')
|
||||
if localized:
|
||||
lordered = collections.OrderedDict()
|
||||
for lkey, lvalue in sorted(localized.items()):
|
||||
lordered[lkey] = collections.OrderedDict()
|
||||
for ikey, iname in sorted(lvalue.items()):
|
||||
lordered[lkey][ikey] = iname
|
||||
app['localized'] = lordered
|
||||
antiFeatures = app.get('antiFeatures', [])
|
||||
if apps[app["packageName"]].get("NoSourceSince"):
|
||||
app_dict['localized'] = lordered
|
||||
antiFeatures = app_dict.get('antiFeatures', [])
|
||||
if apps[app_dict["packageName"]].get("NoSourceSince"):
|
||||
antiFeatures.append("NoSourceSince")
|
||||
if antiFeatures:
|
||||
app['antiFeatures'] = sorted(set(antiFeatures))
|
||||
app_dict['antiFeatures'] = sorted(set(antiFeatures))
|
||||
|
||||
output_packages = collections.OrderedDict()
|
||||
output['packages'] = output_packages
|
||||
|
|
@ -1050,7 +1021,7 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
|
|||
lkey = key[:1].lower() + key[1:]
|
||||
localized = app.get('localized')
|
||||
if not value and localized:
|
||||
for lang in ['en-US'] + [x for x in localized.keys()]:
|
||||
for lang in [DEFAULT_LOCALE] + [x for x in localized.keys()]:
|
||||
if not lang.startswith('en'):
|
||||
continue
|
||||
if lang in localized:
|
||||
|
|
@ -1096,8 +1067,8 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
|
|||
root.appendChild(element)
|
||||
element.setAttribute('packageName', packageName)
|
||||
|
||||
for appid, appdict in apps.items():
|
||||
app = metadata.App(appdict)
|
||||
for appid, app_dict in apps.items():
|
||||
app = metadata.App(app_dict)
|
||||
|
||||
if app.get('Disabled') is not None:
|
||||
continue
|
||||
|
|
@ -1294,7 +1265,7 @@ def make_v0(apps, apks, repodir, repodict, requestsdict, fdroid_signing_key_fing
|
|||
namefield = common.config['current_version_name_source']
|
||||
name = app.get(namefield)
|
||||
if not name and namefield == 'Name':
|
||||
name = app.get('localized', {}).get('en-US', {}).get('name')
|
||||
name = app.get('localized', {}).get(DEFAULT_LOCALE, {}).get('name')
|
||||
if not name:
|
||||
name = app.id
|
||||
sanitized_name = re.sub(b'''[ '"&%?+=/]''', b'', str(name).encode('utf-8'))
|
||||
|
|
|
|||
|
|
@ -220,6 +220,19 @@ locale_pattern = re.compile(r"[a-z]{2,3}(-([A-Z][a-zA-Z]+|\d+|[a-z]+))*")
|
|||
|
||||
versioncode_check_pattern = re.compile(r"(\\d|\[(0-9|\\d)_?(a-fA-F)?])[+]")
|
||||
|
||||
ANTIFEATURES_KEYS = None
|
||||
ANTIFEATURES_PATTERN = None
|
||||
|
||||
|
||||
def load_antiFeatures_config():
|
||||
"""Lazy loading, since it might read a lot of files."""
|
||||
global ANTIFEATURES_KEYS, ANTIFEATURES_PATTERN
|
||||
k = 'antiFeatures' # internal dict uses camelCase key name
|
||||
if not ANTIFEATURES_KEYS or k not in common.config:
|
||||
common.config[k] = common.load_localized_config(k, 'repo')
|
||||
ANTIFEATURES_KEYS = sorted(common.config[k].keys())
|
||||
ANTIFEATURES_PATTERN = ','.join(ANTIFEATURES_KEYS)
|
||||
|
||||
|
||||
def check_regexes(app):
|
||||
for f, checks in regex_checks.items():
|
||||
|
|
@ -613,6 +626,26 @@ def check_app_field_types(app):
|
|||
)
|
||||
|
||||
|
||||
def check_antiFeatures(app):
|
||||
"""Check the Anti-Features keys match those declared in the config."""
|
||||
pattern = ANTIFEATURES_PATTERN
|
||||
msg = _("'{value}' is not a valid {field} in {appid}. Regex pattern: {pattern}")
|
||||
|
||||
field = 'AntiFeatures' # App entries use capitalized CamelCase
|
||||
for value in app.get(field, []):
|
||||
if value not in ANTIFEATURES_KEYS:
|
||||
yield msg.format(value=value, field=field, appid=app.id, pattern=pattern)
|
||||
|
||||
field = 'antifeatures' # Build entries use all lowercase
|
||||
for build in app.get('Builds', []):
|
||||
build_antiFeatures = build.get(field, [])
|
||||
for value in build_antiFeatures:
|
||||
if value not in ANTIFEATURES_KEYS:
|
||||
yield msg.format(
|
||||
value=value, field=field, appid=app.id, pattern=pattern
|
||||
)
|
||||
|
||||
|
||||
def check_for_unsupported_metadata_files(basedir=""):
|
||||
"""Check whether any non-metadata files are in metadata/."""
|
||||
basedir = Path(basedir)
|
||||
|
|
@ -745,6 +778,7 @@ def main():
|
|||
metadata.warnings_action = options.W
|
||||
|
||||
config = common.read_config(options)
|
||||
load_antiFeatures_config()
|
||||
|
||||
# Get all apps...
|
||||
allapps = metadata.read_metadata(options.appid)
|
||||
|
|
@ -801,6 +835,7 @@ def main():
|
|||
|
||||
app_check_funcs = [
|
||||
check_app_field_types,
|
||||
check_antiFeatures,
|
||||
check_regexes,
|
||||
check_update_check_data_url,
|
||||
check_update_check_data_int,
|
||||
|
|
|
|||
|
|
@ -448,10 +448,6 @@ valuetypes = {
|
|||
r'^[0-9]+ versions$',
|
||||
["ArchivePolicy"]),
|
||||
|
||||
FieldValidator("Anti-Feature",
|
||||
r'^(Ads|Tracking|NonFreeNet|NonFreeDep|NonFreeAdd|UpstreamNonFree|NonFreeAssets|KnownVuln|ApplicationDebuggable|NoSourceSince|NSFW)$',
|
||||
["AntiFeatures"]),
|
||||
|
||||
FieldValidator("Auto Update Mode",
|
||||
r"^(Version.*|None)$",
|
||||
["AutoUpdateMode"]),
|
||||
|
|
@ -676,7 +672,7 @@ def parse_metadata(metadatapath):
|
|||
# pylint: disable-next=no-member
|
||||
except git.exc.InvalidGitRepositoryError:
|
||||
logging.debug(
|
||||
_('Including metadata from {path}').format(metadata_in_repo)
|
||||
_('Including metadata from {path}').format(path=metadata_in_repo)
|
||||
)
|
||||
app_in_repo = parse_metadata(metadata_in_repo)
|
||||
for k, v in app_in_repo.items():
|
||||
|
|
|
|||
|
|
@ -44,6 +44,22 @@ def proper_format(app):
|
|||
return content == cur_content
|
||||
|
||||
|
||||
def remove_blank_flags_from_builds(builds):
|
||||
"""Remove unset entries from Builds so they are not written out."""
|
||||
if not builds:
|
||||
return list()
|
||||
newbuilds = list()
|
||||
for build in builds:
|
||||
new = dict()
|
||||
for k in metadata.build_flags:
|
||||
v = build[k]
|
||||
if v is None or v is False or v == [] or v == '':
|
||||
continue
|
||||
new[k] = v
|
||||
newbuilds.append(new)
|
||||
return newbuilds
|
||||
|
||||
|
||||
def main():
|
||||
global config, options
|
||||
|
||||
|
|
@ -82,16 +98,9 @@ def main():
|
|||
print(path)
|
||||
continue
|
||||
|
||||
newbuilds = []
|
||||
for build in app.get('Builds', []):
|
||||
new = metadata.Build()
|
||||
for k in metadata.build_flags:
|
||||
v = build[k]
|
||||
if v is None or v is False or v == [] or v == '':
|
||||
continue
|
||||
new[k] = v
|
||||
newbuilds.append(new)
|
||||
app['Builds'] = newbuilds
|
||||
builds = remove_blank_flags_from_builds(app.get('Builds'))
|
||||
if builds:
|
||||
app['Builds'] = builds
|
||||
|
||||
# rewrite to temporary file before overwriting existing
|
||||
# file in case there's a bug in write_metadata
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ from . import _
|
|||
from . import common
|
||||
from . import index
|
||||
from . import metadata
|
||||
from .common import DEFAULT_LOCALE
|
||||
from .exception import BuildException, FDroidException, VerificationException
|
||||
|
||||
from PIL import Image, PngImagePlugin
|
||||
|
|
@ -1037,7 +1038,7 @@ def insert_localized_app_metadata(apps):
|
|||
base = "iconv2"
|
||||
if base not in apps[packageName] or not isinstance(apps[packageName][base], collections.OrderedDict):
|
||||
apps[packageName][base] = collections.OrderedDict()
|
||||
apps[packageName][base][locale] = index.file_entry(dst)
|
||||
apps[packageName][base][locale] = common.file_entry(dst)
|
||||
for d in dirs:
|
||||
if d in SCREENSHOT_DIRS:
|
||||
if locale == 'images':
|
||||
|
|
@ -1090,7 +1091,7 @@ def insert_localized_app_metadata(apps):
|
|||
base = "iconv2"
|
||||
if base not in apps[packageName] or not isinstance(apps[packageName][base], collections.OrderedDict):
|
||||
apps[packageName][base] = collections.OrderedDict()
|
||||
apps[packageName][base][locale] = index.file_entry(index_file)
|
||||
apps[packageName][base][locale] = common.file_entry(index_file)
|
||||
elif screenshotdir in SCREENSHOT_DIRS:
|
||||
# there can any number of these per locale
|
||||
logging.debug(_('adding to {name}: {path}').format(name=screenshotdir, path=f))
|
||||
|
|
@ -1105,7 +1106,7 @@ def insert_localized_app_metadata(apps):
|
|||
apps[packageName]["screenshots"][newKey] = collections.OrderedDict()
|
||||
if locale not in apps[packageName]["screenshots"][newKey]:
|
||||
apps[packageName]["screenshots"][newKey][locale] = []
|
||||
apps[packageName]["screenshots"][newKey][locale].append(index.file_entry(f))
|
||||
apps[packageName]["screenshots"][newKey][locale].append(common.file_entry(f))
|
||||
else:
|
||||
logging.warning(_('Unsupported graphics file found: {path}').format(path=f))
|
||||
|
||||
|
|
@ -2034,7 +2035,7 @@ def insert_missing_app_names_from_apks(apps, apks):
|
|||
|
||||
The name from the APK is set as the default name for the app if
|
||||
there is no other default set, e.g. app['Name'] or
|
||||
app['localized']['en-US']['name']. The en-US locale is defined in
|
||||
app['localized'][DEFAULT_LOCALE]['name']. The default is defined in
|
||||
the F-Droid ecosystem as the locale of last resort, as in the one
|
||||
that should always be present. en-US is used since it is the
|
||||
locale of the source strings.
|
||||
|
|
@ -2050,7 +2051,7 @@ def insert_missing_app_names_from_apks(apps, apks):
|
|||
for appid, app in apps.items():
|
||||
if app.get('Name') is not None:
|
||||
continue
|
||||
if app.get('localized', {}).get('en-US', {}).get('name') is not None:
|
||||
if app.get('localized', {}).get(DEFAULT_LOCALE, {}).get('name') is not None:
|
||||
continue
|
||||
|
||||
bestver = UNSET_VERSION_CODE
|
||||
|
|
@ -2063,9 +2064,9 @@ def insert_missing_app_names_from_apks(apps, apks):
|
|||
if bestver != UNSET_VERSION_CODE:
|
||||
if 'localized' not in app:
|
||||
app['localized'] = {}
|
||||
if 'en-US' not in app['localized']:
|
||||
app['localized']['en-US'] = {}
|
||||
app['localized']['en-US']['name'] = bestapk.get('name')
|
||||
if DEFAULT_LOCALE not in app['localized']:
|
||||
app['localized'][DEFAULT_LOCALE] = {}
|
||||
app['localized'][DEFAULT_LOCALE]['name'] = bestapk.get('name')
|
||||
|
||||
|
||||
def get_apps_with_packages(apps, apks):
|
||||
|
|
@ -2342,10 +2343,10 @@ def main():
|
|||
add_apks_to_per_app_repos(repodirs[0], apks)
|
||||
for appid, app in apps.items():
|
||||
repodir = os.path.join(appid, 'fdroid', 'repo')
|
||||
appdict = dict()
|
||||
appdict[appid] = app
|
||||
app_dict = dict()
|
||||
app_dict[appid] = app
|
||||
if os.path.isdir(repodir):
|
||||
index.make(appdict, apks, repodir, False)
|
||||
index.make(app_dict, apks, repodir, False)
|
||||
else:
|
||||
logging.info(_('Skipping index generation for {appid}').format(appid=appid))
|
||||
return
|
||||
|
|
|
|||
4
tests/build/info.guardianproject.urzip/.fdroid.yml
Normal file
4
tests/build/info.guardianproject.urzip/.fdroid.yml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
Summary: This should be overridden by metadata/info.guardianproject.urzip.yml
|
||||
Builds:
|
||||
- versionCode: 50
|
||||
|
|
@ -2667,6 +2667,38 @@ class CommonTest(unittest.TestCase):
|
|||
config['smartcardoptions'],
|
||||
)
|
||||
|
||||
def test_load_localized_config(self):
|
||||
"""It should load"""
|
||||
antiFeatures = fdroidserver.common.load_localized_config('antiFeatures', 'repo')
|
||||
self.assertEqual(
|
||||
[
|
||||
'Ads',
|
||||
'DisabledAlgorithm',
|
||||
'KnownVuln',
|
||||
'NSFW',
|
||||
'NoSourceSince',
|
||||
'NonFreeAdd',
|
||||
'NonFreeAssets',
|
||||
'NonFreeDep',
|
||||
'NonFreeNet',
|
||||
'Tracking',
|
||||
'UpstreamNonFree',
|
||||
],
|
||||
list(antiFeatures.keys()),
|
||||
)
|
||||
self.assertEqual(
|
||||
['de', 'en-US', 'fa', 'ro', 'zh-rCN'],
|
||||
list(antiFeatures['Ads']['description'].keys()),
|
||||
)
|
||||
self.assertEqual(
|
||||
['en-US'],
|
||||
list(antiFeatures['NoSourceSince']['description'].keys()),
|
||||
)
|
||||
# it should have copied the icon files into place
|
||||
for v in antiFeatures.values():
|
||||
p = Path(os.path.dirname(__file__) + '/repo' + v['icon']['en-US']['name'])
|
||||
self.assertTrue(p.exists())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
|
|
|
|||
45
tests/config/antiFeatures.yml
Normal file
45
tests/config/antiFeatures.yml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
Ads:
|
||||
description: This app contains advertising
|
||||
icon: ic_antifeature_ads.xml
|
||||
name: Ads
|
||||
DisabledAlgorithm:
|
||||
description: This app has a weak security signature
|
||||
icon: ic_antifeature_disabledalgorithm.xml
|
||||
name: Signed Using An Unsafe Algorithm
|
||||
KnownVuln:
|
||||
description: This app contains a known security vulnerability
|
||||
icon: ic_antifeature_knownvuln.xml
|
||||
name: Known Vulnerability
|
||||
NSFW:
|
||||
description: This app contains content that should not be publicized or visible
|
||||
everywhere
|
||||
icon: ic_antifeature_nsfw.xml
|
||||
name: NSFW
|
||||
NoSourceSince:
|
||||
description: The source code is no longer available, no updates possible.
|
||||
icon: ic_antifeature_nosourcesince.xml
|
||||
name: Newer Source Not Available
|
||||
NonFreeAdd:
|
||||
description: This app promotes non-free add-ons
|
||||
icon: ic_antifeature_nonfreeadd.xml
|
||||
name: Non-Free Addons
|
||||
NonFreeAssets:
|
||||
description: This app contains non-free assets
|
||||
icon: ic_antifeature_nonfreeassets.xml
|
||||
name: Non-Free Assets
|
||||
NonFreeDep:
|
||||
description: This app depends on other non-free apps
|
||||
icon: ic_antifeature_nonfreedep.xml
|
||||
name: Non-Free Dependencies
|
||||
NonFreeNet:
|
||||
description: This app promotes or depends entirely on a non-free network service
|
||||
icon: ic_antifeature_nonfreenet.xml
|
||||
name: Non-Free Network Services
|
||||
Tracking:
|
||||
description: This app tracks and reports your activity
|
||||
icon: ic_antifeature_tracking.xml
|
||||
name: Tracking
|
||||
UpstreamNonFree:
|
||||
description: The upstream source code is not entirely Free
|
||||
icon: ic_antifeature_upstreamnonfree.xml
|
||||
name: Upstream Non-Free
|
||||
44
tests/config/de/antiFeatures.yml
Normal file
44
tests/config/de/antiFeatures.yml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
Ads:
|
||||
description: Diese App enthält Werbung
|
||||
icon: ic_antifeature_ads.xml
|
||||
name: Werbung
|
||||
DisabledAlgorithm:
|
||||
description: Diese App hat eine schwache Sicherheitssignatur
|
||||
icon: ic_antifeature_disabledalgorithm.xml
|
||||
name: Mit einem unsicheren Algorithmus signiert
|
||||
KnownVuln:
|
||||
description: Diese App enthält eine bekannte Sicherheitslücke
|
||||
icon: ic_antifeature_knownvuln.xml
|
||||
name: Bekannte Sicherheitslücke
|
||||
NSFW:
|
||||
description: Diese App enthält Inhalte, die nicht überall veröffentlicht oder sichtbar
|
||||
sein sollten
|
||||
icon: ic_antifeature_nsfw.xml
|
||||
name: NSFW
|
||||
NoSourceSince:
|
||||
icon: ic_antifeature_nosourcesince.xml
|
||||
name: Der Quellcode ist nicht mehr erhältlich, keine Aktualisierungen möglich.
|
||||
NonFreeAdd:
|
||||
description: Diese App bewirbt nicht-quelloffene Erweiterungen
|
||||
icon: ic_antifeature_nonfreeadd.xml
|
||||
name: Nicht-quelloffene Erweiterungen
|
||||
NonFreeAssets:
|
||||
description: Diese App enthält nicht-quelloffene Bestandteile
|
||||
icon: ic_antifeature_nonfreeassets.xml
|
||||
name: Nicht-quelloffene Bestandteile
|
||||
NonFreeDep:
|
||||
description: Diese App ist abhängig von anderen nicht-quelloffenen Apps
|
||||
icon: ic_antifeature_nonfreedep.xml
|
||||
name: Nicht-quelloffene Abhängigkeiten
|
||||
NonFreeNet:
|
||||
description: Diese App bewirbt nicht-quelloffene Netzwerkdienste
|
||||
icon: ic_antifeature_nonfreenet.xml
|
||||
name: Nicht-quelloffene Netzwerkdienste
|
||||
Tracking:
|
||||
description: Diese App verfolgt und versendet Ihre Aktivitäten
|
||||
icon: ic_antifeature_tracking.xml
|
||||
name: Tracking
|
||||
UpstreamNonFree:
|
||||
description: Der Originalcode ist nicht völlig quelloffen
|
||||
icon: ic_antifeature_upstreamnonfree.xml
|
||||
name: Originalcode nicht-quelloffen
|
||||
43
tests/config/fa/antiFeatures.yml
Normal file
43
tests/config/fa/antiFeatures.yml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
Ads:
|
||||
description: این کاره دارای تبلیغات است
|
||||
icon: ic_antifeature_ads.xml
|
||||
name: تبلیغات
|
||||
DisabledAlgorithm:
|
||||
description: این کاره، امضای امنیتی ضعیفی دارد
|
||||
icon: ic_antifeature_disabledalgorithm.xml
|
||||
name: امضا شده با الگوریتمی ناامن
|
||||
KnownVuln:
|
||||
description: این کاره، آسیبپذیری امنیتی شناختهشدهای دارد
|
||||
icon: ic_antifeature_knownvuln.xml
|
||||
name: آسیبپذیری شناخته
|
||||
NSFW:
|
||||
description: این کاره محتوایی دارد که نباید عمومی شده یا همهحا نمایان باشد
|
||||
icon: ic_antifeature_nsfw.xml
|
||||
name: NSFW
|
||||
NoSourceSince:
|
||||
icon: ic_antifeature_nosourcesince.xml
|
||||
name: کد مبدأ دیگر در دسترس نیست. بهروز رسانی ناممکن است.
|
||||
NonFreeAdd:
|
||||
description: این کاره، افزونههای ناآزاد را تبلیغ میکند
|
||||
icon: ic_antifeature_nonfreeadd.xml
|
||||
name: افزونههای ناآزاد
|
||||
NonFreeAssets:
|
||||
description: این کاره دارای بخشهای ناآزاد است
|
||||
icon: ic_antifeature_nonfreeassets.xml
|
||||
name: بخشهای ناآزاد
|
||||
NonFreeDep:
|
||||
description: این کاره به دیگر کارههای ناآزاد وابسته است
|
||||
icon: ic_antifeature_nonfreedep.xml
|
||||
name: وابستگیهای ناآزاد
|
||||
NonFreeNet:
|
||||
description: این کاره، خدمات شبکههای ناآزاد را ترویج میکند
|
||||
icon: ic_antifeature_nonfreenet.xml
|
||||
name: خدمات شبکهای ناآزاد
|
||||
Tracking:
|
||||
description: این کاره، فعّالیتتان را ردیابی و گزارش میکند
|
||||
icon: ic_antifeature_tracking.xml
|
||||
name: ردیابی
|
||||
UpstreamNonFree:
|
||||
description: کد مبدأ بالادستی کاملاً آزاد نیست
|
||||
icon: ic_antifeature_upstreamnonfree.xml
|
||||
name: بالادست ناآزاد
|
||||
15
tests/config/ic_antifeature_ads.xml
Normal file
15
tests/config/ic_antifeature_ads.xml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:tools="http://schemas.android.com/tools"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
tools:ignore="VectorRaster">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M32.56,11.19a3,3 0,0 0,-3.07 0.44h0a44.91,44.91 0,0 1,-13.55 8.07,2.67 2.67,0 0,0 -2.51,-2.08H8.76a2.84,2.84 0,0 0,-2.64 3.06v6A3.08,3.08 0,0 0,7.66 29.5c0.28,7 2.5,11.65 4.05,12.8a2.65,2.65 0,0 0,1.61 0.47,7.75 7.75,0 0,0 3.17,-0.89c1.55,-0.79 2.33,-1.67 2.32,-2.64A6.52,6.52 0,0 0,18 36.92,25 25,0 0,1 16.5,33a14.59,14.59 0,0 1,-0.44 -4.38,1.28 1.28,0 0,0 0,-0.37c2.13,0.41 7,1.91 13.44,7.49a3.13,3.13 0,0 0,2 0.73,2.63 2.63,0 0,0 1.1,-0.24c0.62,-0.28 1.66,-1.08 1.66,-3.19V14.34A3.13,3.13 0,0 0,32.56 11.19ZM8.71,20.69a0.78,0.78 0,0 1,0.13 -0.47h4.5a0.78,0.78 0,0 1,0.13 0.47v6a0.78,0.78 0,0 1,-0.13 0.47H8.85a0.78,0.78 0,0 1,-0.13 -0.47ZM16.13,39.1a5.6,5.6 0,0 1,-2.92 1.09c-0.63,-0.58 -2.62,-4.2 -2.94,-10.41h3.18A17.66,17.66 0,0 0,14 33.62,27.5 27.5,0 0,0 15.65,38C15.82,38.36 16,38.8 16.13,39.1ZM31.63,33a1.67,1.67 0,0 1,-0.14 0.83,0.47 0.47,0 0,1 -0.31,-0.09C24,27.52 18.51,26 16.07,25.6V22.37c2.44,-0.64 8.75,-3.41 15.09,-8.75h0a0.42,0.42 0,0 1,0.3 -0.07s0.16,0.24 0.16,0.8Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M40.86,13.17 L44,6.11a1.3,1.3 0,0 0,-2.37 -1l-4.72,10.7h5.27l-3.62,7A1.3,1.3 0,1 0,40.83 24l5.56,-10.82Z" />
|
||||
</vector>
|
||||
21
tests/config/ic_antifeature_disabledalgorithm.xml
Normal file
21
tests/config/ic_antifeature_disabledalgorithm.xml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<vector xmlns:tools="http://schemas.android.com/tools"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
tools:ignore="VectorRaster">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M36.24,30.79l-2.18,-2.33A10,10 0,0 0,30.4 26a9.64,9.64 0,0 0,-1.28 -2.77A1.3,1.3 0,1 0,27 24.63a7.38,7.38 0,0 1,0.42 0.73,6.59 6.59,0 0,0 -4.63,1.71 6.51,6.51 0,0 0,-2 4.22,7.7 7.7,0 0,1 -1.48,-1.21l-2.18,-2.33A7.76,7.76 0,0 1,16 26.16,6.37 6.37,0 0,0 22.36,20a7.38,7.38 0,0 1,0.69 0.46,1.3 1.3,0 1,0 1.59,-2.05A9.65,9.65 0,0 0,22 16.92a10,10 0,0 0,-2.25 -3.83l-2.18,-2.33C14.26,7.24 9.18,6.62 6.23,9.37a6.74,6.74 0,0 0,-2 5.53,9.63 9.63,0 0,0 2.64,5.84L9,23.07a9.94,9.94 0,0 0,3.91 2.59,10.05 10.05,0 0,0 2.26,3.84l2.18,2.33A10,10 0,0 0,21 34.34a10,10 0,0 0,2.33 4.1l2.18,2.33a9.4,9.4 0,0 0,6.75 3.11,6.58 6.58,0 0,0 4.55,-1.72 6.74,6.74 0,0 0,2 -5.53A9.63,9.63 0,0 0,36.24 30.79ZM19.77,19.11a4.2,4.2 0,0 1,-1.22 3.46,4.18 4.18,0 0,1 -3.42,1s0,0 0,-0.06A4.2,4.2 0,0 1,16.35 20a4.2,4.2 0,0 1,3.41 -1S19.77,19.09 19.77,19.11ZM8.73,19a7,7 0,0 1,-2 -4.25A4.2,4.2 0,0 1,8 11.26a4,4 0,0 1,2.8 -1,6.84 6.84,0 0,1 4.85,2.3l2.18,2.33a7.7,7.7 0,0 1,1.11 1.57,6.4 6.4,0 0,0 -6.39,6.19 7.69,7.69 0,0 1,-1.63 -1.31ZM24.52,29a4.23,4.23 0,0 1,3.59 -1,3.94 3.94,0 0,1 -4.81,4.31A4.17,4.17 0,0 1,24.52 29ZM35.07,40.3C33.17,42 29.74,41.48 27.43,39l-2.18,-2.33a7.68,7.68 0,0 1,-1.2 -1.73h0.06A6.39,6.39 0,0 0,30.68 29a7.7,7.7 0,0 1,1.49 1.22l2.18,2.33a7,7 0,0 1,2 4.25A4.2,4.2 0,0 1,35.07 40.26Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M41.09,19.1a1.59,1.59 0,0 0,-1.87 -1.21l-4.57,1a1.54,1.54 0,0 0,-0.57 0.24h0a1.58,1.58 0,0 0,1.27 2.83l4.57,-1A1.55,1.55 0,0 0,41.09 19.1Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M33.93,16.3l0.06,-0.05 3.48,-3.1a1.58,1.58 0,0 0,-2 -2.41l-0.06,0.05 -3.48,3.1a1.58,1.58 0,0 0,2 2.41Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M27.14,14.49A1.54,1.54 0,0 0,29 13.34h0l1,-4.56a1.59,1.59 0,0 0,-1.15 -1.91,1.55 1.55,0 0,0 -1.49,0.4h0A1.54,1.54 0,0 0,27 8l-1,4.56A1.59,1.59 0,0 0,27.14 14.49Z" />
|
||||
</vector>
|
||||
15
tests/config/ic_antifeature_knownvuln.xml
Normal file
15
tests/config/ic_antifeature_knownvuln.xml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:tools="http://schemas.android.com/tools"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
tools:ignore="VectorRaster">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M37.55,32.13a1.27,1.27 0,0 0,-0.43 0v-1.5h7.94a1.3,1.3 0,0 0,0 -2.59L37.12,28.04L37.12,26.71a1.24,1.24 0,0 0,0.18 0l0.25,0c3.44,-0.67 7.38,-5 8.61,-9.4a1.3,1.3 0,1 0,-2.5 -0.7c-1,3.7 -4.35,7.06 -6.55,7.53L37.11,20.58a1.3,1.3 0,0 0,-1.3 -1.3L33.54,19.28c0,-1.14 0,-3.88 0,-5a9.24,9.24 0,0 0,-18.47 0,1.3 1.3,0 1,0 2.59,0 6.64,6.64 0,0 1,13.29 0c0,1.08 0,3.81 0,5L13.14,19.28a1.3,1.3 0,0 0,-1.3 1.3v3.57c-2.2,-0.49 -5.51,-3.84 -6.53,-7.53a1.3,1.3 0,1 0,-2.5 0.7C4,21.75 8,26.06 11.43,26.72l0.25,0a1.24,1.24 0,0 0,0.17 0L11.85,28L3.65,28a1.3,1.3 0,1 0,0 2.59h8.2v1.5a1.26,1.26 0,0 0,-0.42 0c-3.44,0.67 -7.38,5 -8.61,9.4a1.3,1.3 0,1 0,2.5 0.7c1,-3.69 4.33,-7 6.53,-7.53v2.84a1.3,1.3 0,0 0,1.3 1.3L35.82,38.8a1.3,1.3 0,0 0,1.3 -1.3L37.12,34.69c2.2,0.48 5.52,3.83 6.55,7.53a1.3,1.3 0,1 0,2.5 -0.7C44.93,37.1 41,32.79 37.55,32.13ZM34.55,36.24L14.44,36.24L14.44,21.88L34.52,21.88Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M24.5,28.82m-2.44,0a2.44,2.44 0,1 1,4.88 0a2.44,2.44 0,1 1,-4.88 0" />
|
||||
</vector>
|
||||
19
tests/config/ic_antifeature_nonfreeadd.xml
Normal file
19
tests/config/ic_antifeature_nonfreeadd.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M32.83,26.35H29.65a2.68,2.68 0,0 0,-3 -2.27h-0.18c-2.4,0 -3.35,1.82 -3.43,4.5s1.54,4.54 3.43,4.5a2.73,2.73 0,0 0,3 -2.44h3.56c-0.59,3.34 -3,5.29 -6.53,5.3 -3.94,0 -6.8,-3.29 -6.8,-7.36 0,-4.34 2.85,-7.36 6.8,-7.36H27c2.46,0 5.81,1.77 5.81,5.13Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16.28,23.15h0A1.87,1.87 0,0 1,18.14 25h0a1.87,1.87 0,0 1,-1.86 1.87h0A1.87,1.87 0,0 1,14.42 25h0A1.87,1.87 0,0 1,16.28 23.15Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16.28,29.7h0a1.87,1.87 0,0 1,1.86 1.87h0a1.87,1.87 0,0 1,-1.86 1.87h0a1.87,1.87 0,0 1,-1.86 -1.87h0A1.87,1.87 0,0 1,16.28 29.7Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11,41.81a1.5,1.5 0,0 1,-1.5 -1.5L9.5,16.24a1.5,1.5 0,0 1,1.5 -1.5h8.71l0,-0.82A4.54,4.54 0,0 1,17.9 10.6,3.62 3.62,0 0,1 19,8a7,7 0,0 1,5.08 -1.81c5.65,0 6.35,3.1 6.38,4.42A4.61,4.61 0,0 1,28.76 14v0.79h8.19a1.5,1.5 0,0 1,1.5 1.49l0,7.6a1.3,1.3 0,0 1,-1.29 1.3h0a1.3,1.3 0,0 1,-1.3 -1.29l0,-6.51h-8.4a1.3,1.3 0,0 1,-1.3 -1.3v-2.7a1.3,1.3 0,0 1,0.55 -1.06c0.49,-0.35 1.17,-1.1 1.15,-1.59 0,-1.25 -1.32,-1.89 -3.8,-1.9a4.62,4.62 0,0 0,-3.22 1,1.08 1.08,0 0,0 -0.36,0.73c0,0.88 1.09,1.55 1.1,1.55a1.3,1.3 0,0 1,0.65 1.05L22.4,16a1.3,1.3 0,0 1,-1.29 1.37h-9L12.11,39.21l23.74,0c0,-0.33 0,-0.74 0,-1.21 0,-1.43 0,-3.4 0,-5.17a1.3,1.3 0,0 1,1.29 -1.3h0a1.3,1.3 0,0 1,1.3 1.29c0,1.79 0,3.77 0,5.21 0,0.72 0,1.3 0,1.67 0,0.07 0,0.32 0,0.55 -0.11,1.45 -1.09,1.56 -1.39,1.56l-26,0ZM11,39.22h0ZM37,39.22h0Z" />
|
||||
</vector>
|
||||
19
tests/config/ic_antifeature_nonfreeassets.xml
Normal file
19
tests/config/ic_antifeature_nonfreeassets.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M17.08,18.06h0a1.87,1.87 0,0 1,1.86 1.87h0a1.87,1.87 0,0 1,-1.86 1.87h0a1.87,1.87 0,0 1,-1.86 -1.87h0A1.87,1.87 0,0 1,17.08 18.06Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M17.08,26.28h0a1.87,1.87 0,0 1,1.86 1.87h0A1.87,1.87 0,0 1,17.08 30h0a1.87,1.87 0,0 1,-1.86 -1.87h0A1.87,1.87 0,0 1,17.08 26.28Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M33.18,22H30a2.68,2.68 0,0 0,-3 -2.27h-0.18c-2.4,0 -3.35,1.82 -3.43,4.5s1.54,4.54 3.43,4.5a2.73,2.73 0,0 0,3 -2.44h3.56c-0.59,3.34 -3,5.29 -6.53,5.3 -3.94,0 -6.8,-3.29 -6.8,-7.36 0,-4.34 2.85,-7.36 6.8,-7.36h0.43c2.46,0 5.81,1.77 5.81,5.13Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M39.29,7.11h-30A3.85,3.85 0,0 0,6.44 8.37h0v0a3.59,3.59 0,0 0,-0.9 2.37L5.54,37.63a3.75,3.75 0,0 0,3.8 3.68h30a3.75,3.75 0,0 0,3.8 -3.68L43.14,10.79A3.75,3.75 0,0 0,39.29 7.11ZM39.48,9.71a1.86,1.86 0,1 1,-1.85 1.86A1.85,1.85 0,0 1,39.48 9.71ZM39.48,17.93a1.86,1.86 0,1 1,-1.85 1.86A1.85,1.85 0,0 1,39.48 17.94ZM9.06,38.34h0a1.87,1.87 0,0 1,0 -3.75h0a1.87,1.87 0,0 1,0 3.75ZM9.06,30.05h0a1.87,1.87 0,0 1,0 -3.75h0a1.87,1.87 0,0 1,0 3.75ZM9.06,21.76h0a1.87,1.87 0,0 1,0 -3.75h0a1.87,1.87 0,0 1,0 3.75ZM9.06,13.47h0a1.87,1.87 0,0 1,0 -3.75h0a1.87,1.87 0,0 1,0 3.75ZM36,38.71L12.23,38.71L12.23,9.7L36,9.7ZM39.51,38.33a1.87,1.87 0,1 1,1.86 -1.87A1.87,1.87 0,0 1,39.48 38.34ZM39.51,30.04a1.87,1.87 0,1 1,1.86 -1.87A1.87,1.87 0,0 1,39.48 30Z" />
|
||||
</vector>
|
||||
22
tests/config/ic_antifeature_nonfreedep.xml
Normal file
22
tests/config/ic_antifeature_nonfreedep.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9.38,17.97a1.49,1.46 0,1 0,2.98 0a1.49,1.46 0,1 0,-2.98 0z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M34.73,9.72a1.3,1.3 0,0 0,-1.3 1.3V33.07l-7.19,-5.52a12,12 0,1 0,-1.67 2l8.29,6.37a1.27,1.27 0,0 0,0.56 0.23v6.4a1.3,1.3 0,1 0,2.59 0V11A1.3,1.3 0,0 0,34.73 9.72ZM16.33,30.27a9.33,9.33 0,1 1,9.33 -9.33A9.34,9.34 0,0 1,16.33 30.27Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M41.67,9.72a1.3,1.3 0,0 0,-1.3 1.3V42.54a1.3,1.3 0,1 0,2.59 0V11A1.3,1.3 0,0 0,41.67 9.72Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9.38,23.81a1.49,1.46 0,1 0,2.98 0a1.49,1.46 0,1 0,-2.98 0z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.08,22.43A1.74,1.74 0,0 1,18.13 24h0a1.93,1.93 0,0 1,-1.38 -0.59,3.12 3.12,0 0,1 -0.78,-2.32c0.06,-1.94 0.8,-2.92 2.2,-2.92h0.18a1.68,1.68 0,0 1,1.83 1.44v0.07h2.28v-0.09c0,-2.34 -2.36,-3.48 -4,-3.5h-0.28c-2.72,0 -4.62,2.05 -4.62,5A5.23,5.23 0,0 0,15 24.77a4.41,4.41 0,0 0,3.14 1.29h0a4.19,4.19 0,0 0,4.43 -3.6l0,-0.1H20.09Z" />
|
||||
</vector>
|
||||
37
tests/config/ic_antifeature_nonfreenet.xml
Normal file
37
tests/config/ic_antifeature_nonfreenet.xml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13.65,31.74L13,31.74a10.63,10.63 0,0 1,0 -21.25C15.18,7.25 19.22,4.1 23.66,3.9h0c6.23,-0.23 11.08,3.49 13.09,10a8.91,8.91 0,0 1,0 17.82L13.65,31.72ZM13.21,13.06A8,8 0,0 0,13 29.14L36.69,29.14a6.32,6.32 0,0 0,-0.23 -12.64l-0.54,0 -1.11,0.11 -0.27,-1.08c-0.72,-2.82 -3.19,-9.35 -10.76,-9.07h0c-3.23,0.14 -7,2.61 -9.06,6l-0.42,0.67 -0.78,-0.06Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.33,14.71h0a1.87,1.87 0,0 1,1.86 1.87h0a1.87,1.87 0,0 1,-1.86 1.87h0a1.87,1.87 0,0 1,-1.86 -1.87h0A1.87,1.87 0,0 1,15.33 14.71Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.33,20.77h0a1.87,1.87 0,0 1,1.86 1.87h0a1.87,1.87 0,0 1,-1.86 1.87h0a1.87,1.87 0,0 1,-1.86 -1.87h0A1.87,1.87 0,0 1,15.33 20.77Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M36.27,39.92a1.3,1.3 0,0 1,-1.1 -2l2.28,-3.68a1.3,1.3 0,1 1,2.2 1.37l-2.28,3.68A1.3,1.3 0,0 1,36.27 39.92Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M27.92,43.41a1.3,1.3 0,0 1,-1.1 -2l2.28,-3.68a1.3,1.3 0,1 1,2.2 1.37L29,42.79A1.3,1.3 0,0 1,27.92 43.41Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M22.17,39.92a1.3,1.3 0,0 1,-1.1 -2l2.28,-3.68a1.3,1.3 0,1 1,2.2 1.37l-2.28,3.68A1.3,1.3 0,0 1,22.17 39.92Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13.83,43.41a1.3,1.3 0,0 1,-1.1 -2L15,37.75a1.3,1.3 0,1 1,2.2 1.37l-2.28,3.68A1.3,1.3 0,0 1,13.83 43.41Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8.64,39.84a1.3,1.3 0,0 1,-1.1 -2l2.28,-3.68A1.3,1.3 0,0 1,12 35.55L9.74,39.23A1.3,1.3 0,0 1,8.64 39.84Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M30.28,17.37H27.56A2.3,2.3 0,0 0,25 15.43h-0.15c-2.06,0 -2.87,1.56 -2.94,3.85s1.32,3.89 2.94,3.85A2.34,2.34 0,0 0,27.48 21h3.05a5.28,5.28 0,0 1,-5.59 4.54c-3.38,0 -5.82,-2.82 -5.82,-6.3 0,-3.72 2.44,-6.3 5.82,-6.3h0.37C27.42,13 30.28,14.5 30.28,17.37Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M24.93,25.63a5.61,5.61 0,0 1,-4 -1.64,6.56 6.56,0 0,1 -1.86,-4.7 6.65,6.65 0,0 1,1.65 -4.57,5.67 5.67,0 0,1 4.21,-1.77h0.37c2,0 5,1.47 5,4.44v0H27.52v0a2.23,2.23 0,0 0,-2.42 -1.91h-0.23c-1.85,0 -2.82,1.28 -2.9,3.81a4.07,4.07 0,0 0,1 3,2.55 2.55,0 0,0 1.87,0.78A2.3,2.3 0,0 0,27.44 21v0h3.14v0.05a5.32,5.32 0,0 1,-5.64 4.57ZM25.14,13h-0.2c-3.4,0 -5.78,2.57 -5.78,6.26A6.48,6.48 0,0 0,21 23.93a5.53,5.53 0,0 0,3.93 1.62h0a5.24,5.24 0,0 0,5.54 -4.45h-3a2.39,2.39 0,0 1,-2.64 2.09h-0.05a2.63,2.63 0,0 1,-1.88 -0.8,4.15 4.15,0 0,1 -1.05,-3.1c0.08,-2.59 1.08,-3.9 3,-3.9h0.22a2.34,2.34 0,0 1,2.5 1.94h2.65c0,-2.88 -3,-4.27 -4.94,-4.31h-0.16Z" />
|
||||
</vector>
|
||||
16
tests/config/ic_antifeature_nosourcesince.xml
Normal file
16
tests/config/ic_antifeature_nosourcesince.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M42,31.65L40.6,31.65L40.6,21.46a1.24,1.24 0,0 0,0 -0.26,16.08 16.08,0 0,0 -32.16,0.05 1.31,1.31 0,0 0,0 0.21v10.2L6.9,31.66a1.3,1.3 0,0 0,-1.3 1.3v7.36a1.3,1.3 0,0 0,1.3 1.3L42,41.62a1.3,1.3 0,0 0,1.3 -1.3L43.3,32.95A1.3,1.3 0,0 0,42 31.65ZM11,21.65a1.3,1.3 0,0 0,0 -0.18,13.49 13.49,0 0,1 27,0 1.24,1.24 0,0 0,0 0.24v10L11,31.71ZM40.74,39L8.2,39L8.2,34.25L40.74,34.25Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M28.27,16.23a1.3,1.3 0,0 0,-1.82 1.85l3.9,3.82 -3.9,3.82a1.3,1.3 0,0 0,1.82 1.85l4.84,-4.75a1.3,1.3 0,0 0,0 -1.85Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M22.52,16.25a1.3,1.3 0,0 0,-1.83 0L15.84,21a1.3,1.3 0,0 0,0 1.85l4.84,4.75a1.3,1.3 0,0 0,1.82 -1.85L18.6,21.9l3.9,-3.82A1.3,1.3 0,0 0,22.52 16.25Z" />
|
||||
</vector>
|
||||
4
tests/config/ic_antifeature_nsfw.xml
Normal file
4
tests/config/ic_antifeature_nsfw.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<vector android:height="24dp" android:viewportHeight="48"
|
||||
android:viewportWidth="48" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M21.99,12.34C22,12.23 22,12.11 22,12c0,-5.52 -4.48,-10 -10,-10S2,6.48 2,12c0,5.17 3.93,9.43 8.96,9.95c-0.93,-0.73 -1.72,-1.64 -2.32,-2.68C5.9,18 4,15.22 4,12c0,-1.85 0.63,-3.55 1.69,-4.9l5.66,5.66c0.56,-0.4 1.17,-0.73 1.82,-1L7.1,5.69C8.45,4.63 10.15,4 12,4c4.24,0 7.7,3.29 7.98,7.45C20.69,11.67 21.37,11.97 21.99,12.34zM17,13c-3.18,0 -5.9,1.87 -7,4.5c1.1,2.63 3.82,4.5 7,4.5s5.9,-1.87 7,-4.5C22.9,14.87 20.18,13 17,13zM17,20c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5C19.5,18.88 18.38,20 17,20zM18.5,17.5c0,0.83 -0.67,1.5 -1.5,1.5s-1.5,-0.67 -1.5,-1.5c0,-0.83 0.67,-1.5 1.5,-1.5S18.5,16.67 18.5,17.5z"/>
|
||||
</vector>
|
||||
22
tests/config/ic_antifeature_tracking.xml
Normal file
22
tests/config/ic_antifeature_tracking.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M6.32,34.68a2.83,2.83 0,0 1,-2.54 -1.4,3.12 3.12,0 0,1 0.12,-3.16L9.68,20.3l0.25,-0.45c0.72,-1.31 1.25,-1.49 2.82,-1.5h0l20.2,-0.06h0c1.48,0 2,0.2 2.73,1.43l0.29,0.49L42.12,30a3.07,3.07 0,0 1,0.17 3.14,2.88 2.88,0 0,1 -2.58,1.44l-33.38,0.06ZM12.32,20.96 L12.24,21.11 11.95,21.62L6.13,31.44A0.62,0.62 0,0 0,6 32c0,0.08 0.24,0.09 0.29,0.09h0L39.71,32c0.08,0 0.26,0 0.31,-0.11a0.57,0.57 0,0 0,-0.1 -0.52l-6.11,-9.82c-0.14,-0.22 -0.25,-0.41 -0.34,-0.57l-0.07,-0.12L33,20.86l-20.2,0.06Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M22.94,18.19a8,8 0,0 0,-8.2 7.89A8,8 0,0 0,22.94 34a8,8 0,0 0,8.2 -7.89A8,8 0,0 0,22.94 18.19ZM22.94,31.12a5,5 0,1 1,5.26 -5A5.16,5.16 0,0 1,22.94 31.12Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M22.94,24h0a2.1,2.1 0,0 1,2.14 2.05h0a2.1,2.1 0,0 1,-2.14 2.05h0a2.1,2.1 0,0 1,-2.14 -2.05h0A2.1,2.1 0,0 1,22.94 24Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M42.91,29.16a6.72,6.72 0,0 1,-3.12 -1c-0.71,-0.39 -4.24,-2.45 -4.23,-4.5s3.48,-4 4.18,-4.42c2.92,-1.6 3.94,-0.94 4.28,-0.73 1.24,0.79 1.48,3.31 1.47,5.28 0,2.77 -0.51,4.49 -1.49,5.1A1.89,1.89 0,0 1,42.91 29.16ZM42.47,26.8ZM38.21,23.62a10.84,10.84 0,0 0,4.39 2.91,13.3 13.3,0 0,0 0,-5.75A10.64,10.64 0,0 0,38.21 23.62ZM38.13,23.77ZM38.13,23.47ZM42.87,20.75h0ZM42.47,20.52Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M42.82,42.72H3.15A1.3,1.3 0,0 1,2 40.79l3.49,-6.2a2.72,2.72 0,0 1,-1.74 -1.3,3.12 3.12,0 0,1 0.12,-3.16L9.68,20.3l0.25,-0.45c0.72,-1.31 1.25,-1.49 2.82,-1.5h1.91L21.51,6.17a1.3,1.3 0,0 1,1.12 -0.66,1.28 1.28,0 0,1 1.13,0.64L30.85,18.3h2.1c1.52,0 2.06,0.18 2.77,1.43 0.08,0.14 0.17,0.3 0.29,0.49L42.12,30a3.07,3.07 0,0 1,0.17 3.14,2.8 2.8,0 0,1 -2,1.38l3.62,6.2a1.3,1.3 0,0 1,-1.12 1.95ZM5.37,40.13H40.56L37,34A1.3,1.3 0,0 1,38.1 32h1.61c0.08,0 0.26,0 0.31,-0.11a0.57,0.57 0,0 0,-0.1 -0.52l-6.11,-9.82c-0.14,-0.23 -0.25,-0.41 -0.34,-0.57l-0.07,-0.12h-3.3A1.31,1.31 0,0 1,29 20.26L22.66,9.42 16.54,20.28a1.3,1.3 0,0 1,-1.13 0.66H12.29l-0.08,0.15 -0.29,0.51L6.13,31.44A0.62,0.62 0,0 0,6 32c0,0.08 0.24,0.09 0.29,0.09H7.68A1.3,1.3 0,0 1,8.81 34Z" />
|
||||
</vector>
|
||||
19
tests/config/ic_antifeature_upstreamnonfree.xml
Normal file
19
tests/config/ic_antifeature_upstreamnonfree.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="48"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="48"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.72,22.64a1.86,1.87 0,1 0,3.72 0a1.86,1.87 0,1 0,-3.72 0z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.72,29.24a1.86,1.87 0,1 0,3.72 0a1.86,1.87 0,1 0,-3.72 0z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20.28,26.12c0,4.06 2.85,7.37 6.8,7.36 3.49,0 5.94,-2 6.53,-5.3H30a2.73,2.73 0,0 1,-3 2.44c-1.89,0 -3.51,-1.7 -3.43,-4.5s1,-4.5 3.43,-4.5h0.18a2.68,2.68 0,0 1,3 2.27h3.18c0,-3.36 -3.35,-5.08 -5.81,-5.13h-0.43C23.13,18.76 20.28,21.78 20.28,26.12Z" />
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M24.375,8.9277A1.3,1.3 0,0 0,23.7793 9.0801L5.4492,18.8008A1.3,1.3 0,0 0,6.6699 21.0898L10.1992,19.2109L10.1992,36.6699A3.07,3.07 0,0 0,13.3594 39.6699L35.6406,39.6699A3.07,3.07 0,0 0,38.8008 36.6699L38.8008,19.4609L42.3301,21.3594A1.3,1.3 0,0 0,43.5605 19.0801L43.5605,19.0703L25,9.0801A1.3,1.3 0,0 0,24.375 8.9277zM24.3691,11.6992L36.2207,18.0703L36.2109,36.6699C36.2109,36.8399 35.9706,37.0293 35.6406,37.0293L13.3594,37.0293C13.0394,37.0293 12.7891,36.8399 12.7891,36.6699L12.7891,17.9492L12.7891,17.8496L24.3691,11.6992z" />
|
||||
</vector>
|
||||
44
tests/config/ro/antiFeatures.yml
Normal file
44
tests/config/ro/antiFeatures.yml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
Ads:
|
||||
description: Aplicația conține reclamă
|
||||
icon: ic_antifeature_ads.xml
|
||||
name: Reclame
|
||||
DisabledAlgorithm:
|
||||
description: Aplicația are o semnătură slab securizată
|
||||
icon: ic_antifeature_disabledalgorithm.xml
|
||||
name: Algoritm nesigur semnătură
|
||||
KnownVuln:
|
||||
description: Aplicația conține o vulnerabilitate de securitate cunoscută
|
||||
icon: ic_antifeature_knownvuln.xml
|
||||
name: Vulnerabilitate cunoscută
|
||||
NSFW:
|
||||
description: Această aplicație conține conținut care nu ar trebui să fie făcut public
|
||||
sau vizibil peste tot
|
||||
icon: ic_antifeature_nsfw.xml
|
||||
name: NSFW
|
||||
NoSourceSince:
|
||||
icon: ic_antifeature_nosourcesince.xml
|
||||
name: Codul sursă nu mai este disponibil, nu mai există posibilitatea de a actualiza.
|
||||
NonFreeAdd:
|
||||
description: Aplicația promovează anexe ce nu sunt software liber
|
||||
icon: ic_antifeature_nonfreeadd.xml
|
||||
name: Anexe ne-libere
|
||||
NonFreeAssets:
|
||||
description: Aceasta aplicație conține resurse ce nu sunt la disponibile la liber
|
||||
icon: ic_antifeature_nonfreeassets.xml
|
||||
name: Resurse ne-libere
|
||||
NonFreeDep:
|
||||
description: Aplicația depinde de alte aplicații ce nu sunt software liber
|
||||
icon: ic_antifeature_nonfreedep.xml
|
||||
name: Dependențe ne-libere
|
||||
NonFreeNet:
|
||||
description: Aplicația promovează servicii de rețea ce nu sunt accesibile la liber
|
||||
icon: ic_antifeature_nonfreenet.xml
|
||||
name: Servicii de rețea ne-libere
|
||||
Tracking:
|
||||
description: Aplicația îți înregistrează și raportează activitatea undeva
|
||||
icon: ic_antifeature_tracking.xml
|
||||
name: Urmărire
|
||||
UpstreamNonFree:
|
||||
description: Codul sursa originar nu este în totalitatea lui software liber
|
||||
icon: ic_antifeature_upstreamnonfree.xml
|
||||
name: Surse ne-libere
|
||||
43
tests/config/zh-rCN/antiFeatures.yml
Normal file
43
tests/config/zh-rCN/antiFeatures.yml
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
Ads:
|
||||
description: 此应用包含广告
|
||||
icon: ic_antifeature_ads.xml
|
||||
name: 广告
|
||||
DisabledAlgorithm:
|
||||
description: 此应用的安全签名较弱
|
||||
icon: ic_antifeature_disabledalgorithm.xml
|
||||
name: 使用不安全算法签名
|
||||
KnownVuln:
|
||||
description: 此应用包含已知的安全漏洞
|
||||
icon: ic_antifeature_knownvuln.xml
|
||||
name: 含有已知漏洞
|
||||
NSFW:
|
||||
description: 此应用包含不应宣扬或随处可见的内容
|
||||
icon: ic_antifeature_nsfw.xml
|
||||
name: NSFW
|
||||
NoSourceSince:
|
||||
icon: ic_antifeature_nosourcesince.xml
|
||||
name: 源代码不再可用,无法更新。
|
||||
NonFreeAdd:
|
||||
description: 此应用推广非自由的附加组件
|
||||
icon: ic_antifeature_nonfreeadd.xml
|
||||
name: 非自由附加组件
|
||||
NonFreeAssets:
|
||||
description: 此应用包含非自由资源
|
||||
icon: ic_antifeature_nonfreeassets.xml
|
||||
name: 非自由资产
|
||||
NonFreeDep:
|
||||
description: 此应用依赖于其它非自由应用
|
||||
icon: ic_antifeature_nonfreedep.xml
|
||||
name: 非自由依赖项
|
||||
NonFreeNet:
|
||||
description: 此应用推广非自由的网络服务
|
||||
icon: ic_antifeature_nonfreenet.xml
|
||||
name: 非自由网络服务
|
||||
Tracking:
|
||||
description: 此应用会记录并报告你的活动
|
||||
icon: ic_antifeature_tracking.xml
|
||||
name: 跟踪用户
|
||||
UpstreamNonFree:
|
||||
description: 上游源代码不是完全自由的
|
||||
icon: ic_antifeature_upstreamnonfree.xml
|
||||
name: 上游代码非自由
|
||||
|
|
@ -132,23 +132,9 @@ class LintTest(unittest.TestCase):
|
|||
app.Description = 'These are some back'
|
||||
|
||||
fields = {
|
||||
'AntiFeatures': {
|
||||
'good': [
|
||||
[
|
||||
'KnownVuln',
|
||||
],
|
||||
['NonFreeNet', 'KnownVuln'],
|
||||
],
|
||||
'bad': [
|
||||
'KnownVuln',
|
||||
'NonFreeNet,KnownVuln',
|
||||
],
|
||||
},
|
||||
'Categories': {
|
||||
'good': [
|
||||
[
|
||||
'Sports & Health',
|
||||
],
|
||||
['Sports & Health'],
|
||||
['Multimedia', 'Graphics'],
|
||||
],
|
||||
'bad': [
|
||||
|
|
@ -328,6 +314,53 @@ class LintTest(unittest.TestCase):
|
|||
self.assertFalse(anywarns)
|
||||
|
||||
|
||||
class LintAntiFeaturesTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.basedir = localmodule / 'tests'
|
||||
os.chdir(self.basedir)
|
||||
fdroidserver.common.config = dict()
|
||||
fdroidserver.lint.load_antiFeatures_config()
|
||||
|
||||
def test_check_antiFeatures_empty(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
self.assertEqual([], list(fdroidserver.lint.check_antiFeatures(app)))
|
||||
|
||||
def test_check_antiFeatures_empty_AntiFeatures(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
app['AntiFeatures'] = []
|
||||
self.assertEqual([], list(fdroidserver.lint.check_antiFeatures(app)))
|
||||
|
||||
def test_check_antiFeatures(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
app['AntiFeatures'] = ['Ads', 'UpstreamNonFree']
|
||||
self.assertEqual([], list(fdroidserver.lint.check_antiFeatures(app)))
|
||||
|
||||
def test_check_antiFeatures_fails_one(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
app['AntiFeatures'] = ['Ad']
|
||||
self.assertEqual(1, len(list(fdroidserver.lint.check_antiFeatures(app))))
|
||||
|
||||
def test_check_antiFeatures_fails_many(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
app['AntiFeatures'] = ['Adss', 'Tracker', 'NoSourceSince', 'FAKE', 'NonFree']
|
||||
self.assertEqual(4, len(list(fdroidserver.lint.check_antiFeatures(app))))
|
||||
|
||||
def test_check_antiFeatures_build_empty(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
app['Builds'] = [{'antifeatures': []}]
|
||||
self.assertEqual([], list(fdroidserver.lint.check_antiFeatures(app)))
|
||||
|
||||
def test_check_antiFeatures_build(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
app['Builds'] = [{'antifeatures': ['Tracking']}]
|
||||
self.assertEqual(0, len(list(fdroidserver.lint.check_antiFeatures(app))))
|
||||
|
||||
def test_check_antiFeatures_build_fail(self):
|
||||
app = fdroidserver.metadata.App()
|
||||
app['Builds'] = [{'antifeatures': ['Ads', 'Tracker']}]
|
||||
self.assertEqual(1, len(list(fdroidserver.lint.check_antiFeatures(app))))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option(
|
||||
|
|
|
|||
|
|
@ -14,8 +14,9 @@ import tempfile
|
|||
import textwrap
|
||||
from collections import OrderedDict
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
from testcommon import TmpCwd
|
||||
from testcommon import TmpCwd, mkdtemp
|
||||
|
||||
localmodule = Path(__file__).resolve().parent.parent
|
||||
print('localmodule: ' + str(localmodule))
|
||||
|
|
@ -40,10 +41,13 @@ class MetadataTest(unittest.TestCase):
|
|||
logging.basicConfig(level=logging.DEBUG)
|
||||
self.basedir = localmodule / 'tests'
|
||||
os.chdir(self.basedir)
|
||||
self._td = mkdtemp()
|
||||
self.testdir = self._td.name
|
||||
fdroidserver.metadata.warnings_action = 'error'
|
||||
|
||||
def tearDown(self):
|
||||
# auto-generated dirs by functions, not tests, so they are not always cleaned up
|
||||
self._td.cleanup()
|
||||
try:
|
||||
os.rmdir("srclibs")
|
||||
except OSError:
|
||||
|
|
@ -178,26 +182,6 @@ class MetadataTest(unittest.TestCase):
|
|||
'fake.app.id',
|
||||
)
|
||||
|
||||
def test_check_metadata_AntiFeatures(self):
|
||||
fdroidserver.metadata.warnings_action = 'error'
|
||||
|
||||
app = fdroidserver.metadata.App()
|
||||
self.assertIsNone(metadata.check_metadata(app))
|
||||
|
||||
app['AntiFeatures'] = []
|
||||
self.assertIsNone(metadata.check_metadata(app))
|
||||
|
||||
app['AntiFeatures'] = ['Ads', 'UpstreamNonFree']
|
||||
self.assertIsNone(metadata.check_metadata(app))
|
||||
|
||||
app['AntiFeatures'] = ['Ad']
|
||||
with self.assertRaises(fdroidserver.exception.MetaDataException):
|
||||
metadata.check_metadata(app)
|
||||
|
||||
app['AntiFeatures'] = ['Adss']
|
||||
with self.assertRaises(fdroidserver.exception.MetaDataException):
|
||||
metadata.check_metadata(app)
|
||||
|
||||
def test_valid_funding_yml_regex(self):
|
||||
"""Check the regex can find all the cases"""
|
||||
with (self.basedir / 'funding-usernames.yaml').open() as fp:
|
||||
|
|
@ -218,8 +202,10 @@ class MetadataTest(unittest.TestCase):
|
|||
m, 'this is a valid %s username: {%s}' % (k, entry)
|
||||
)
|
||||
|
||||
def test_read_metadata(self):
|
||||
@mock.patch('git.Repo')
|
||||
def test_read_metadata(self, git_repo):
|
||||
"""Read specified metadata files included in tests/, compare to stored output"""
|
||||
|
||||
self.maxDiff = None
|
||||
|
||||
config = dict()
|
||||
|
|
@ -248,7 +234,27 @@ class MetadataTest(unittest.TestCase):
|
|||
# yaml.register_class(metadata.Build)
|
||||
# yaml.dump(frommeta, fp)
|
||||
|
||||
def test_rewrite_yaml_fakeotaupdate(self):
|
||||
@mock.patch('git.Repo')
|
||||
def test_metadata_overrides_dot_fdroid_yml(self, git_Repo):
|
||||
"""Fields in metadata files should override anything in .fdroid.yml."""
|
||||
app = metadata.parse_metadata('metadata/info.guardianproject.urzip.yml')
|
||||
self.assertEqual(app['Summary'], '一个实用工具,获取已安装在您的设备上的应用的有关信息')
|
||||
|
||||
def test_dot_fdroid_yml_works_without_git(self):
|
||||
"""Parsing should work if .fdroid.yml is present and it is not a git repo."""
|
||||
os.chdir(self.testdir)
|
||||
yml = Path('metadata/test.yml')
|
||||
yml.parent.mkdir()
|
||||
with yml.open('w') as fp:
|
||||
fp.write('Repo: https://example.com/not/git/or/anything')
|
||||
fdroid_yml = Path('build/test/.fdroid.yml')
|
||||
fdroid_yml.parent.mkdir(parents=True)
|
||||
with fdroid_yml.open('w') as fp:
|
||||
fp.write('OpenCollective: test')
|
||||
metadata.parse_metadata(yml) # should not throw an exception
|
||||
|
||||
@mock.patch('git.Repo')
|
||||
def test_rewrite_yaml_fakeotaupdate(self, git_Repo):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
testdir = Path(testdir)
|
||||
fdroidserver.common.config = {'accepted_formats': ['yml']}
|
||||
|
|
@ -270,7 +276,8 @@ class MetadataTest(unittest.TestCase):
|
|||
(Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
|
||||
)
|
||||
|
||||
def test_rewrite_yaml_fdroidclient(self):
|
||||
@mock.patch('git.Repo')
|
||||
def test_rewrite_yaml_fdroidclient(self, git_Repo):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
testdir = Path(testdir)
|
||||
fdroidserver.common.config = {'accepted_formats': ['yml']}
|
||||
|
|
@ -291,7 +298,8 @@ class MetadataTest(unittest.TestCase):
|
|||
(Path('metadata-rewrite-yml') / file_name).read_text(encoding='utf-8'),
|
||||
)
|
||||
|
||||
def test_rewrite_yaml_special_build_params(self):
|
||||
@mock.patch('git.Repo')
|
||||
def test_rewrite_yaml_special_build_params(self, git_Repo):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
testdir = Path(testdir)
|
||||
|
||||
|
|
@ -450,7 +458,6 @@ class MetadataTest(unittest.TestCase):
|
|||
with self.assertRaises(TypeError):
|
||||
metadata.parse_yaml_metadata(mf)
|
||||
|
||||
mf.name = 'mock_filename.yaml'
|
||||
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
||||
|
||||
def test_parse_yaml_metadata_unknown_app_field(self):
|
||||
|
|
@ -481,7 +488,9 @@ class MetadataTest(unittest.TestCase):
|
|||
with self.assertRaises(MetaDataException):
|
||||
fdroidserver.metadata.parse_yaml_metadata(mf)
|
||||
|
||||
def test_parse_yaml_metadata_continue_on_warning(self):
|
||||
@mock.patch('logging.warning')
|
||||
@mock.patch('logging.error')
|
||||
def test_parse_yaml_metadata_continue_on_warning(self, _error, _warning):
|
||||
"""When errors are disabled, parsing should provide something that can work.
|
||||
|
||||
When errors are disabled, then it should try to give data that
|
||||
|
|
@ -495,6 +504,8 @@ class MetadataTest(unittest.TestCase):
|
|||
fdroidserver.metadata.warnings_action = None
|
||||
mf = _get_mock_mf('[AntiFeatures: Tracking]')
|
||||
self.assertEqual(fdroidserver.metadata.parse_yaml_metadata(mf), dict())
|
||||
_warning.assert_called_once()
|
||||
_error.assert_called_once()
|
||||
|
||||
def test_parse_yaml_srclib_corrupt_file(self):
|
||||
with tempfile.TemporaryDirectory() as testdir:
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
"version": 20002,
|
||||
"index": {
|
||||
"name": "/index-v2.json",
|
||||
"sha256": "07fa4500736ae77fcc6434e4d70ab315b8e018aef52c2afca9f2834ddc73747d",
|
||||
"size": 32946,
|
||||
"sha256": "a3c7e88a522a7228937e5c3d760fc239e3578e292035d88478d32fec9ff5eb54",
|
||||
"size": 52314,
|
||||
"numPackages": 10
|
||||
},
|
||||
"diffs": {}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,477 @@
|
|||
}
|
||||
],
|
||||
"timestamp": 1676634233000,
|
||||
"antiFeatures": {
|
||||
"Ads": {
|
||||
"description": {
|
||||
"de": "Diese App enthält Werbung",
|
||||
"en-US": "This app contains advertising",
|
||||
"fa": "این کاره دارای تبلیغات است",
|
||||
"ro": "Aplicația conține reclamă",
|
||||
"zh-rCN": "此应用包含广告"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_ads.xml",
|
||||
"sha256": "b333528573134c5de73484862a1b567a0bdfd6878d183f8500287abadc0ba60e",
|
||||
"size": 1564
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_ads.xml",
|
||||
"sha256": "b333528573134c5de73484862a1b567a0bdfd6878d183f8500287abadc0ba60e",
|
||||
"size": 1564
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_ads.xml",
|
||||
"sha256": "b333528573134c5de73484862a1b567a0bdfd6878d183f8500287abadc0ba60e",
|
||||
"size": 1564
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_ads.xml",
|
||||
"sha256": "b333528573134c5de73484862a1b567a0bdfd6878d183f8500287abadc0ba60e",
|
||||
"size": 1564
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_ads.xml",
|
||||
"sha256": "b333528573134c5de73484862a1b567a0bdfd6878d183f8500287abadc0ba60e",
|
||||
"size": 1564
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Werbung",
|
||||
"en-US": "Ads",
|
||||
"fa": "تبلیغات",
|
||||
"ro": "Reclame",
|
||||
"zh-rCN": "广告"
|
||||
}
|
||||
},
|
||||
"DisabledAlgorithm": {
|
||||
"description": {
|
||||
"de": "Diese App hat eine schwache Sicherheitssignatur",
|
||||
"en-US": "This app has a weak security signature",
|
||||
"fa": "این کاره، امضای امنیتی ضعیفی دارد",
|
||||
"ro": "Aplicația are o semnătură slab securizată",
|
||||
"zh-rCN": "此应用的安全签名较弱"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_disabledalgorithm.xml",
|
||||
"sha256": "94dea590c7c0aa37d351ab62a69fc7eefbc2cdbb84b79df3934c2e9332e1dcfb",
|
||||
"size": 2313
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_disabledalgorithm.xml",
|
||||
"sha256": "94dea590c7c0aa37d351ab62a69fc7eefbc2cdbb84b79df3934c2e9332e1dcfb",
|
||||
"size": 2313
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_disabledalgorithm.xml",
|
||||
"sha256": "94dea590c7c0aa37d351ab62a69fc7eefbc2cdbb84b79df3934c2e9332e1dcfb",
|
||||
"size": 2313
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_disabledalgorithm.xml",
|
||||
"sha256": "94dea590c7c0aa37d351ab62a69fc7eefbc2cdbb84b79df3934c2e9332e1dcfb",
|
||||
"size": 2313
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_disabledalgorithm.xml",
|
||||
"sha256": "94dea590c7c0aa37d351ab62a69fc7eefbc2cdbb84b79df3934c2e9332e1dcfb",
|
||||
"size": 2313
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Mit einem unsicheren Algorithmus signiert",
|
||||
"en-US": "Signed Using An Unsafe Algorithm",
|
||||
"fa": "امضا شده با الگوریتمی ناامن",
|
||||
"ro": "Algoritm nesigur semnătură",
|
||||
"zh-rCN": "使用不安全算法签名"
|
||||
}
|
||||
},
|
||||
"KnownVuln": {
|
||||
"description": {
|
||||
"de": "Diese App enthält eine bekannte Sicherheitslücke",
|
||||
"en-US": "This app contains a known security vulnerability",
|
||||
"fa": "این کاره، آسیبپذیری امنیتی شناختهشدهای دارد",
|
||||
"ro": "Aplicația conține o vulnerabilitate de securitate cunoscută",
|
||||
"zh-rCN": "此应用包含已知的安全漏洞"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_knownvuln.xml",
|
||||
"sha256": "743ddcad0120896b03bf62bca9b3b9902878ac9366959a0b77b2c50beeb37f9d",
|
||||
"size": 1415
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_knownvuln.xml",
|
||||
"sha256": "743ddcad0120896b03bf62bca9b3b9902878ac9366959a0b77b2c50beeb37f9d",
|
||||
"size": 1415
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_knownvuln.xml",
|
||||
"sha256": "743ddcad0120896b03bf62bca9b3b9902878ac9366959a0b77b2c50beeb37f9d",
|
||||
"size": 1415
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_knownvuln.xml",
|
||||
"sha256": "743ddcad0120896b03bf62bca9b3b9902878ac9366959a0b77b2c50beeb37f9d",
|
||||
"size": 1415
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_knownvuln.xml",
|
||||
"sha256": "743ddcad0120896b03bf62bca9b3b9902878ac9366959a0b77b2c50beeb37f9d",
|
||||
"size": 1415
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Bekannte Sicherheitslücke",
|
||||
"en-US": "Known Vulnerability",
|
||||
"fa": "آسیبپذیری شناخته",
|
||||
"ro": "Vulnerabilitate cunoscută",
|
||||
"zh-rCN": "含有已知漏洞"
|
||||
}
|
||||
},
|
||||
"NSFW": {
|
||||
"description": {
|
||||
"de": "Diese App enthält Inhalte, die nicht überall veröffentlicht oder sichtbar sein sollten",
|
||||
"en-US": "This app contains content that should not be publicized or visible everywhere",
|
||||
"fa": "این کاره محتوایی دارد که نباید عمومی شده یا همهحا نمایان باشد",
|
||||
"ro": "Această aplicație conține conținut care nu ar trebui să fie făcut public sau vizibil peste tot",
|
||||
"zh-rCN": "此应用包含不应宣扬或随处可见的内容"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_nsfw.xml",
|
||||
"sha256": "acab2a7a846700529cd7f2b7a7980f7d04a291f22db8434f3e966f7350ed1465",
|
||||
"size": 871
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_nsfw.xml",
|
||||
"sha256": "acab2a7a846700529cd7f2b7a7980f7d04a291f22db8434f3e966f7350ed1465",
|
||||
"size": 871
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_nsfw.xml",
|
||||
"sha256": "acab2a7a846700529cd7f2b7a7980f7d04a291f22db8434f3e966f7350ed1465",
|
||||
"size": 871
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_nsfw.xml",
|
||||
"sha256": "acab2a7a846700529cd7f2b7a7980f7d04a291f22db8434f3e966f7350ed1465",
|
||||
"size": 871
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_nsfw.xml",
|
||||
"sha256": "acab2a7a846700529cd7f2b7a7980f7d04a291f22db8434f3e966f7350ed1465",
|
||||
"size": 871
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "NSFW",
|
||||
"en-US": "NSFW",
|
||||
"fa": "NSFW",
|
||||
"ro": "NSFW",
|
||||
"zh-rCN": "NSFW"
|
||||
}
|
||||
},
|
||||
"NoSourceSince": {
|
||||
"description": {
|
||||
"en-US": "The source code is no longer available, no updates possible."
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_nosourcesince.xml",
|
||||
"sha256": "69c880b075967fe9598c777e18d600e1c1612bf061111911421fe8f6b9d88d4f",
|
||||
"size": 1102
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_nosourcesince.xml",
|
||||
"sha256": "69c880b075967fe9598c777e18d600e1c1612bf061111911421fe8f6b9d88d4f",
|
||||
"size": 1102
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_nosourcesince.xml",
|
||||
"sha256": "69c880b075967fe9598c777e18d600e1c1612bf061111911421fe8f6b9d88d4f",
|
||||
"size": 1102
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_nosourcesince.xml",
|
||||
"sha256": "69c880b075967fe9598c777e18d600e1c1612bf061111911421fe8f6b9d88d4f",
|
||||
"size": 1102
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_nosourcesince.xml",
|
||||
"sha256": "69c880b075967fe9598c777e18d600e1c1612bf061111911421fe8f6b9d88d4f",
|
||||
"size": 1102
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Der Quellcode ist nicht mehr erhältlich, keine Aktualisierungen möglich.",
|
||||
"en-US": "Newer Source Not Available",
|
||||
"fa": "کد مبدأ دیگر در دسترس نیست. بهروز رسانی ناممکن است.",
|
||||
"ro": "Codul sursă nu mai este disponibil, nu mai există posibilitatea de a actualiza.",
|
||||
"zh-rCN": "源代码不再可用,无法更新。"
|
||||
}
|
||||
},
|
||||
"NonFreeAdd": {
|
||||
"description": {
|
||||
"de": "Diese App bewirbt nicht-quelloffene Erweiterungen",
|
||||
"en-US": "This app promotes non-free add-ons",
|
||||
"fa": "این کاره، افزونههای ناآزاد را تبلیغ میکند",
|
||||
"ro": "Aplicația promovează anexe ce nu sunt software liber",
|
||||
"zh-rCN": "此应用推广非自由的附加组件"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_nonfreeadd.xml",
|
||||
"sha256": "a1d1f2070bdaabf80ca5a55bccef98c82031ea2f31cc040be5ec009f44ddeef2",
|
||||
"size": 1846
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_nonfreeadd.xml",
|
||||
"sha256": "a1d1f2070bdaabf80ca5a55bccef98c82031ea2f31cc040be5ec009f44ddeef2",
|
||||
"size": 1846
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_nonfreeadd.xml",
|
||||
"sha256": "a1d1f2070bdaabf80ca5a55bccef98c82031ea2f31cc040be5ec009f44ddeef2",
|
||||
"size": 1846
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_nonfreeadd.xml",
|
||||
"sha256": "a1d1f2070bdaabf80ca5a55bccef98c82031ea2f31cc040be5ec009f44ddeef2",
|
||||
"size": 1846
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_nonfreeadd.xml",
|
||||
"sha256": "a1d1f2070bdaabf80ca5a55bccef98c82031ea2f31cc040be5ec009f44ddeef2",
|
||||
"size": 1846
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Nicht-quelloffene Erweiterungen",
|
||||
"en-US": "Non-Free Addons",
|
||||
"fa": "افزونههای ناآزاد",
|
||||
"ro": "Anexe ne-libere",
|
||||
"zh-rCN": "非自由附加组件"
|
||||
}
|
||||
},
|
||||
"NonFreeAssets": {
|
||||
"description": {
|
||||
"de": "Diese App enthält nicht-quelloffene Bestandteile",
|
||||
"en-US": "This app contains non-free assets",
|
||||
"fa": "این کاره دارای بخشهای ناآزاد است",
|
||||
"ro": "Aceasta aplicație conține resurse ce nu sunt la disponibile la liber",
|
||||
"zh-rCN": "此应用包含非自由资源"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_nonfreeassets.xml",
|
||||
"sha256": "b39fe384386fc67fb30fa2f91402594110e2e42c961d76adc93141b8bd774008",
|
||||
"size": 1784
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_nonfreeassets.xml",
|
||||
"sha256": "b39fe384386fc67fb30fa2f91402594110e2e42c961d76adc93141b8bd774008",
|
||||
"size": 1784
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_nonfreeassets.xml",
|
||||
"sha256": "b39fe384386fc67fb30fa2f91402594110e2e42c961d76adc93141b8bd774008",
|
||||
"size": 1784
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_nonfreeassets.xml",
|
||||
"sha256": "b39fe384386fc67fb30fa2f91402594110e2e42c961d76adc93141b8bd774008",
|
||||
"size": 1784
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_nonfreeassets.xml",
|
||||
"sha256": "b39fe384386fc67fb30fa2f91402594110e2e42c961d76adc93141b8bd774008",
|
||||
"size": 1784
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Nicht-quelloffene Bestandteile",
|
||||
"en-US": "Non-Free Assets",
|
||||
"fa": "بخشهای ناآزاد",
|
||||
"ro": "Resurse ne-libere",
|
||||
"zh-rCN": "非自由资产"
|
||||
}
|
||||
},
|
||||
"NonFreeDep": {
|
||||
"description": {
|
||||
"de": "Diese App ist abhängig von anderen nicht-quelloffenen Apps",
|
||||
"en-US": "This app depends on other non-free apps",
|
||||
"fa": "این کاره به دیگر کارههای ناآزاد وابسته است",
|
||||
"ro": "Aplicația depinde de alte aplicații ce nu sunt software liber",
|
||||
"zh-rCN": "此应用依赖于其它非自由应用"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_nonfreedep.xml",
|
||||
"sha256": "c1b4052a8f58125b2120d9ca07adb725d47bfa7cfcea80c4d6bbbc432b5cb83a",
|
||||
"size": 1396
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_nonfreedep.xml",
|
||||
"sha256": "c1b4052a8f58125b2120d9ca07adb725d47bfa7cfcea80c4d6bbbc432b5cb83a",
|
||||
"size": 1396
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_nonfreedep.xml",
|
||||
"sha256": "c1b4052a8f58125b2120d9ca07adb725d47bfa7cfcea80c4d6bbbc432b5cb83a",
|
||||
"size": 1396
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_nonfreedep.xml",
|
||||
"sha256": "c1b4052a8f58125b2120d9ca07adb725d47bfa7cfcea80c4d6bbbc432b5cb83a",
|
||||
"size": 1396
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_nonfreedep.xml",
|
||||
"sha256": "c1b4052a8f58125b2120d9ca07adb725d47bfa7cfcea80c4d6bbbc432b5cb83a",
|
||||
"size": 1396
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Nicht-quelloffene Abhängigkeiten",
|
||||
"en-US": "Non-Free Dependencies",
|
||||
"fa": "وابستگیهای ناآزاد",
|
||||
"ro": "Dependențe ne-libere",
|
||||
"zh-rCN": "非自由依赖项"
|
||||
}
|
||||
},
|
||||
"NonFreeNet": {
|
||||
"description": {
|
||||
"de": "Diese App bewirbt nicht-quelloffene Netzwerkdienste",
|
||||
"en-US": "This app promotes or depends entirely on a non-free network service",
|
||||
"fa": "این کاره، خدمات شبکههای ناآزاد را ترویج میکند",
|
||||
"ro": "Aplicația promovează servicii de rețea ce nu sunt accesibile la liber",
|
||||
"zh-rCN": "此应用推广非自由的网络服务"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_nonfreenet.xml",
|
||||
"sha256": "7fff45c847ed2ecc94e85ba2341685c8f113fa5fdf7267a25637dc38ee0275f6",
|
||||
"size": 3038
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_nonfreenet.xml",
|
||||
"sha256": "7fff45c847ed2ecc94e85ba2341685c8f113fa5fdf7267a25637dc38ee0275f6",
|
||||
"size": 3038
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_nonfreenet.xml",
|
||||
"sha256": "7fff45c847ed2ecc94e85ba2341685c8f113fa5fdf7267a25637dc38ee0275f6",
|
||||
"size": 3038
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_nonfreenet.xml",
|
||||
"sha256": "7fff45c847ed2ecc94e85ba2341685c8f113fa5fdf7267a25637dc38ee0275f6",
|
||||
"size": 3038
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_nonfreenet.xml",
|
||||
"sha256": "7fff45c847ed2ecc94e85ba2341685c8f113fa5fdf7267a25637dc38ee0275f6",
|
||||
"size": 3038
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Nicht-quelloffene Netzwerkdienste",
|
||||
"en-US": "Non-Free Network Services",
|
||||
"fa": "خدمات شبکهای ناآزاد",
|
||||
"ro": "Servicii de rețea ne-libere",
|
||||
"zh-rCN": "非自由网络服务"
|
||||
}
|
||||
},
|
||||
"Tracking": {
|
||||
"description": {
|
||||
"de": "Diese App verfolgt und versendet Ihre Aktivitäten",
|
||||
"en-US": "This app tracks and reports your activity",
|
||||
"fa": "این کاره، فعّالیتتان را ردیابی و گزارش میکند",
|
||||
"ro": "Aplicația îți înregistrează și raportează activitatea undeva",
|
||||
"zh-rCN": "此应用会记录并报告你的活动"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_tracking.xml",
|
||||
"sha256": "4779337b5b0a12c4b4a8a83d0d8a994a2477460db702784df4c8d3e3730be961",
|
||||
"size": 2493
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_tracking.xml",
|
||||
"sha256": "4779337b5b0a12c4b4a8a83d0d8a994a2477460db702784df4c8d3e3730be961",
|
||||
"size": 2493
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_tracking.xml",
|
||||
"sha256": "4779337b5b0a12c4b4a8a83d0d8a994a2477460db702784df4c8d3e3730be961",
|
||||
"size": 2493
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_tracking.xml",
|
||||
"sha256": "4779337b5b0a12c4b4a8a83d0d8a994a2477460db702784df4c8d3e3730be961",
|
||||
"size": 2493
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_tracking.xml",
|
||||
"sha256": "4779337b5b0a12c4b4a8a83d0d8a994a2477460db702784df4c8d3e3730be961",
|
||||
"size": 2493
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Tracking",
|
||||
"en-US": "Tracking",
|
||||
"fa": "ردیابی",
|
||||
"ro": "Urmărire",
|
||||
"zh-rCN": "跟踪用户"
|
||||
}
|
||||
},
|
||||
"UpstreamNonFree": {
|
||||
"description": {
|
||||
"de": "Der Originalcode ist nicht völlig quelloffen",
|
||||
"en-US": "The upstream source code is not entirely Free",
|
||||
"fa": "کد مبدأ بالادستی کاملاً آزاد نیست",
|
||||
"ro": "Codul sursa originar nu este în totalitatea lui software liber",
|
||||
"zh-rCN": "上游源代码不是完全自由的"
|
||||
},
|
||||
"icon": {
|
||||
"de": {
|
||||
"name": "/icons/ic_antifeature_upstreamnonfree.xml",
|
||||
"sha256": "06a9af843ff56ecd7a270f98c0b19b3154edf3ffa854e6d50a84ef00d0ce1a86",
|
||||
"size": 1442
|
||||
},
|
||||
"en-US": {
|
||||
"name": "/icons/ic_antifeature_upstreamnonfree.xml",
|
||||
"sha256": "06a9af843ff56ecd7a270f98c0b19b3154edf3ffa854e6d50a84ef00d0ce1a86",
|
||||
"size": 1442
|
||||
},
|
||||
"fa": {
|
||||
"name": "/icons/ic_antifeature_upstreamnonfree.xml",
|
||||
"sha256": "06a9af843ff56ecd7a270f98c0b19b3154edf3ffa854e6d50a84ef00d0ce1a86",
|
||||
"size": 1442
|
||||
},
|
||||
"ro": {
|
||||
"name": "/icons/ic_antifeature_upstreamnonfree.xml",
|
||||
"sha256": "06a9af843ff56ecd7a270f98c0b19b3154edf3ffa854e6d50a84ef00d0ce1a86",
|
||||
"size": 1442
|
||||
},
|
||||
"zh-rCN": {
|
||||
"name": "/icons/ic_antifeature_upstreamnonfree.xml",
|
||||
"sha256": "06a9af843ff56ecd7a270f98c0b19b3154edf3ffa854e6d50a84ef00d0ce1a86",
|
||||
"size": 1442
|
||||
}
|
||||
},
|
||||
"name": {
|
||||
"de": "Originalcode nicht-quelloffen",
|
||||
"en-US": "Upstream Non-Free",
|
||||
"fa": "بالادست ناآزاد",
|
||||
"ro": "Surse ne-libere",
|
||||
"zh-rCN": "上游代码非自由"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests": {
|
||||
"install": [
|
||||
"org.adaway"
|
||||
|
|
|
|||
|
|
@ -9,15 +9,14 @@ import tempfile
|
|||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
from testcommon import TmpCwd
|
||||
from testcommon import TmpCwd, mkdtemp
|
||||
|
||||
localmodule = Path(__file__).resolve().parent.parent
|
||||
print('localmodule: ' + str(localmodule))
|
||||
if localmodule not in sys.path:
|
||||
sys.path.insert(0, str(localmodule))
|
||||
|
||||
from fdroidserver import common
|
||||
from fdroidserver import rewritemeta
|
||||
from fdroidserver import common, metadata, rewritemeta
|
||||
|
||||
|
||||
class RewriteMetaTest(unittest.TestCase):
|
||||
|
|
@ -27,6 +26,123 @@ class RewriteMetaTest(unittest.TestCase):
|
|||
logging.basicConfig(level=logging.DEBUG)
|
||||
self.basedir = localmodule / 'tests'
|
||||
os.chdir(self.basedir)
|
||||
metadata.warnings_action = 'error'
|
||||
self._td = mkdtemp()
|
||||
self.testdir = self._td.name
|
||||
|
||||
def tearDown(self):
|
||||
self._td.cleanup()
|
||||
|
||||
def test_remove_blank_flags_from_builds_com_politedroid_3(self):
|
||||
"""Unset fields in Builds: entries should be removed."""
|
||||
appid = 'com.politedroid'
|
||||
app = metadata.read_metadata({appid: -1})[appid]
|
||||
builds = rewritemeta.remove_blank_flags_from_builds(app.get('Builds'))
|
||||
self.assertEqual(
|
||||
builds[0],
|
||||
{
|
||||
'versionName': '1.2',
|
||||
'versionCode': 3,
|
||||
'commit': '6a548e4b19',
|
||||
'target': 'android-10',
|
||||
'antifeatures': [
|
||||
'KnownVuln',
|
||||
'UpstreamNonFree',
|
||||
'NonFreeAssets',
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
def test_remove_blank_flags_from_builds_com_politedroid_4(self):
|
||||
"""Unset fields in Builds: entries should be removed."""
|
||||
appid = 'com.politedroid'
|
||||
app = metadata.read_metadata({appid: -1})[appid]
|
||||
builds = rewritemeta.remove_blank_flags_from_builds(app.get('Builds'))
|
||||
self.assertEqual(
|
||||
builds[1],
|
||||
{
|
||||
'versionName': '1.3',
|
||||
'versionCode': 4,
|
||||
'commit': 'ad865b57bf3ac59580f38485608a9b1dda4fa7dc',
|
||||
'target': 'android-15',
|
||||
},
|
||||
)
|
||||
|
||||
def test_remove_blank_flags_from_builds_no_builds(self):
|
||||
"""Unset fields in Builds: entries should be removed."""
|
||||
self.assertEqual(
|
||||
rewritemeta.remove_blank_flags_from_builds(None),
|
||||
list(),
|
||||
)
|
||||
self.assertEqual(
|
||||
rewritemeta.remove_blank_flags_from_builds(dict()),
|
||||
list(),
|
||||
)
|
||||
|
||||
def test_rewrite_no_builds(self):
|
||||
os.chdir(self.testdir)
|
||||
Path('metadata').mkdir()
|
||||
with Path('metadata/a.yml').open('w') as f:
|
||||
f.write('AutoName: a')
|
||||
rewritemeta.main()
|
||||
self.assertEqual(
|
||||
Path('metadata/a.yml').read_text(encoding='utf-8'),
|
||||
textwrap.dedent(
|
||||
'''\
|
||||
License: Unknown
|
||||
|
||||
AutoName: a
|
||||
|
||||
AutoUpdateMode: None
|
||||
UpdateCheckMode: None
|
||||
'''
|
||||
),
|
||||
)
|
||||
|
||||
def test_rewrite_empty_build_field(self):
|
||||
os.chdir(self.testdir)
|
||||
Path('metadata').mkdir()
|
||||
with Path('metadata/a.yml').open('w') as fp:
|
||||
fp.write(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
License: Apache-2.0
|
||||
Builds:
|
||||
- versionCode: 4
|
||||
versionName: a
|
||||
rm:
|
||||
"""
|
||||
)
|
||||
)
|
||||
rewritemeta.main()
|
||||
self.assertEqual(
|
||||
Path('metadata/a.yml').read_text(encoding='utf-8'),
|
||||
textwrap.dedent(
|
||||
'''\
|
||||
License: Apache-2.0
|
||||
|
||||
Builds:
|
||||
- versionName: a
|
||||
versionCode: 4
|
||||
|
||||
AutoUpdateMode: None
|
||||
UpdateCheckMode: None
|
||||
'''
|
||||
),
|
||||
)
|
||||
|
||||
def test_remove_blank_flags_from_builds_app_with_special_build_params(self):
|
||||
appid = 'app.with.special.build.params'
|
||||
app = metadata.read_metadata({appid: -1})[appid]
|
||||
builds = rewritemeta.remove_blank_flags_from_builds(app.get('Builds'))
|
||||
self.assertEqual(
|
||||
builds[-1],
|
||||
{
|
||||
'versionName': '2.1.2',
|
||||
'versionCode': 51,
|
||||
'disable': 'Labelled as pre-release, so skipped',
|
||||
},
|
||||
)
|
||||
|
||||
def test_rewrite_scenario_trivial(self):
|
||||
sys.argv = ['rewritemeta', 'a', 'b']
|
||||
|
|
|
|||
|
|
@ -213,16 +213,6 @@ if use_apksigner; then
|
|||
fi
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------#
|
||||
echo_header "TODO remove once buildserver image is upgraded to bullseye with apksigner"
|
||||
|
||||
if java -version 2>&1 | grep -F 1.8.0; then
|
||||
echo "Skipping the rest because they require apksigner 30.0.0+ which does not run on Java8"
|
||||
echo SUCCESS
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
#------------------------------------------------------------------------------#
|
||||
echo_header "test UTF-8 metadata"
|
||||
|
||||
|
|
@ -271,7 +261,12 @@ REPOROOT=`create_test_dir`
|
|||
GNUPGHOME=$REPOROOT/gnupghome
|
||||
cd $REPOROOT
|
||||
fdroid_init_with_prebuilt_keystore
|
||||
cp -a $WORKSPACE/tests/metadata $WORKSPACE/tests/repo $WORKSPACE/tests/stats $REPOROOT/
|
||||
cp -a \
|
||||
$WORKSPACE/tests/config \
|
||||
$WORKSPACE/tests/metadata \
|
||||
$WORKSPACE/tests/repo \
|
||||
$WORKSPACE/tests/stats \
|
||||
$REPOROOT/
|
||||
cp -a $WORKSPACE/tests/gnupghome $GNUPGHOME
|
||||
chmod 0700 $GNUPGHOME
|
||||
echo "install_list: org.adaway" >> config.yml
|
||||
|
|
@ -1139,7 +1134,7 @@ echo_header "setup a new repo from scratch using ANDROID_HOME with git mirror"
|
|||
# fake git remote server for repo mirror
|
||||
SERVER_GIT_MIRROR=`create_test_dir`
|
||||
cd $SERVER_GIT_MIRROR
|
||||
$git init
|
||||
$git init --initial-branch=master
|
||||
$git config receive.denyCurrentBranch updateInstead
|
||||
|
||||
REPOROOT=`create_test_dir`
|
||||
|
|
@ -1201,7 +1196,7 @@ SERVERWEBROOT=`create_test_dir`/fdroid
|
|||
cd $OFFLINE_ROOT
|
||||
mkdir binary_transparency
|
||||
cd binary_transparency
|
||||
$git init
|
||||
$git init --initial-branch=master
|
||||
|
||||
# fake git remote server for binary transparency log
|
||||
BINARY_TRANSPARENCY_REMOTE=`create_test_dir`
|
||||
|
|
@ -1209,7 +1204,7 @@ BINARY_TRANSPARENCY_REMOTE=`create_test_dir`
|
|||
# fake git remote server for repo mirror
|
||||
SERVER_GIT_MIRROR=`create_test_dir`
|
||||
cd $SERVER_GIT_MIRROR
|
||||
$git init
|
||||
$git init --initial-branch=master
|
||||
$git config receive.denyCurrentBranch updateInstead
|
||||
|
||||
cd $OFFLINE_ROOT
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue