Verify raise exception instead of return False

This commit is contained in:
shortcutme 2017-06-19 15:47:03 +02:00
parent fec3ff7d8e
commit 2a3b8a7692
No known key found for this signature in database
GPG key ID: 5B63BAE6CB9613AE

View file

@ -15,6 +15,10 @@ from Peer import PeerHashfield
from ContentDbDict import ContentDbDict from ContentDbDict import ContentDbDict
class VerifyError(Exception):
pass
class ContentManager(object): class ContentManager(object):
def __init__(self, site): def __init__(self, site):
@ -611,9 +615,7 @@ class ContentManager(object):
new_content["signs"] = {} new_content["signs"] = {}
new_content["signs"][privatekey_address] = sign new_content["signs"][privatekey_address] = sign
if not self.verifyContent(inner_path, new_content): self.verifyContent(inner_path, new_content)
self.log.error("Sign failed: Invalid content")
return False
if filewrite: if filewrite:
self.log.info("Saving to %s..." % inner_path) self.log.info("Saving to %s..." % inner_path)
@ -655,18 +657,19 @@ class ContentManager(object):
if not rules.get("cert_signers"): if not rules.get("cert_signers"):
return True # Does not need cert return True # Does not need cert
if not "cert_user_id" in content:
raise VerifyError("Missing cert_user_id")
name, domain = content["cert_user_id"].split("@") name, domain = content["cert_user_id"].split("@")
cert_address = rules["cert_signers"].get(domain) cert_address = rules["cert_signers"].get(domain)
if not cert_address: # Cert signer not allowed if not cert_address: # Cert signer not allowed
self.log.warning("Invalid cert signer: %s" % domain) raise VerifyError("Invalid cert signer: %s" % domain)
return False
try: try:
cert_subject = "%s#%s/%s" % (rules["user_address"], content["cert_auth_type"], name) cert_subject = "%s#%s/%s" % (rules["user_address"], content["cert_auth_type"], name)
result = CryptBitcoin.verify(cert_subject, cert_address, content["cert_sign"]) result = CryptBitcoin.verify(cert_subject, cert_address, content["cert_sign"])
except Exception, err: except Exception, err:
self.log.warning("Certificate verify error: %s" % err) raise VerifyError("Certificate verify error: %s" % err)
result = False
return result return result
# Checks if the content.json content is valid # Checks if the content.json content is valid
@ -690,24 +693,21 @@ class ContentManager(object):
# Check site address # Check site address
if content.get("address") and content["address"] != self.site.address: if content.get("address") and content["address"] != self.site.address:
self.log.warning("%s: Wrong site address: %s != %s" % (inner_path, content["address"], self.site.address)) raise VerifyError("Wrong site address: %s != %s" % (content["address"], self.site.address))
return False
# Check file inner path # Check file inner path
if content.get("inner_path") and content["inner_path"] != inner_path: if content.get("inner_path") and content["inner_path"] != inner_path:
self.log.warning("%s: Wrong inner_path: %s" % (inner_path, content["inner_path"])) raise VerifyError("Wrong inner_path: %s" % content["inner_path"])
return False
# Check total site size limit # Check total site size limit
if site_size > site_size_limit: if site_size > site_size_limit:
self.log.warning("%s: Site too large %s > %s, aborting task..." % (inner_path, site_size, site_size_limit))
if inner_path == "content.json" and self.site.settings["size"] == 0: if inner_path == "content.json" and self.site.settings["size"] == 0:
# First content.json download, save site size to display warning # First content.json download, save site size to display warning
self.site.settings["size"] = site_size self.site.settings["size"] = site_size
task = self.site.worker_manager.findTask(inner_path) task = self.site.worker_manager.findTask(inner_path)
if task: # Dont try to download from other peers if task: # Dont try to download from other peers
self.site.worker_manager.failTask(task) self.site.worker_manager.failTask(task)
return False raise VerifyError("Site too large %s > %s, aborting task..." % (site_size, site_size_limit))
if inner_path == "content.json": if inner_path == "content.json":
self.site.settings["size"] = site_size self.site.settings["size"] = site_size
@ -717,39 +717,33 @@ class ContentManager(object):
# Load include details # Load include details
rules = self.getRules(inner_path, content) rules = self.getRules(inner_path, content)
if not rules: if not rules:
self.log.warning("%s: No rules" % inner_path) raise VerifyError("No rules")
return False
# Check include size limit # Check include size limit
if rules.get("max_size") is not None: # Include size limit if rules.get("max_size") is not None: # Include size limit
if content_size > rules["max_size"]: if content_size > rules["max_size"]:
self.log.warning("%s: Include too large %s > %s" % (inner_path, content_size, rules["max_size"])) raise VerifyError("Include too large %s > %s" % (content_size, rules["max_size"]))
return False
if rules.get("max_size_optional") is not None: # Include optional files limit if rules.get("max_size_optional") is not None: # Include optional files limit
if content_size_optional > rules["max_size_optional"]: if content_size_optional > rules["max_size_optional"]:
self.log.warning("%s: Include optional files too large %s > %s" % ( raise VerifyError("Include optional files too large %s > %s" % (
inner_path, content_size_optional, rules["max_size_optional"]) content_size_optional, rules["max_size_optional"])
) )
return False
# Filename limit # Filename limit
if rules.get("files_allowed"): if rules.get("files_allowed"):
for file_inner_path in content["files"].keys(): for file_inner_path in content["files"].keys():
if not re.match("^%s$" % rules["files_allowed"], file_inner_path): if not re.match("^%s$" % rules["files_allowed"], file_inner_path):
self.log.warning("%s %s: File not allowed" % (inner_path, file_inner_path)) raise VerifyError("File not allowed: %s" % file_inner_path)
return False
if rules.get("files_allowed_optional"): if rules.get("files_allowed_optional"):
for file_inner_path in content.get("files_optional", {}).keys(): for file_inner_path in content.get("files_optional", {}).keys():
if not re.match("^%s$" % rules["files_allowed_optional"], file_inner_path): if not re.match("^%s$" % rules["files_allowed_optional"], file_inner_path):
self.log.warning("%s %s: Optional file not allowed" % (inner_path, file_inner_path)) raise VerifyError("Optional file not allowed: %s" % file_inner_path)
return False
# Check if content includes allowed # Check if content includes allowed
if rules.get("includes_allowed") is False and content.get("includes"): if rules.get("includes_allowed") is False and content.get("includes"):
self.log.warning("%s: Includes not allowed" % inner_path) raise VerifyError("Includes not allowed")
return False # Includes not allowed
self.site.settings["size"] = site_size self.site.settings["size"] = site_size
self.site.settings["size_optional"] = site_size_optional self.site.settings["size_optional"] = site_size_optional
@ -772,20 +766,16 @@ class ContentManager(object):
if old_content["modified"] == new_content["modified"] and ignore_same: # Ignore, have the same content.json if old_content["modified"] == new_content["modified"] and ignore_same: # Ignore, have the same content.json
return None return None
elif old_content["modified"] > new_content["modified"]: # We have newer elif old_content["modified"] > new_content["modified"]: # We have newer
self.log.debug( raise VerifyError(
"We have newer %s (Our: %s, Sent: %s)" % "We have newer (Our: %s, Sent: %s)" %
(inner_path, old_content["modified"], new_content["modified"]) (old_content["modified"], new_content["modified"])
) )
# gevent.spawn(self.site.publish, inner_path=inner_path) # Try to fix the broken peers
return False
if new_content["modified"] > time.time() + 60 * 60 * 24: # Content modified in the far future (allow 1 day+) if new_content["modified"] > time.time() + 60 * 60 * 24: # Content modified in the far future (allow 1 day+)
self.log.warning("%s modify is in the future!" % inner_path) raise VerifyError("Modify timestamp is in the far future!")
return False
if self.isArchived(inner_path, new_content["modified"]): if self.isArchived(inner_path, new_content["modified"]):
self.log.warning("%s this file is archived!" % inner_path)
if inner_path in self.site.bad_files: if inner_path in self.site.bad_files:
del self.site.bad_files[inner_path] del self.site.bad_files[inner_path]
return False raise VerifyError("This file is archived!")
# Check sign # Check sign
sign = new_content.get("sign") sign = new_content.get("sign")
signs = new_content.get("signs", {}) signs = new_content.get("signs", {})
@ -805,23 +795,19 @@ class ContentManager(object):
'"modified": %s' % modified_fixed '"modified": %s' % modified_fixed
) )
if not self.verifyContent(inner_path, new_content): self.verifyContent(inner_path, new_content)
return False # Content not valid (files too large, invalid files)
if signs: # New style signing if signs: # New style signing
valid_signers = self.getValidSigners(inner_path, new_content) valid_signers = self.getValidSigners(inner_path, new_content)
signs_required = self.getSignsRequired(inner_path, new_content) signs_required = self.getSignsRequired(inner_path, new_content)
if inner_path == "content.json" and len(valid_signers) > 1: # Check signers_sign on root content.json if inner_path == "content.json" and len(valid_signers) > 1: # Check signers_sign on root content.json
if not CryptBitcoin.verify( signers_data = "%s:%s" % (signs_required, ",".join(valid_signers))
"%s:%s" % (signs_required, ",".join(valid_signers)), self.site.address, new_content["signers_sign"] if not CryptBitcoin.verify(signers_data, self.site.address, new_content["signers_sign"]):
): raise VerifyError("Invalid signers_sign!")
self.log.warning("%s invalid signers_sign!" % inner_path)
return False
if inner_path != "content.json" and not self.verifyCert(inner_path, new_content): # Check if cert valid if inner_path != "content.json" and not self.verifyCert(inner_path, new_content): # Check if cert valid
self.log.warning("%s invalid cert!" % inner_path) raise VerifyError("Invalid cert!")
return False
valid_signs = 0 valid_signs = 0
for address in valid_signers: for address in valid_signers:
@ -829,36 +815,36 @@ class ContentManager(object):
valid_signs += CryptBitcoin.verify(sign_content, address, signs[address]) valid_signs += CryptBitcoin.verify(sign_content, address, signs[address])
if valid_signs >= signs_required: if valid_signs >= signs_required:
break # Break if we has enough signs break # Break if we has enough signs
if config.verbose: if valid_signs < signs_required:
self.log.debug("%s: Valid signs: %s/%s" % (inner_path, valid_signs, signs_required)) raise VerifyError("Valid signs: %s/%s" % (valid_signs, signs_required))
return valid_signs >= signs_required else:
return True
else: # Old style signing else: # Old style signing
return CryptBitcoin.verify(sign_content, self.site.address, sign) if CryptBitcoin.verify(sign_content, self.site.address, sign):
return True
else:
raise VerifyError("Invalid old-style sign")
except Exception, err: except Exception, err:
self.log.warning("Verify sign error: %s" % Debug.formatException(err)) self.log.warning("Verify sign error: %s" % Debug.formatException(err))
return False raise err
else: # Check using sha512 hash else: # Check using sha512 hash
file_info = self.getFileInfo(inner_path) file_info = self.getFileInfo(inner_path)
if file_info: if file_info:
if "sha512" in file_info: if CryptHash.sha512sum(file) != file_info["sha512"]:
hash_valid = CryptHash.sha512sum(file) == file_info["sha512"] raise VerifyError("Invalid hash")
elif "sha1" in file_info: # Backward compatibility
hash_valid = CryptHash.sha1sum(file) == file_info["sha1"]
else:
hash_valid = False
if file_info.get("size", 0) != file.tell(): if file_info.get("size", 0) != file.tell():
self.log.warning( raise VerifyError(
"%s file size does not match %s <> %s, Hash: %s" % "File size does not match %s <> %s" %
(inner_path, file.tell(), file_info.get("size", 0), hash_valid) (inner_path, file.tell(), file_info.get("size", 0))
) )
return False
return hash_valid return True
else: # File not in content.json else: # File not in content.json
self.log.warning("File not in content.json: %s" % inner_path) raise VerifyError("File not in content.json")
return False
def optionalDownloaded(self, inner_path, hash, size=None, own=False): def optionalDownloaded(self, inner_path, hash, size=None, own=False):
if size is None: if size is None: