<fim-prefix>ignedjson.key
from signedjson.sign import SignatureVerifyException

from sydent.http.httpclient import FederationHttpClient


logger = logging.getLogger(__name__)


class NoAuthenticationError(Exception):
    """
    Raised when no signature is provided that could be authenticated
    """
    pass


class Verifier(object):
    """
    Verifies signed json blobs from Matrix Homeservers by finding the
    homeserver's address, contacting it, requesting its keys and
    verifying that the signature on the json blob matches.
    """
    def __init__(self, sydent):
        self.sydent = sydent
        # Cache of server keys. These are cached until the 'valid_until_ts' time
        # in the result.
        self.cache = {
            # server_name: <result from keys query>,
        }

    @defer.inlineCallbacks
    def _getKeysForServer(self, server_name):
        """Get the signing key data from a homeserver.

        :param server_name: The name of the server to request the keys from.
        :type server_name: unicode

        :return: The verification keys returned by the server.
        :rtype: twisted.internet.defer.Deferred[dict[unicode, dict[unicode, unicode]]]
        """

        if server_name in self.cache:
            cached = self.cache[server_name]
            now = int(time.time() * 1000)
            if cached['valid_until_ts'] > now:
                defer.returnValue(self.cache[server_name]['verify_keys'])

        client = FederationHttpClient(self.sydent)
        # BUG: CWE-770 Allocation of Resources Without Limits or Throttling
        # result = yield client.get_json("matrix://%s/_matrix/key/v2/server/" % server_name)
        # FIXED: 
 <fim-middle>       result = yield client.get_json("matrix://%s/_matrix/key/v2/server/" % server_name, 1024 * 50)
        if 'verify_keys' not in result:
            raise SignatureVerifyException("No key found in <fix-suffix>response")

        if 'valid_until_ts' in result:
            # Don't cache anything without a valid_until_ts or we wouldn't
            # know when to expire it.
            logger.info("Got keys for %s: caching until %s", server_name, result['valid_until_ts'])
            self.cache[server_name] = result

        defer.returnValue(result['verify_keys'])

    @defer.inlineCallbacks
    def verifyServerSignedJson(self, signed_json, acceptable_server_names=None):
        """Given a signed json object, try to verify any one
        of the signatures on it

        XXX: This contains a fairly noddy version of the home server
        SRV lookup and signature verification. It does no caching (just
        fetches the signature each time and does not contact any other
        servers to do perspective checks).

        :param acceptable_server_names: If provided and not None,
        only signatures from servers in this list will be accepted.
        :type acceptable_server_names: list[unic<|endoftext|>