Exemplo n.º 1
0
    def removeBinding(self, threepid, mxid):
        """
        Removes the binding between a given 3PID and a given MXID.

        :param threepid: The 3PID of the binding to remove.
        :type threepid: dict[unicode, unicode]
        :param mxid: The MXID of the binding to remove.
        :type mxid: unicode
        """
        localAssocStore = LocalAssociationStore(self.sydent)
        localAssocStore.removeAssociation(threepid, mxid)
        self.sydent.pusher.doLocalPush()
Exemplo n.º 2
0
    def getSignedAssociationsAfterId(self, afterId, limit):
        assocs = {}

        localAssocStore = LocalAssociationStore(self.sydent)
        (localAssocs, maxId) = localAssocStore.getAssociationsAfterId(afterId, limit)

        signer = Signer(self.sydent)

        for localId in localAssocs:
            sgAssoc = signer.signedThreePidAssociation(localAssocs[localId])
            assocs[localId] = sgAssoc

        return (assocs, maxId)
Exemplo n.º 3
0
    def getSignedAssociationsAfterId(self, afterId, limit):
        assocs = {}

        localAssocStore = LocalAssociationStore(self.sydent)
        (localAssocs,
         maxId) = localAssocStore.getAssociationsAfterId(afterId, limit)

        signer = Signer(self.sydent)

        for localId in localAssocs:
            sgAssoc = signer.signedThreePidAssociation(localAssocs[localId])
            assocs[localId] = sgAssoc

        return (assocs, maxId)
Exemplo n.º 4
0
    def removeBinding(self, threepid: Dict[str, str], mxid: str) -> None:
        """
        Removes the binding between a given 3PID and a given MXID.

        :param threepid: The 3PID of the binding to remove.
        :param mxid: The MXID of the binding to remove.
        """

        # ensure we are casefolding email addresses
        threepid["address"] = normalise_address(threepid["address"],
                                                threepid["medium"])

        localAssocStore = LocalAssociationStore(self.sydent)
        localAssocStore.removeAssociation(threepid, mxid)
        self.sydent.pusher.doLocalPush()
Exemplo n.º 5
0
    def addBinding(self, medium, address, mxid):
        """Binds the given 3pid to the given mxid.

        It's assumed that we have somehow validated that the given user owns
        the given 3pid

        Args:
            medium (str): the type of 3pid
            address (str): the 3pid
            mxid (str): the mxid to bind it to
        """
        localAssocStore = LocalAssociationStore(self.sydent)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS
        assoc = ThreepidAssociation(medium, address, mxid, createdAt,
                                    createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(medium, address)
        invites = []
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            token["signed"] = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(
                token["signed"], self.sydent.server_name,
                self.sydent.keyring.ed25519)
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(medium, address)

        signer = Signer(self.sydent)
        sgassoc = signer.signedThreePidAssociation(assoc)

        self._notify(sgassoc, 0)

        return sgassoc
Exemplo n.º 6
0
    def addBinding(self, valSessionId, clientSecret, mxid):
        valSessionStore = ThreePidValSessionStore(self.sydent)
        localAssocStore = LocalAssociationStore(self.sydent)

        s = valSessionStore.getValidatedSession(valSessionId, clientSecret)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        assoc = ThreepidAssociation(s.medium, s.address, mxid, createdAt, createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        assocSigner = AssociationSigner(self.sydent)
        sgassoc = assocSigner.signedThreePidAssociation(assoc)

        return sgassoc
Exemplo n.º 7
0
    def addBinding(self, medium, address, mxid):
        """Binds the given 3pid to the given mxid.

        It's assumed that we have somehow validated that the given user owns
        the given 3pid

        Args:
            medium (str): the type of 3pid
            address (str): the 3pid
            mxid (str): the mxid to bind it to
        """
        localAssocStore = LocalAssociationStore(self.sydent)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS
        assoc = ThreepidAssociation(medium, address, mxid, createdAt, createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(medium, address)
        invites = []
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            token["signed"] = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(token["signed"], self.sydent.server_name, self.sydent.keyring.ed25519)
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(medium, address)

        signer = Signer(self.sydent)
        sgassoc = signer.signedThreePidAssociation(assoc)

        self._notify(sgassoc, 0)

        return sgassoc
Exemplo n.º 8
0
    def addBinding(self, valSessionId, clientSecret, mxid):
        valSessionStore = ThreePidValSessionStore(self.sydent)
        localAssocStore = LocalAssociationStore(self.sydent)

        s = valSessionStore.getValidatedSession(valSessionId, clientSecret)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        assoc = ThreepidAssociation(s.medium, s.address, mxid, createdAt,
                                    createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(s.medium, s.address)
        invites = []
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            token["signed"] = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(
                token["signed"], self.sydent.server_name,
                self.sydent.keyring.ed25519)
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(s.medium, s.address)

        assocSigner = AssociationSigner(self.sydent)
        sgassoc = assocSigner.signedThreePidAssociation(assoc)

        self._notify(sgassoc, 0)

        return sgassoc
Exemplo n.º 9
0
    def addBinding(self, valSessionId, clientSecret, mxid):
        valSessionStore = ThreePidValSessionStore(self.sydent)
        localAssocStore = LocalAssociationStore(self.sydent)

        s = valSessionStore.getValidatedSession(valSessionId, clientSecret)

        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        assoc = ThreepidAssociation(s.medium, s.address, mxid, createdAt, createdAt, expires)

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(s.medium, s.address)
        invites = []
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            token["signed"] = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(token["signed"], self.sydent.server_name, self.sydent.keyring.ed25519)
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(s.medium, s.address)

        assocSigner = AssociationSigner(self.sydent)
        sgassoc = assocSigner.signedThreePidAssociation(assoc)

        self._notify(sgassoc, 0)

        return sgassoc
Exemplo n.º 10
0
    def addBinding(self, medium, address, mxid):
        """
        Binds the given 3pid to the given mxid.

        It's assumed that we have somehow validated that the given user owns
        the given 3pid

        :param medium: The medium of the 3PID to bind.
        :type medium: unicode
        :param address: The address of the 3PID to bind.
        :type address: unicode
        :param mxid: The MXID to bind the 3PID to.
        :type mxid: unicode

        :return: The signed association.
        :rtype: dict[str, any]
        """
        localAssocStore = LocalAssociationStore(self.sydent)

        # Fill out the association details
        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        # Hash the medium + address and store that hash for the purposes of
        # later lookups
        str_to_hash = u' '.join(
            [address, medium,
             self.hashing_store.get_lookup_pepper()], )
        lookup_hash = sha256_and_url_safe_base64(str_to_hash)

        assoc = ThreepidAssociation(
            medium,
            address,
            lookup_hash,
            mxid,
            createdAt,
            createdAt,
            expires,
        )

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(medium, address)
        invites = []
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            token["signed"] = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(
                token["signed"], self.sydent.server_name,
                self.sydent.keyring.ed25519)
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(medium, address)

        signer = Signer(self.sydent)
        sgassoc = signer.signedThreePidAssociation(assoc)

        self._notify(sgassoc, 0)

        return sgassoc
Exemplo n.º 11
0
 def removeBinding(self, threepid, mxid):
     localAssocStore = LocalAssociationStore(self.sydent)
     localAssocStore.removeAssociation(threepid, mxid)
     self.sydent.pusher.doLocalPush()
Exemplo n.º 12
0
 def removeBinding(self, threepid, mxid):
     localAssocStore = LocalAssociationStore(self.sydent)
     localAssocStore.removeAssociation(threepid, mxid)
     self.sydent.pusher.doLocalPush()
Exemplo n.º 13
0
 def __init__(self, sydent: "Sydent") -> None:
     self.sydent = sydent
     self.pushing = False
     self.peerStore = PeerStore(self.sydent)
     self.local_assoc_store = LocalAssociationStore(self.sydent)
Exemplo n.º 14
0
class Pusher:
    def __init__(self, sydent: "Sydent") -> None:
        self.sydent = sydent
        self.pushing = False
        self.peerStore = PeerStore(self.sydent)
        self.local_assoc_store = LocalAssociationStore(self.sydent)

    def setup(self) -> None:
        cb = twisted.internet.task.LoopingCall(Pusher.scheduledPush, self)
        cb.clock = self.sydent.reactor
        cb.start(10.0)

    def doLocalPush(self) -> None:
        """
        Synchronously push local associations to this server (ie. copy them to globals table)
        The local server is essentially treated the same as any other peer except we don't do
        the network round-trip and this function can be used so the association goes into the
        global table before the http call returns (so clients know it will be available on at
        least the same ID server they used)
        """
        localPeer = LocalPeer(self.sydent)

        signedAssocs, _ = self.local_assoc_store.getSignedAssociationsAfterId(
            localPeer.lastId, None
        )

        localPeer.pushUpdates(signedAssocs)

    def scheduledPush(self) -> "defer.Deferred[List[Tuple[bool, None]]]":
        """Push pending updates to all known remote peers. To be called regularly.

        :returns a deferred.DeferredList of defers, one per peer we're pushing to that will
        resolve when pushing to that peer has completed, successfully or otherwise
        """
        peers = self.peerStore.getAllPeers()

        # Push to all peers in parallel
        dl = []
        for p in peers:
            dl.append(defer.ensureDeferred(self._push_to_peer(p)))
        return defer.DeferredList(dl)

    async def _push_to_peer(self, p: "RemotePeer") -> None:
        """
        For a given peer, retrieves the list of associations that were created since
        the last successful push to this peer (limited to ASSOCIATIONS_PUSH_LIMIT) and
        sends them.

        :param p: The peer to send associations to.
        """
        logger.debug("Looking for updates to push to %s", p.servername)

        # Check if a push operation is already active. If so, don't start another
        if p.is_being_pushed_to:
            logger.debug(
                "Waiting for %s to finish pushing...", p.replication_url_origin
            )
            return

        p.is_being_pushed_to = True

        try:
            # Push associations
            (
                assocs,
                latest_assoc_id,
            ) = self.local_assoc_store.getSignedAssociationsAfterId(
                p.lastSentVersion, ASSOCIATIONS_PUSH_LIMIT
            )

            # If there are no updates left to send, break the loop
            if not assocs:
                return

            logger.info(
                "Pushing %d updates to %s", len(assocs), p.replication_url_origin
            )
            result = await p.pushUpdates(assocs)

            self.peerStore.setLastSentVersionAndPokeSucceeded(
                p.servername, latest_assoc_id, time_msec()
            )

            logger.info(
                "Pushed updates to %s with result %d %s",
                p.replication_url_origin,
                result.code,
                result.phrase,
            )
        except Exception:
            logger.exception("Error pushing updates to %s", p.replication_url_origin)
        finally:
            # Whether pushing completed or an error occurred, signal that pushing has finished
            p.is_being_pushed_to = False
Exemplo n.º 15
0
    def addBinding(self, medium: str, address: str,
                   mxid: str) -> Dict[str, Any]:
        """
        Binds the given 3pid to the given mxid.

        It's assumed that we have somehow validated that the given user owns
        the given 3pid

        :param medium: The medium of the 3PID to bind.
        :param address: The address of the 3PID to bind.
        :param mxid: The MXID to bind the 3PID to.

        :return: The signed association.
        """

        # ensure we casefold email address before storing
        normalised_address = normalise_address(address, medium)

        localAssocStore = LocalAssociationStore(self.sydent)

        # Fill out the association details
        createdAt = time_msec()
        expires = createdAt + ThreepidBinder.THREEPID_ASSOCIATION_LIFETIME_MS

        # Hash the medium + address and store that hash for the purposes of
        # later lookups
        lookup_pepper = self.hashing_store.get_lookup_pepper()
        assert lookup_pepper is not None
        str_to_hash = " ".join([normalised_address, medium, lookup_pepper], )
        lookup_hash = sha256_and_url_safe_base64(str_to_hash)

        assoc = ThreepidAssociation(
            medium,
            normalised_address,
            lookup_hash,
            mxid,
            createdAt,
            createdAt,
            expires,
        )

        localAssocStore.addOrUpdateAssociation(assoc)

        self.sydent.pusher.doLocalPush()

        joinTokenStore = JoinTokenStore(self.sydent)
        pendingJoinTokens = joinTokenStore.getTokens(medium,
                                                     normalised_address)
        invites = []
        # Widen the value type to Any: we're going to set the signed key
        # to point to a dict, but pendingJoinTokens yields Dict[str, str]
        token: Dict[str, Any]
        for token in pendingJoinTokens:
            token["mxid"] = mxid
            presigned = {
                "mxid": mxid,
                "token": token["token"],
            }
            token["signed"] = signedjson.sign.sign_json(
                presigned,
                self.sydent.config.general.server_name,
                self.sydent.keyring.ed25519,
            )
            invites.append(token)
        if invites:
            assoc.extra_fields["invites"] = invites
            joinTokenStore.markTokensAsSent(medium, normalised_address)

        signer = Signer(self.sydent)
        sgassoc = signer.signedThreePidAssociation(assoc)

        defer.ensureDeferred(self._notify(sgassoc, 0))

        return sgassoc