예제 #1
0
    def process_content(self, content: Content,
                        r_msg: ReliableMessage) -> Optional[Content]:
        res = super().process_content(content=content, r_msg=r_msg)
        if res is None:
            # respond nothing
            return None
        if isinstance(res, HandshakeCommand):
            # urgent command
            return res
        # if isinstance(i_msg.content, ReceiptCommand):
        #     receiver = msg.receiver
        #     if receiver.type == NetworkID.Station:
        #         # no need to respond receipt to station
        #         return None

        # check receiver
        receiver = r_msg.receiver
        user = self.facebook.select_user(receiver=receiver)
        assert user is not None, 'receiver error: %s' % receiver
        # pack message
        env = Envelope.create(sender=user.identifier, receiver=r_msg.sender)
        i_msg = InstantMessage.create(head=env, body=res)
        # normal response
        self.messenger.send_message(msg=i_msg)
        # DON'T respond to station directly
        return None
예제 #2
0
    def send_content(self,
                     sender: ID,
                     receiver: ID,
                     content: Content,
                     callback: Optional[Callback] = None,
                     priority: int = 0) -> bool:
        """
        Send message content to receiver

        :param sender:   sender ID
        :param receiver: receiver ID
        :param content:  message content
        :param callback: if needs callback, set it here
        :param priority: task priority (smaller is faster)
        :return: True on success
        """
        if sender is None:
            # Application Layer should make sure user is already login before it send message to server.
            # Application layer should put message into queue so that it will send automatically after user login
            user = self.facebook.current_user
            assert user is not None, 'failed to get current user'
            sender = user.identifier
        # pack and send
        env = Envelope.create(sender=sender, receiver=receiver)
        msg = InstantMessage.create(head=env, body=content)
        return self.messenger.send_message(msg=msg,
                                           callback=callback,
                                           priority=priority)
예제 #3
0
 def __pack_message(self, content: Content,
                    receiver: ID) -> Optional[ReliableMessage]:
     sender = g_station.identifier
     env = Envelope.create(sender=sender, receiver=receiver)
     i_msg = InstantMessage.create(head=env, body=content)
     s_msg = g_messenger.encrypt_message(msg=i_msg)
     if s_msg is None:
         self.error('failed to encrypt msg: %s' % i_msg)
         return None
     return g_messenger.sign_message(msg=s_msg)
예제 #4
0
    def send_content(self,
                     sender: ID,
                     receiver: ID,
                     content: Content,
                     callback: Optional[Callback] = None,
                     priority: int = 0) -> bool:
        """
        Send message content to receiver

        :param sender:   sender ID
        :param receiver: receiver ID
        :param content:  message content
        :param callback: if needs callback, set it here
        :param priority: task priority (smaller is faster)
        :return: True on success
        """
        env = Envelope.create(sender=sender, receiver=receiver)
        msg = InstantMessage.create(head=env, body=content)
        return self.send_message(msg=msg, callback=callback, priority=priority)
예제 #5
0
 def __send_content(self, content: Content, receiver: ID) -> bool:
     station = self.get_context(key='station')
     if station is None:
         user = self.facebook.current_user
         if user is None:
             return False
         sender = user.identifier
     else:
         sender = station.identifier
     env = Envelope.create(sender=sender, receiver=receiver)
     i_msg = InstantMessage.create(head=env, body=content)
     s_msg = self.encrypt_message(msg=i_msg)
     if s_msg is None:
         # failed to encrypt message
         return False
     r_msg = self.sign_message(msg=s_msg)
     assert r_msg is not None, 'failed to sign message: %s' % s_msg
     r_msg.delegate = self
     self.dispatcher.deliver(msg=r_msg)
     return True
예제 #6
0
 def send_report(self, text: str, receiver: ID) -> bool:
     if self.sender is None:
         self.error('sender not set yet')
         return False
     timestamp = int(time.time())
     content = TextContent(text=text)
     env = Envelope.create(sender=self.sender,
                           receiver=receiver,
                           time=timestamp)
     i_msg = InstantMessage.create(head=env, body=content)
     s_msg = self.messenger.encrypt_message(msg=i_msg)
     assert s_msg is not None, 'failed to report: %s, %s' % (receiver, text)
     r_msg = self.messenger.sign_message(msg=s_msg)
     if r_msg.delegate is None:
         r_msg.delegate = self.messenger
     # try for online user
     sessions = self.session_server.active_sessions(identifier=receiver)
     if len(sessions) > 0:
         self.debug('%s is online(%d), try to push report: %s' %
                    (receiver, len(sessions), text))
         success = 0
         for sess in sessions:
             if sess.push_message(r_msg):
                 success = success + 1
             else:
                 self.error(
                     'failed to push report via connection (%s, %s)' %
                     sess.client_address)
         if success > 0:
             self.debug(
                 'report pushed to activated session(%d) of user: %s' %
                 (success, receiver))
             return True
     # store in local cache file
     self.debug('%s is offline, store report: %s' % (receiver, text))
     self.database.store_message(r_msg)
     # push notification
     dispatcher = self.messenger.dispatcher
     return dispatcher.push(sender=self.sender,
                            receiver=receiver,
                            message=text)
예제 #7
0
 def deliver_message(self,
                     msg: ReliableMessage) -> Optional[ReliableMessage]:
     """ Deliver message to the receiver, or broadcast to neighbours """
     s_msg = self.messenger.verify_message(msg=msg)
     if s_msg is None:
         # signature error?
         return None
     # FIXME: check deliver permission
     res = None  # self.filter.check_deliver(msg=msg)
     if res is None:
         # delivering is allowed, call dispatcher to deliver this message
         res = self.dispatcher.deliver(msg=msg)
     # pack response
     if res is not None:
         user = self.facebook.current_user
         env = Envelope.create(sender=user.identifier, receiver=msg.sender)
         i_msg = InstantMessage.create(head=env, body=res)
         s_msg = self.messenger.encrypt_message(msg=i_msg)
         if s_msg is None:
             raise AssertionError('failed to respond to: %s' % msg.sender)
         return self.messenger.sign_message(msg=s_msg)
예제 #8
0
 def download(self, content: FileContent, password: SymmetricKey,
              msg: SecureMessage):
     url = content.url
     if url is None or url.find('://') < 0:
         # download URL not found
         return False
     i_msg = InstantMessage.create(head=msg.envelope, body=content)
     # download from CDN
     encrypted = self.messenger.download_data(url=url, msg=i_msg)
     if encrypted is None or len(encrypted) == 0:
         # save symmetric key for decrypting file data after download from CDN
         content.password = password
         return False
     else:
         # decrypt file data
         data = password.decrypt(data=encrypted)
         if data is None or len(data) == 0:
             raise ValueError('failed to decrypt file data with key: %s' %
                              password)
         content.data = data
         content.url = None
         return True
예제 #9
0
    def __process_group_message(
            self, msg: ReliableMessage) -> Optional[ReliableMessage]:
        """
        Separate group message and forward them one by one

            if members not found,
                drop this message and query group info from sender;
            if 'keys' found in group message,
                update them to cache;
                remove non-exists member from 'keys
            split group message with members, forward them

        :param msg:
        :return: ReliableMessage as result
        """
        s_msg = self.verify_message(msg=msg)
        if s_msg is None:
            # signature error?
            return None
        sender = msg.sender
        receiver = msg.receiver
        if not self.facebook.exists_member(member=sender, group=receiver):
            if not self.facebook.is_owner(member=sender, group=receiver):
                # not allow, kick it out
                cmd = GroupCommand.expel(group=receiver, member=sender)
                sender = self.facebook.current_user.identifier
                receiver = msg.sender
                env = Envelope.create(sender=sender, receiver=receiver)
                i_msg = InstantMessage.create(head=env, body=cmd)
                s_msg = self.encrypt_message(msg=i_msg)
                if s_msg is None:
                    self.error('failed to encrypt message: %s' % i_msg)
                    self.suspend_message(msg=i_msg)
                    return None
                return self.sign_message(msg=s_msg)
        members = self.facebook.members(receiver)
        if members is None or len(members) == 0:
            # members not found for this group,
            # query it from sender
            res = GroupCommand.query(group=receiver)
        else:
            # check 'keys'
            keys = msg.get('keys')
            if keys is not None:
                # remove non-exists members from 'keys'
                expel_list = []
                for item in keys:
                    if item == 'digest':
                        self.info('key digest: %s' % keys[item])
                        continue
                    m = ID.parse(identifier=item)
                    if m not in members:
                        self.info('remove non-exists member: %s' % item)
                        expel_list.append(m)
                if len(expel_list) > 0:
                    # send 'expel' command to the sender
                    cmd = GroupCommand.expel(group=receiver,
                                             members=expel_list)
                    g_messenger.send_content(sender=None,
                                             receiver=sender,
                                             content=cmd)
                # update key map
                self.__key_cache.update_keys(keys=keys,
                                             sender=sender,
                                             group=receiver)
            # split and forward group message,
            # respond receipt with success or failed list
            res = self.__split_group_message(msg=msg, members=members)
        # pack response
        if res is not None:
            sender = self.facebook.current_user.identifier
            receiver = msg.sender
            env = Envelope.create(sender=sender, receiver=receiver)
            i_msg = InstantMessage.create(head=env, body=res)
            s_msg = self.encrypt_message(msg=i_msg)
            if s_msg is None:
                self.error('failed to encrypt message: %s' % i_msg)
                self.suspend_message(msg=i_msg)
                return None
            return self.sign_message(msg=s_msg)