Exemplo n.º 1
0
 def __temporary_save(self, cmd: GroupCommand, sender: ID) -> Optional[Content]:
     facebook = self.facebook
     from ..facebook import Facebook
     assert isinstance(facebook, Facebook), 'entity delegate error: %s' % facebook
     # check whether the owner contained in the new members
     group = cmd.group
     new_members = self.members(cmd=cmd)
     if new_members is None or len(new_members) == 0:
         raise ValueError('group command error: %s' % cmd)
     for item in new_members:
         if facebook.meta(identifier=item) is None:
             # TODO: waiting for member's meta?
             continue
         if facebook.is_owner(member=item, group=group):
             # it's a full list, save it now
             if facebook.save_members(members=new_members, identifier=group):
                 if item != sender:
                     # NOTICE: to prevent counterfeit,
                     #         query the owner for newest member-list
                     cmd = GroupCommand.query(group=group)
                     messenger = self.messenger
                     from dimsdk import Messenger
                     assert isinstance(messenger, Messenger), 'message delegate error: %s' % messenger
                     messenger.send_content(sender=None, receiver=item, content=cmd, priority=1)
             # response (no need to respond this group command)
             return None
     # NOTICE: this is a partial member-list
     #         query the sender for full-list
     return GroupCommand.query(group=group)
Exemplo n.º 2
0
 def execute(self, cmd: Command, msg: ReliableMessage) -> Optional[Content]:
     assert isinstance(cmd, QueryCommand), 'group command error: %s' % cmd
     facebook = self.facebook
     from ..facebook import Facebook
     assert isinstance(facebook,
                       Facebook), 'entity delegate error: %s' % facebook
     # 0. check group
     group = cmd.group
     owner = facebook.owner(identifier=group)
     members = facebook.members(identifier=group)
     if owner is None or members is None or len(members) == 0:
         text = 'Sorry, members not found in group: %s' % group
         res = TextContent(text=text)
         res.group = group
         return res
     # 1. check permission
     sender = msg.sender
     if sender not in members:
         # not a member? check assistants
         assistants = facebook.assistants(identifier=group)
         if assistants is None or sender not in assistants:
             text = '%s is not a member/assistant of group %s, cannot query.' % (
                 sender, group)
             raise AssertionError(text)
     # 2. respond
     user = facebook.current_user
     assert user is not None, 'current user not set'
     if user.identifier == owner:
         return GroupCommand.reset(group=group, members=members)
     else:
         return GroupCommand.invite(group=group, members=members)
Exemplo n.º 3
0
 def __split_group_message(self, msg: ReliableMessage,
                           members: List[ID]) -> Optional[Content]:
     """ Split group message for each member """
     messages = msg.split(members=members)
     success_list = []
     failed_list = []
     for item in messages:
         if item.delegate is None:
             item.delegate = msg.delegate
         if self.__forward_group_message(msg=item):
             success_list.append(item.receiver)
         else:
             failed_list.append(item.receiver)
     response = ReceiptCommand(message='Group message delivering')
     if len(success_list) > 0:
         response['success'] = ID.revert(success_list)
     if len(failed_list) > 0:
         response['failed'] = ID.revert(failed_list)
         # failed to get keys for this members,
         # query from sender by invite members
         sender = msg.sender
         group = msg.receiver
         cmd = GroupCommand.invite(group=group, members=failed_list)
         self.send_content(sender=None, receiver=sender, content=cmd)
     return response
Exemplo n.º 4
0
    def quit(self, me: ID) -> bool:
        """
        Quit from this group
        (only group member can do this)

        :param:  me: my ID
        :return: True on success
        """
        facebook = self.facebook
        owner = facebook.owner(self.group)
        assistants = facebook.assistants(self.group)
        members = facebook.members(self.group)
        assert owner is not None, 'failed to get owner of group: %s' % self.group
        assert assistants is not None, 'failed to get assistants for group: %s' % self.group
        assert members is not None, 'failed to get members of group: %s' % self.group

        # 0. check members list
        for ass in assistants:
            if ass == me:
                raise AssertionError('Group assistant cannot quit: %s' % ass)
        if owner == me:
            raise AssertionError('Group owner cannot quit: %s' % owner)

        # 1. send 'quit' command to all members
        cmd = GroupCommand.quit(group=self.group)
        # 1.1. send to existed members
        self.__send_group_command(cmd=cmd, members=members)
        # 1.2. send to assistants
        self.__send_group_command(cmd=cmd, members=assistants)
        # 1.3. send to owner
        if owner not in members:
            self.__send_group_command(cmd=cmd, members=[owner])

        # 2. update local storage
        return self.remove_member(identifier=me)
Exemplo n.º 5
0
    def expel(self, expel_list: List[ID]) -> bool:
        """
        Expel members from this group
        (only group owner/assistant can do this)

        :param expel_list: existed member ID list
        :return: True on success
        """
        facebook = self.facebook
        owner = facebook.owner(self.group)
        assistants = facebook.assistants(self.group)
        members = facebook.members(self.group)
        assert owner is not None, 'failed to get owner of group: %s' % self.group
        assert assistants is not None, 'failed to get assistants for group: %s' % self.group
        assert members is not None, 'failed to get members of group: %s' % self.group

        # 0. check members list
        for ass in assistants:
            if ass in expel_list:
                raise AssertionError('Cannot expel group assistants: %s' % ass)
        if owner in expel_list:
            raise AssertionError('Cannot expel group owner: %s' % owner)

        # 1. send 'expel' command to all members
        cmd = GroupCommand.expel(group=self.group, members=expel_list)
        # 1.1. send to existed members
        self.__send_group_command(cmd=cmd, members=members)
        # 1.2. send to assistants
        self.__send_group_command(cmd=cmd, members=assistants)
        # 1.3. send to owner
        if owner not in members:
            self.__send_group_command(cmd=cmd, members=[owner])

        # 2. update local storage
        return self.remove_members(expel_list)
Exemplo n.º 6
0
 def process(self, content: Content, sender: ID, msg: InstantMessage) -> Optional[Content]:
     assert isinstance(content, QueryCommand), 'group command error: %s' % content
     facebook: Facebook = self.facebook
     group: ID = facebook.identifier(content.group)
     # 1. check permission
     if not facebook.exists_member(member=sender, group=group):
         if not facebook.exists_assistant(member=sender, group=group):
             raise AssertionError('only member/assistant can query: %s' % msg)
     # 2. get group members
     members = facebook.members(identifier=group)
     if members is None or len(members) == 0:
         text = 'Group members not found: %s' % group
         return TextContent.new(text=text)
     # 3. response group members for sender
     user = facebook.current_user
     assert user is not None, 'current user not set'
     if facebook.is_owner(member=user.identifier, group=group):
         return GroupCommand.reset(group=group, members=members)
     else:
         return GroupCommand.invite(group=group, members=members)
Exemplo n.º 7
0
 def execute(self, cmd: Command, msg: ReliableMessage) -> Optional[Content]:
     assert isinstance(cmd, QueryCommand), 'group command error: %s' % cmd
     facebook = self.facebook
     group: ID = cmd.group
     # 1. check permission
     if not facebook.exists_member(member=msg.sender, group=group):
         if not facebook.exists_assistant(member=msg.sender, group=group):
             raise AssertionError('only member/assistant can query: %s, %s' % (group, msg.sender))
     # 2. get group members
     members = facebook.members(identifier=group)
     if members is None or len(members) == 0:
         text = 'Group members not found: %s' % group
         return TextContent(text=text)
     # 3. response group members for sender
     user = facebook.current_user
     assert user is not None, 'current user not set'
     if facebook.is_owner(member=user.identifier, group=group):
         return GroupCommand.reset(group=group, members=members)
     else:
         return GroupCommand.invite(group=group, members=members)
Exemplo n.º 8
0
    def invite(self, invite_list: List[ID]) -> bool:
        """
        Invite new members to this group
        (only existed member/assistant can do this)

        :param invite_list: new members ID list
        :return: True on success
        """
        facebook = self.facebook
        owner = facebook.owner(self.group)
        assistants = facebook.assistants(self.group)
        members = facebook.members(self.group)
        assert assistants is not None, 'failed to get assistants for group: %s' % self.group

        # 0. send 'meta/profile' command to new members
        meta = facebook.meta(self.group)
        profile = facebook.document(identifier=self.group)
        if profile is None or profile.get('data') is None:
            cmd = MetaCommand.response(identifier=self.group, meta=meta)
        else:
            cmd = DocumentCommand.response(document=profile, meta=meta, identifier=self.group)
        self.__send_group_command(cmd=cmd, members=invite_list)

        # 1. send 'invite' command with new members to existed members
        cmd = GroupCommand.invite(group=self.group, members=invite_list)
        # 1.1. send to existed members
        self.__send_group_command(cmd=cmd, members=members)
        # 1.2. send to assistants
        self.__send_group_command(cmd=cmd, members=assistants)
        # 1.3. send to owner
        if owner is not None and owner not in members:
            self.__send_group_command(cmd=cmd, members=[owner])

        # 2. update local storage
        self.add_members(invite_list)

        # 3. send 'invite' command with all members to new members
        members = facebook.members(self.group)
        cmd = GroupCommand.invite(group=self.group, members=members)
        self.__send_group_command(cmd=cmd, members=invite_list)
        return True
Exemplo n.º 9
0
 def query_group(self, group: ID, users: List[ID]) -> bool:
     now = time.time()
     last = self.__group_queries.get(group, 0)
     if (now - last) < self.EXPIRES:
         return False
     if len(users) == 0:
         return False
     self.__group_queries[group] = now
     # query from users
     cmd = GroupCommand.query(group=group)
     checking = False
     for item in users:
         if self.__send_content(content=cmd, receiver=item):
             checking = True
     return checking
Exemplo n.º 10
0
 def __invite_members(self, members: list) -> InviteCommand:
     gid = self.__group.identifier
     return GroupCommand.invite(group=gid, members=members)
Exemplo n.º 11
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)