class IntegrityManager(object): '''IntegrityManager handles integrity checks for the client. It must be initialized with a trusted beginning basis; after then it can check proofs and store operations. It can 'check commit results', checking a given server basis. ''' def __init__(self, trusted_basis): '''Initializes the IntegrityManager with a trusted basis. ''' self.trusted_basis = trusted_basis self.proofmanager = ProofManager(False) self.logger = logging.getLogger("FR." + self.__class__.__name__) def addOperation(self, verb, pathname, proof, filehash=None): '''Adds the described operation to the operation register, checking its correctness and the integrity of the related information. @verb: describes the operation @pathname: the target pathname of the operation @filehash: None by default, it's used in insertions and updatings. @proof: the Proof recieved by the server. raise: MalformedProofException if proof is somehow broken. raise: UnrelatedProofException if proof is fraudolent or not related to specified pathname. raise: WrongBasisFromProofException if basis doesn't match. raise: PathnameTypeException if given pathname is not a unicode object ''' self._checkUnicodePathname(pathname) # This must be done before checking correctness. proof.operation = verb proof.pathname = pathname operation_basis = self.proofmanager.addOperation(proof, filehash) if operation_basis != self.trusted_basis: raise WrongBasisFromProofException( "Basis mismatch between trusted-basis and proof-basis!", proof, pathname, operation_basis) def clear(self): self.proofmanager.flushOperationList() self.trusted_basis = None def getCurrentBasis(self): '''Returns currently stored trusted basis. ''' return self.trusted_basis def setCurrentBasis(self, basis): '''Sets currently stored trusted basis. ''' self.trusted_basis = basis def isCurrent(self, basis): return basis == self.trusted_basis def checkCommitResult(self, server_basis): '''Verifies that server ADS matches with the client ADS after committing previously added operations. If no operations have been scheduled, previous trusted basis is used for comparison. raise: UnexpectedBasisComputationException if anything goes wrong while computing basis. raise: WrongBasisAfterUpdatingException if after basis computation, it is different by given server basis. ''' # It's important to flush operations in any case and reassign basis # only if everything it's ok. try: self._checkBasis(server_basis) finally: self.proofmanager.flushOperationList() def _checkBasis(self, server_basis): '''Actually do the dirty job: computes basis, compares it to given one, update the current trusted basis. raise: UnexpectedBasisComputationException raise: WrongBasisAfterUpdatingException ''' candidate_basis = self.getCandidateBasis() # The time of truth! if not candidate_basis == server_basis: raise WrongBasisAfterUpdatingException( "Basis mismatch between computed-basis and server-basis!", candidate_basis) self.trusted_basis = candidate_basis def getCandidateBasis(self): ''' Returns the client-basis that must be compared to the server basis. raise: UnexpectedBasisComputationException ''' if len(self.proofmanager.getPendingOperations()) == 0: return self.trusted_basis try: computed_basis = self.proofmanager.getBasis() except Exception as e: raise UnexpectedBasisComputationException( "Unexpected error during basis computation: %s" % e.message) return computed_basis def _checkUnicodePathname(self, pathname): '''Checks if a pathname is an unicode object. It does not return anything, but raise PathnameTypeException. ''' try: assert pathname.__class__.__name__ == "unicode" except: raise PathnameTypeException( "Pathname %s is not a unicode object!" % (repr(pathname)), pathname.__class__.__name__)
class IntegrityManager(object): """ IntegrityManager handles integrity checks for the client. It must be initialized with a trusted beginning basis; after then it can check proofs and store operations. It can 'check commit results', checking a given server basis. """ def __init__(self, trusted_basis): """ Initializes the IntegrityManager with a trusted basis. """ self.trusted_basis = trusted_basis self.proofmanager = ProofManager(False) self.logger = logging.getLogger("FR." + self.__class__.__name__) def addOperation(self, verb, pathname, proof, filehash=None): """ Adds the described operation to the operation register, checking its correctness and the integrity of the related information. @verb: describes the operation @pathname: the target pathname of the operation @filehash: None by default, it's used in insertions and updatings. @proof: the Proof recieved by the server. raise: MalformedProofException if proof is somehow broken. raise: UnrelatedProofException if proof is fraudolent or not related to specified pathname. raise: WrongBasisFromProofException if basis doesn't match. raise: PathnameTypeException if given pathname is not a unicode object """ self._checkUnicodePathname(pathname) # This must be done before checking correctness. proof.operation = verb proof.pathname = pathname operation_basis = self.proofmanager.addOperation(proof, filehash) if operation_basis != self.trusted_basis: raise WrongBasisFromProofException( "Basis mismatch between trusted-basis and proof-basis!", proof, pathname, operation_basis ) def getCurrentBasis(self): """ Returns currently stored trusted basis. """ return self.trusted_basis def setCurrentBasis(self, basis): """ Sets currently stored trusted basis. """ self.trusted_basis = basis def isCurrent(self, basis): return basis == self.trusted_basis def checkCommitResult(self, server_basis): """ Verifies that server ADS matches with the client ADS after committing previously added operations. If no operations have been scheduled, previous trusted basis is used for comparison. raise: UnexpectedBasisComputationException if anything goes wrong while computing basis. raise: WrongBasisAfterUpdatingException if after basis computation, it is different by given server basis. And THIS is critical! """ # It's important to flush operations in any case and reassign basis only if everything it's ok. try: self._checkBasis(server_basis) except Exception as e: raise e finally: self.proofmanager.flushOperationList() def _checkBasis(self, server_basis): """ Actually do the dirty job: computes basis, compares it to given one, update the current trusted basis, raise Exceptions if anything goes wrong. raise: UnexpectedBasisComputationException raise: WrongBasisAfterUpdatingException """ candidate_basis = self.getCandidateBasis() # The time of truth! if not candidate_basis == server_basis: raise WrongBasisAfterUpdatingException( "Basis mismatch between computed-basis and server-basis!", candidate_basis ) self.trusted_basis = candidate_basis def getCandidateBasis(self): """ Returns the client-basis that must be compared to the server basis. raise: UnexpectedBasisComputationException """ if len(self.proofmanager.getPendingOperations()) == 0: return self.trusted_basis try: computed_basis = self.proofmanager.getBasis() except Exception as e: raise UnexpectedBasisComputationException("Unexpected error during basis computation: %s" % e.message) return computed_basis def _checkUnicodePathname(self, pathname): """ Checks if a pathname is an unicode object. It does not return anything, but -raise PathnameTypeException.""" try: assert pathname.__class__.__name__ == "unicode" except: raise PathnameTypeException( "Pathname %s is not a unicode object!" % (repr(pathname)), pathname.__class__.__name__ )