Prevent API from changing protected tags

Fixes #322
This commit is contained in:
rubenwardy 2021-07-24 00:43:55 +01:00
parent 3049d17f5e
commit 823c06d3ea
4 changed files with 18 additions and 9 deletions

@ -100,7 +100,7 @@ def api_edit_package(token: APIToken, package: Package, data: dict, reason: str
reason += ", token=" + token.name reason += ", token=" + token.name
package = guard(do_edit_package)(token.owner, package, False, data, reason) package = guard(do_edit_package)(token.owner, package, False, False, data, reason)
return jsonify({ return jsonify({
"success": True, "success": True,

@ -302,7 +302,7 @@ def create_edit(author=None, name=None):
wasNew = True wasNew = True
try: try:
do_edit_package(current_user, package, wasNew, { do_edit_package(current_user, package, wasNew, True, {
"type": form.type.data, "type": form.type.data,
"title": form.title.data, "title": form.title.data,
"name": form.name.data, "name": form.name.data,

@ -40,17 +40,17 @@ def get_license(name):
name_re = re.compile("^[a-z0-9_]+$") name_re = re.compile("^[a-z0-9_]+$")
any = "?" AnyType = "?"
ALLOWED_FIELDS = { ALLOWED_FIELDS = {
"type": any, "type": AnyType,
"title": str, "title": str,
"name": str, "name": str,
"short_description": str, "short_description": str,
"short_desc": str, "short_desc": str,
"tags": list, "tags": list,
"content_warnings": list, "content_warnings": list,
"license": any, "license": AnyType,
"media_license": any, "media_license": AnyType,
"long_description": str, "long_description": str,
"desc": str, "desc": str,
"repo": str, "repo": str,
@ -80,7 +80,7 @@ def validate(data: dict):
if value is not None: if value is not None:
typ = ALLOWED_FIELDS.get(key) typ = ALLOWED_FIELDS.get(key)
check(typ is not None, key + " is not a known field") check(typ is not None, key + " is not a known field")
if typ != any: if typ != AnyType:
check(isinstance(value, typ), key + " must be a " + typ.__name__) check(isinstance(value, typ), key + " must be a " + typ.__name__)
if "name" in data: if "name" in data:
@ -98,7 +98,8 @@ def validate(data: dict):
check(validators.url(value, public=True), key + " must be a valid URL") check(validators.url(value, public=True), key + " must be a valid URL")
def do_edit_package(user: User, package: Package, was_new: bool, data: dict, reason: str = None): def do_edit_package(user: User, package: Package, was_new: bool, was_web: bool, data: dict,
reason: str = None):
if not package.checkPerm(user, Permission.EDIT_PACKAGE): if not package.checkPerm(user, Permission.EDIT_PACKAGE):
raise LogicError(403, "You do not have permission to edit this package") raise LogicError(403, "You do not have permission to edit this package")
@ -144,11 +145,19 @@ def do_edit_package(user: User, package: Package, was_new: bool, data: dict, rea
if tag is None: if tag is None:
raise LogicError(400, "Unknown tag: " + tag_id) raise LogicError(400, "Unknown tag: " + tag_id)
if not was_web and tag.is_protected:
break
if tag.is_protected and tag not in old_tags and not user.rank.atLeast(UserRank.EDITOR): if tag.is_protected and tag not in old_tags and not user.rank.atLeast(UserRank.EDITOR):
raise LogicError(400, f"Unable to add protected tag {tag.title} to package") raise LogicError(400, f"Unable to add protected tag {tag.title} to package")
package.tags.append(tag) package.tags.append(tag)
if not was_web:
for tag in old_tags:
if tag.is_protected:
package.tags.append(tag)
if "content_warnings" in data: if "content_warnings" in data:
package.content_warnings.clear() package.content_warnings.clear()
for warning_id in data["content_warnings"]: for warning_id in data["content_warnings"]:

@ -119,7 +119,7 @@ def postReleaseCheckUpdate(self, release: PackageRelease, path):
try: try:
with open(os.path.join(tree.baseDir, ".cdb.json"), "r") as f: with open(os.path.join(tree.baseDir, ".cdb.json"), "r") as f:
data = json.loads(f.read()) data = json.loads(f.read())
do_edit_package(package.author, package, False, data, "Post release hook") do_edit_package(package.author, package, False, False, data, "Post release hook")
except LogicError as e: except LogicError as e:
raise TaskError(e.message) raise TaskError(e.message)
except IOError: except IOError: