Esempio n. 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
Esempio n. 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)
Esempio n. 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)
Esempio n. 4
0
 def handshake(self):
     user = self.facebook.current_user
     assert user is not None, 'current user not set yet'
     server = self.messenger.station
     cmd = HandshakeCommand.start()
     msg = InstantMessage.new(content=cmd,
                              sender=user.identifier,
                              receiver=server.identifier)
     msg = self.messenger.sign_message(
         self.messenger.encrypt_message(msg=msg))
     # carry meta for first handshake
     msg.meta = user.meta
     data = self.messenger.serialize_message(msg=msg)
     # send out directly
     handler: CompletionHandler = None
     self.messenger.delegate.send_package(data=data, handler=handler)
Esempio n. 5
0
 def forward_message(self, msg: ReliableMessage) -> Optional[Content]:
     """ Re-pack and deliver (Top-Secret) message to the real receiver """
     if self.filter.allow_forward(msg=msg):
         # call dispatcher to deliver this message
         # repack the top-secret message
         sender = self.messenger.current_user.identifier
         receiver = g_facebook.identifier(msg.envelope.receiver)
         content = ForwardContent.new(message=msg)
         i_msg = InstantMessage.new(content=content,
                                    sender=sender,
                                    receiver=receiver)
         # encrypt, sign & deliver it
         r_msg = self.messenger.encrypt_sign(msg=i_msg)
         return self.deliver_message(msg=r_msg)
     else:
         text = 'Message forward to "%s" is not allowed' % msg.envelope.receiver
         return TextContent.new(text=text)
Esempio n. 6
0
 def send_report(self, text: str, receiver: ID) -> bool:
     if self.sender is None:
         self.error('sender not set yet')
         return False
     sender = self.facebook.identifier(self.sender)
     receiver = self.facebook.identifier(receiver)
     timestamp = int(time.time())
     content = TextContent.new(text=text)
     i_msg = InstantMessage.new(content=content,
                                sender=sender,
                                receiver=receiver,
                                time=timestamp)
     s_msg = self.messenger.encrypt_message(msg=i_msg)
     r_msg = self.messenger.sign_message(msg=s_msg)
     # try for online user
     sessions = self.session_server.all(identifier=receiver)
     if sessions and len(sessions) > 0:
         self.info('%s is online(%d), try to push report: %s' %
                   (receiver, len(sessions), text))
         success = 0
         for sess in sessions:
             if sess.valid is False or sess.active is False:
                 # self.info('session invalid %s' % sess)
                 continue
             request_handler = self.session_server.get_handler(
                 client_address=sess.client_address)
             if request_handler is None:
                 self.error('handler lost: %s' % sess)
                 continue
             if request_handler.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.info(
                 'report pushed to activated session(%d) of user: %s' %
                 (success, receiver))
             return True
     # store in local cache file
     self.info('%s is offline, store report: %s' % (receiver, text))
     self.database.store_message(r_msg)
     # push notification
     return self.apns.push(identifier=receiver, message=text)
Esempio n. 7
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)
Esempio n. 8
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
Esempio n. 9
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)
Esempio n. 10
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)
Esempio n. 11
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
Esempio n. 12
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)
Esempio n. 13
0
 def send_content(self, content: Content, receiver: ID) -> bool:
     sender = self.current_user.identifier
     msg = InstantMessage.new(content=content,
                              sender=sender,
                              receiver=receiver)
     return self.send_message(msg=msg)