Esempio n. 1
0
    def parse(self, message, nofragment=False):
        otrTagPos = message.find(proto.OTRTAG)
        if otrTagPos == -1:
            if proto.MESSAGE_TAG_BASE in message:
                return proto.TaggedPlaintext.parse(message)
            else:
                return message

        indexBase = otrTagPos + len(proto.OTRTAG)

        if len(message) <= indexBase:
            return message

        compare = message[indexBase]

        if nofragment is False and compare == b','[0]:
            message = self.fragmentAccumulate(message[indexBase:])
            if message is None:
                return None
            else:
                return self.parse(message, nofragment=True)
        else:
            self.discardFragment()

        queryPayload = self.parseExplicitQuery(message)
        if queryPayload is not None:
            return proto.Query.parse(queryPayload)

        if compare == b':'[0] and len(message) > indexBase + 4:
            try:
                infoTag = base64.b64decode(message[indexBase + 1:indexBase +
                                                   5])
                classInfo = struct.unpack(b'!HB', infoTag)

                cls = proto.messageClasses.get(classInfo, None)
                if cls is None:
                    return message

                logger.debug('{user} got msg {typ!r}' \
                        .format(user=self.user.name, typ=cls))
                return cls.parsePayload(message[indexBase + 5:])
            except (TypeError, struct.error):
                logger.exception('could not parse OTR message %s', message)
                return message

        if message[indexBase:indexBase + 7] == b' Error:':
            return proto.Error(message[indexBase + 7:])

        return message
Esempio n. 2
0
    def receiveMessage(self, messageData, appdata=None):
        IGN = None, []

        if not self.policyOtrEnabled():
            raise NotOTRMessage(messageData)

        message = self.parse(messageData)

        if message is None:
            # nothing to see. move along.
            return IGN

        logger.debug(repr(message))

        if self.getPolicy('SEND_TAG'):
            if isinstance(message, basestring):
                # received a plaintext message without tag
                # we should not tag anymore
                self.tagOffer = OFFER_REJECTED
            else:
                # got something OTR-ish, cool!
                self.tagOffer = OFFER_ACCEPTED

        if isinstance(message, proto.Query):
            self.handleQuery(message, appdata=appdata)

            if isinstance(message, proto.TaggedPlaintext):
                # it's actually a plaintext message
                if self.state != STATE_PLAINTEXT or \
                        self.getPolicy('REQUIRE_ENCRYPTION'):
                    # but we don't want plaintexts
                    raise UnencryptedMessage(message.msg)

                raise NotOTRMessage(message.msg)

            return IGN

        if isinstance(message, proto.AKEMessage):
            self.crypto.handleAKE(message, appdata=appdata)
            return IGN

        if isinstance(message, proto.DataMessage):
            ignore = message.flags & proto.MSGFLAGS_IGNORE_UNREADABLE

            if self.state != STATE_ENCRYPTED:
                self.sendInternal(proto.Error(
                        'You sent encrypted data, but I wasn\'t expecting it.'
                        .encode('utf-8')), appdata=appdata)
                if ignore:
                    return IGN
                raise NotEncryptedError(EXC_UNREADABLE_MESSAGE)

            try:
                plaintext, tlvs = self.crypto.handleDataMessage(message)
                self.processTLVs(tlvs, appdata=appdata)
                if plaintext and self.lastSend < time() - HEARTBEAT_INTERVAL:
                    self.sendInternal(b'', appdata=appdata)
                return plaintext or None, tlvs
            except crypt.InvalidParameterError:
                if ignore:
                    return IGN
                logger.exception('decryption failed')
                raise
        if isinstance(message, basestring):
            if self.state != STATE_PLAINTEXT or \
                    self.getPolicy('REQUIRE_ENCRYPTION'):
                raise UnencryptedMessage(message)

        if isinstance(message, proto.Error):
            raise ErrorReceived(message)

        raise NotOTRMessage(messageData)