Example #1
0
    async def leave_group_not_owner(self, leave_member, leave_member_by, group):
        # leave group service for group not created in this server for user leave_member, called by leave_member_by
        logger.info('leave_group_not_owner')
        owner_workspace_domain = get_owner_workspace_domain()
        tmp_list_client = json.loads(group.group_clients)
        # PROCESS IN THIS SERVER
        # case new member is same server (not owner group)
        if leave_member.workspace_domain == owner_workspace_domain:
            # remove group client add more group client key
            group_client_key = GroupClientKey().get(group.id, leave_member.id)
            if group_client_key:
                group_client_key.delete()
            # remove group with owner group
            group.delete()

        # update all group with owner group
        lst_group = self.model.get_by_group_owner(group.owner_group_id)
        for group in lst_group:
            group.group_clients = group.group_clients
            group.total_member = len(tmp_list_client)
            group.update()

        # push notification for member active
        group_ids = (group.id for group in lst_group)
        list_clients = GroupClientKey().get_clients_in_groups(group_ids)
        push_service = NotifyPushService()

        for client in list_clients:
            data = {
                'client_id': client.GroupClientKey.client_id,
                'client_workspace_domain': owner_workspace_domain,
                'group_id': str(group.id),
                'leave_member': leave_member.id,
                'leave_member_display_name': leave_member.display_name,
                'leave_member_workspace_domain': leave_member.workspace_domain,
                'leave_member_by': leave_member_by.id,
                'leave_member_by_display_name': leave_member_by.display_name,
                'leave_member_by_workspace_domain': leave_member_by.workspace_domain
            }
            logger.info(data)
            # TODO: maybe handling push to owner
            await push_service.push_text_to_client(
                to_client_id=client.GroupClientKey.client_id,
                title="Member leave",
                body="user leave group",
                from_client_id=leave_member_by.id,
                notify_type="member_leave",
                data=json.dumps(data)
            )
        # END PROCESS IN THIS SERVER
        # CALL LEAVE MEMBER TO OWNER SERVER
        leave_group_request = group_pb2.LeaveGroupRequest(
            leave_member=leave_member,
            leave_member_by=leave_member_by,
            group_id=group.owner_group_id,
        )
        ClientGroup(group.owner_workspace_domain).leave_group(leave_group_request)
        # for compatible with old code, should be remove in future?
        return group_pb2.BaseResponse()
Example #2
0
 def group_register_client_key(self, client_id, request):
     # register a group key for client_id
     client_group_key = GroupClientKey().set_key(
         request.groupId, client_id, None, None, request.deviceId,
         request.clientKeyDistribution, request.senderKeyId,
         request.senderKey, request.publicKey, request.privateKey)
     new_group_key = client_group_key.add()
     if new_group_key is None:
         raise Exception(Message.REGISTER_CLIENT_GROUP_FAILED_AVAILABLE)
Example #3
0
    async def workspace_leave_group(self, leave_member, leave_member_by, group):
        # workspace called leave group, with additional info about leave_member, leave_member_by, group info
        logger.info('workspace_leave_group')

        owner_workspace_domain = get_owner_workspace_domain()
        tmp_list_client = json.loads(group.group_clients)

        owner_group_id = None
        group_this_workspace = self.get_group_info(group.group_id)
        if group_this_workspace:
            owner_group_id = group_this_workspace.owner_group_id

        # update all group with owner group
        if owner_group_id:
            lst_group = self.model.get_by_group_owner(owner_group_id)
            for gr in lst_group:
                gr.group_clients = group.group_clients
                gr.total_member = len(tmp_list_client)
                gr.update()

            # push notification for member active
            group_ids = (gr.id for gr in lst_group)
            list_clients = GroupClientKey().get_clients_in_groups(group_ids)
            push_service = NotifyPushService()

            for client in list_clients:
                data = {
                    'client_id': client.GroupClientKey.client_id,
                    'client_workspace_domain': owner_workspace_domain,
                    'group_id': str(client.GroupClientKey.group_id),
                    'leave_member': leave_member.id,
                    'leave_member_display_name': leave_member.display_name,
                    'leave_member_workspace_domain': leave_member.workspace_domain,
                    'leave_member_by': leave_member_by.id,
                    'leave_member_by_display_name': leave_member_by.display_name,
                    'leave_member_by_workspace_domain': leave_member_by.workspace_domain
                }
                logger.info(data)
                # TODO: maybe handling push to owwner
                await push_service.push_text_to_client(
                    to_client_id=client.GroupClientKey.client_id,
                    title="Member leave",
                    body="user leave group",
                    from_client_id=leave_member_by.id,
                    notify_type="member_leave",
                    data=json.dumps(data)
                )
                if leave_member.workspace_domain == owner_workspace_domain and leave_member.id == client.GroupClientKey.client_id:
                    client.GroupClientKey.delete()
                    #remove group
                    leave_member_group = self.get_group_info(client.GroupClientKey.group_id)
                    if leave_member_group:
                        leave_member_group.delete()

        # for compatible with old code, should be remove in future?
        return group_pb2.BaseResponse()
Example #4
0
    def update_call(self, update_type, group_id, from_client_id):
        # update a call from_client_id to group_id and notify all user in this group
        lst_client_in_groups = GroupClientKey().get_clients_in_group(group_id)
        notify_inapp_service = NotifyInAppService()
        for client in lst_client_in_groups:
            if client.User.id != from_client_id:
                notify_inapp_service.notify_client_update_call(
                    update_type, client.User.id, from_client_id, group_id)

        return True
Example #5
0
    def add_group_workspace(self, group_name, group_type, from_client_id, client_id, lst_client, owner_group_id,
                            owner_workspace_domain):
        # workspace call for create a mapping group with reference info (owner_group_id, owner_workspace_domain) to origin group
        self.model = GroupChat(
            group_name=group_name,
            group_type=group_type,
            group_clients=lst_client,
            owner_group_id=owner_group_id,
            owner_workspace_domain=owner_workspace_domain,
            created_by=from_client_id,
            updated_at=datetime.datetime.now()
        )
        new_group = self.model.add()
        # add to signal group key
        client_group_key = GroupClientKey().set_key(new_group.id, client_id)
        client_group_key.add()

        client_name = ""
        user_info = User().get(client_id)
        if user_info:
            client_name = user_info.display_name

        list_client_in_group = json.loads(lst_client)
        created_by_user = None
        for obj in list_client_in_group:
            if obj['id'] == from_client_id:
                created_by_user = obj
        # notify to client
        if group_type == "peer":
            self.notify_service.notify_invite_peer(client_id, from_client_id, new_group.id, owner_workspace_domain,
                                                   created_by_user['display_name'])
        else:
            self.notify_service.notify_invite_group(client_id, from_client_id, new_group.id, owner_workspace_domain,
                                                    created_by_user['display_name'])

        client_workspace_domain = get_owner_workspace_domain()
        return group_pb2.CreateGroupWorkspaceResponse(
            group_id=new_group.id,
            client_id=client_id,
            client_name=client_name,
            client_workspace_domain=client_workspace_domain
        )
Example #6
0
 def group_bulk_update_client_key(self, client_id, list_group_client_key):
     # update client_id's multi group keys
     is_updated = GroupClientKey().update_bulk_client_key(
         client_id, list_group_client_key)
     if not is_updated:
         raise Exception(Message.UPDATE_CLIENT_KEY_GROUPS_FAILED)
Example #7
0
 def __init__(self):
     super().__init__(None)
     self.group_client_key_model = GroupClientKey()
     self.peer_model = PeerClientKey()
     self.group_chat_model = GroupChat()
Example #8
0
class SignalService(BaseService):
    """
    SignalService, handling register/update/get/delete client peer/group key
    """
    def __init__(self):
        super().__init__(None)
        self.group_client_key_model = GroupClientKey()
        self.peer_model = PeerClientKey()
        self.group_chat_model = GroupChat()

    def peer_register_client_key(self, client_id, request):
        # register peer key for new client_id, with fully information of a peer key
        try:
            client_peer_key = PeerClientKey().set_key(
                client_id, request.registrationId, request.deviceId,
                request.identityKeyPublic, request.preKeyId, request.preKey,
                request.signedPreKeyId, request.signedPreKey,
                request.signedPreKeySignature, request.identityKeyEncrypted)
            key_added = client_peer_key.add()
            # Check chatting available and push notify inapp for refreshing key, this should be unneeded as client_id now must register peer key when create account
            self.client_update_key_notify(client_id)
        except Exception as e:
            logger.error(e)
            raise Exception(Message.REGISTER_CLIENT_SIGNAL_KEY_FAILED)

    def client_update_peer_key(self, client_id, request):
        # update peer key for client_id, with fully information of a new peer key
        client = self.peer_model.get_by_client_id(client_id)
        if client is None:
            raise Exception(Message.UPDATE_CLIENT_SIGNAL_KEY_FAILED)

        client.set_key(client_id, request.registrationId, request.deviceId,
                       request.identityKeyPublic, request.preKeyId,
                       request.preKey, request.signedPreKeyId,
                       request.signedPreKey, request.signedPreKeySignature,
                       request.identityKeyEncrypted)
        client.update()
        # Check chatting available and push notify inapp for refreshing key
        self.client_update_key_notify(client_id)

    def client_update_identity_key(self, client_id, identity_key_encrypted):
        # update identity_key_encrypted of peer key for client_id, useful when changing password - which should make identity_key_encrypted changing too
        # return old identity_key_encrypted for get back in case needed
        client = self.peer_model.get_by_client_id(client_id)
        if client is None:
            raise Exception(Message.UPDATE_CLIENT_SIGNAL_KEY_FAILED)

        old_identity_key_encrypted = client.identity_key_encrypted
        client.identity_key_encrypted = identity_key_encrypted
        client.update()
        return old_identity_key_encrypted

    def peer_get_client_key(self, client_id):
        # get peer key of client_id
        return self.peer_model.get_by_client_id(client_id)

    def group_register_client_key(self, client_id, request):
        # register a group key for client_id
        client_group_key = GroupClientKey().set_key(
            request.groupId, client_id, None, None, request.deviceId,
            request.clientKeyDistribution, request.senderKeyId,
            request.senderKey, request.publicKey, request.privateKey)
        new_group_key = client_group_key.add()
        if new_group_key is None:
            raise Exception(Message.REGISTER_CLIENT_GROUP_FAILED_AVAILABLE)

    def group_bulk_update_client_key(self, client_id, list_group_client_key):
        # update client_id's multi group keys
        is_updated = GroupClientKey().update_bulk_client_key(
            client_id, list_group_client_key)
        if not is_updated:
            raise Exception(Message.UPDATE_CLIENT_KEY_GROUPS_FAILED)

    def group_get_client_key(self, group_id, client_id):
        # get client_id's group key in group_id
        client_key = self.group_client_key_model.get(group_id, client_id)
        if client_key:
            return client_key
        return None

    def group_by_owner_get_client_key(self, group_id, client_id):
        # get client_id's group key in owner_group with group_id
        client_key = self.group_chat_model.get_client_key_by_owner_group(
            group_id, client_id)
        if client_key:
            return client_key
        return None

    def group_get_all_client_key(self, group_id):
        # get all client's group keys in group_id
        return self.group_client_key_model.get_all_in_group(group_id)

    def client_update_key_notify(self, client_id):
        # list all client in peer chat with client_id about client_id's updating key event
        try:
            lst_group_peer = self.group_chat_model.get_joined_group_type(
                client_id, "peer")
            notify_inapp_service = NotifyInAppService()
            for group_peer in lst_group_peer:
                if group_peer.group_clients:
                    lst_client_id = ast.literal_eval(group_peer.group_clients)
                    for client_peer_id in lst_client_id:
                        if client_peer_id != client_id:
                            notify_inapp_service.notify_client_update_peer_key(
                                client_peer_id, client_id, group_peer.id)
        except Exception as e:
            logger.error(e)

    def delete_client_peer_key(self, client_id):
        # delete a client peer key
        client_peer_key = self.peer_model.get_by_client_id(client_id)
        client_peer_key.delete()
        return True
Example #9
0
    async def workspace_add_member(self, added_member_info, adding_member_info, owner_group_info):
        # workspace adding member to group, with additional info about adding member, added member and original group
        logger.info('workspace_add_member')

        owner_workspace_domain = get_owner_workspace_domain()
        tmp_list_client = json.loads(owner_group_info.group_clients)

        is_member_workspace = False
        ref_group_id = None
        # create for new member
        if added_member_info.workspace_domain == owner_workspace_domain:
            is_member_workspace = True
            # add group with owner group
            self.model = GroupChat(
                owner_group_id=owner_group_info.group_id,
                owner_workspace_domain=owner_group_info.group_workspace_domain,
                group_name=owner_group_info.group_name,
                group_type=owner_group_info.group_type,
                group_clients=owner_group_info.group_clients,
                group_rtc_token="",
                total_member=len(tmp_list_client),
                created_by=owner_group_info.created_by,
            )
            new_group = self.model.add()
            ref_group_id = new_group.id
            # add more group client key
            group_client_key = GroupClientKey().set_key(
                new_group.id, added_member_info.id)
            group_client_key.add()

        # update all group with owner group
        lst_group = self.model.get_by_group_owner(owner_group_info.group_id)
        for group in lst_group:
            group.group_clients = owner_group_info.group_clients
            group.total_member = len(tmp_list_client)
            group.update()

        # push notification for member active
        group_ids = (group.id for group in lst_group)
        list_clients = GroupClientKey().get_clients_in_groups(group_ids)
        push_service = NotifyPushService()

        for client in list_clients:
            data = {
                'client_id': client.GroupClientKey.client_id,
                'client_workspace_domain': owner_workspace_domain,
                'group_id': str(client.GroupClientKey.group_id),
                'added_member_id': added_member_info.id,
                'added_member_display_name': added_member_info.display_name,
                'added_member_workspace_domain': added_member_info.workspace_domain,
                'adding_member_id': adding_member_info.id,
                'adding_member_display_name': adding_member_info.display_name,
                'adding_member_workspace_domain': adding_member_info.workspace_domain
            }
            logger.info(data)
            # TODO: maybe handling push to owwner
            await push_service.push_text_to_client(
                to_client_id=client.GroupClientKey.client_id,
                title="Member Add",
                body="A user has been added to the group",
                from_client_id=adding_member_info.id,
                notify_type="new_member",
                data=json.dumps(data)
            )

        return group_pb2.AddMemberWorkspaceResponse(
            is_member_workspace=is_member_workspace,
            ref_group_id=ref_group_id
        )
Example #10
0
    async def add_member_to_group_owner(self, added_member_info, adding_member_info, group):
        # adding member to group created in this server, with additional info about adding member and added member
        logger.info('add_member_to_group_owner')
        owner_workspace_domain = get_owner_workspace_domain()

        # add more group client key for group owner
        client_workspace_domain = None
        if added_member_info.workspace_domain != owner_workspace_domain:
            client_workspace_domain = added_member_info.workspace_domain

        group_client_key = GroupClientKey().set_key(
            group.id, added_member_info.id, client_workspace_domain, added_member_info.ref_group_id).add()

        # push notification for other member in server
        lst_client_in_group = self.get_clients_in_group(group.id)
        push_service = NotifyPushService()
        for client in lst_client_in_group:
            if client.GroupClientKey.client_workspace_domain is None or client.GroupClientKey.client_workspace_domain == owner_workspace_domain:
                if client.GroupClientKey.client_id != adding_member_info.id:
                    data = {
                        'client_id': client.GroupClientKey.client_id,
                        'client_workspace_domain': owner_workspace_domain,
                        'group_id': str(group.id),
                        'added_member_id': added_member_info.id,
                        'added_member_display_name': added_member_info.display_name,
                        'added_member_workspace_domain': owner_workspace_domain,
                        'adding_member_id': adding_member_info.id,
                        'adding_member_display_name': adding_member_info.display_name,
                        'adding_member_workspace_domain': owner_workspace_domain
                    }
                    logger.info(data)
                    # TODO: maybe handling push to owwner
                    await push_service.push_text_to_client(
                        to_client_id=client.GroupClientKey.client_id,
                        title="Member Add",
                        body="A user has been added to the group",
                        from_client_id=adding_member_info.id,
                        notify_type="new_member",
                        data=json.dumps(data)
                    )

        # request add member to other server
        informed_workspace_domain = []
        for client in lst_client_in_group:
            if client.GroupClientKey.client_workspace_domain and client.GroupClientKey.client_workspace_domain != owner_workspace_domain \
                    and client.GroupClientKey.client_workspace_domain != adding_member_info.workspace_domain:  # prevent loop call

                if client.GroupClientKey.client_workspace_domain in informed_workspace_domain:
                    continue
                informed_workspace_domain.append(client.GroupClientKey.client_workspace_domain)

                owner_group_req = group_pb2.GroupInfo(
                    group_id=group.id,
                    group_name=group.group_name,
                    group_type=group.group_type,
                    group_clients=group.group_clients,
                    group_workspace_domain=owner_workspace_domain,
                    created_by=group.created_by,
                )
                request = group_pb2.AddMemberWorkspaceRequest(
                    added_member_info=added_member_info,
                    adding_member_info=adding_member_info,
                    owner_group=owner_group_req
                )
                logger.info(
                    "call add member to workspace domain {}".format(client.GroupClientKey.client_workspace_domain))
                response = ClientGroup(client.GroupClientKey.client_workspace_domain).workspace_add_member(request)
                if response.is_member_workspace:
                    logger.info("update ref_group to main server {}".format(response.ref_group_id))
                    group_client_key.client_workspace_group_id = response.ref_group_id
                    group_client_key.update()

        # for compatible with old code, should be remove in future?
        return group_pb2.BaseResponse()
Example #11
0
    async def add_member_to_group_not_owner(self, added_member_info, adding_member_info, group):
        # adding member to group not created in this server, with additional info about adding member and added member
        logger.info('add_member_to_group_not_owner')

        owner_workspace_domain = get_owner_workspace_domain()
        tmp_list_client = json.loads(group.group_clients)

        # PROCESS IN THIS SERVER
        # case new member is same server (not owner group)
        if added_member_info.workspace_domain == owner_workspace_domain:
            # add group with owner group
            self.model = GroupChat(
                owner_group_id=group.owner_group_id,
                owner_workspace_domain=group.owner_workspace_domain,
                group_name=group.group_name,
                group_type=group.group_type,
                group_clients=group.group_clients,
                group_rtc_token="",
                total_member=len(tmp_list_client),
                created_by=group.created_by,
            )
            new_group = self.model.add()
            added_member_info.ref_group_id = new_group.id

            # add more group client key
            group_client_key = GroupClientKey().set_key(
                new_group.id, added_member_info.id)
            group_client_key.add()

        # update all group with owner group
        lst_group = self.model.get_by_group_owner(group.owner_group_id)
        for group in lst_group:
            group.group_clients = group.group_clients
            group.total_member = len(tmp_list_client)
            group.update()

        # push notification for member active
        group_ids = (group.id for group in lst_group)
        list_clients = GroupClientKey().get_clients_in_groups(group_ids)
        push_service = NotifyPushService()

        for client in list_clients:
            data = {
                'client_id': client.GroupClientKey.client_id,
                'client_workspace_domain': owner_workspace_domain,
                'group_id': str(client.GroupClientKey.group_id),
                'added_member_id': added_member_info.id,
                'added_member_display_name': added_member_info.display_name,
                'added_member_workspace_domain': added_member_info.workspace_domain,
                'adding_member_id': adding_member_info.id,
                'adding_member_display_name': adding_member_info.display_name,
                'adding_member_workspace_domain': adding_member_info.workspace_domain
            }
            logger.info(data)
            # TODO: maybe handling push to owwner
            await push_service.push_text_to_client(
                to_client_id=client.GroupClientKey.client_id,
                title="Member Add",
                body="A user has been added to the group",
                from_client_id=adding_member_info.id,
                notify_type="new_member",
                data=json.dumps(data)
            )
        # END PROCESS IN THIS SERVER
        # CALL ADD MEMBER TO OWNER SERVER
        add_member_request = group_pb2.AddMemberRequest(
            added_member_info=added_member_info,
            adding_member_info=adding_member_info,
            group_id=group.owner_group_id,
        )
        ClientGroup(group.owner_workspace_domain).add_member(add_member_request)

        # for compatible with old code, should be remove in future?
        return group_pb2.BaseResponse()
Example #12
0
 def get_clients_in_group_owner(self, group_owner_id):
     # get all client in groups
     lst_group = self.model.get_by_group_owner(group_owner_id)
     group_ids = (group.id for group in lst_group)
     return GroupClientKey().get_clients_in_groups(group_ids)
Example #13
0
 def get_clients_in_group(self, group_id):
     # get all client in group
     return GroupClientKey().get_clients_in_group(group_id)
Example #14
0
    def add_group(self, group_name, group_type, lst_client, created_by):
        # service for create new group with following info:
        # group_name: name of group in request, using for searching group
        # group_type: type of group in request, must be one of this values: [peer/group]
        # lst_client: list of client in this group
        # create_by: user_id of creator
        tmp_list_client = []
        created_by_user = None
        for obj in lst_client:
            if obj.id == created_by:
                created_by_user = obj
            tmp_list_client.append(
                {"id": obj.id, "display_name": obj.display_name, "workspace_domain": obj.workspace_domain,
                 "status": "active"})

        self.model = GroupChat(
            group_name=group_name,
            group_type=group_type,
            group_clients=json.dumps(tmp_list_client),
            group_rtc_token=secrets.token_hex(10),
            total_member=len(tmp_list_client),
            created_by=created_by,
            updated_at=datetime.datetime.now()
        )
        new_group = self.model.add()

        res_obj = group_pb2.GroupObjectResponse(
            group_id=new_group.id,
            group_name=new_group.group_name,
            group_type=new_group.group_type,
            group_avatar=new_group.group_avatar,
            created_by_client_id=new_group.created_by,
            created_at=int(new_group.created_at.timestamp() * 1000),
            updated_by_client_id=new_group.updated_by,
            group_rtc_token=new_group.group_rtc_token

        )
        if new_group.updated_at is not None:
            res_obj.updated_at = int(new_group.updated_at.timestamp() * 1000)

        owner_workspace_domain = get_owner_workspace_domain()
        for obj in lst_client:
            # list client in group
            client_in = group_pb2.ClientInGroupResponse(
                id=obj.id,
                display_name=obj.display_name,
                workspace_domain=obj.workspace_domain,
                status="active"
            )
            res_obj.lst_client.append(client_in)

            # add to signal group key
            if obj.workspace_domain == owner_workspace_domain:
                client_group_key = GroupClientKey().set_key(new_group.id, obj.id)
                client_group_key.add()
                # notify per client
                if group_type == "peer":
                    self.notify_service.notify_invite_peer(
                        obj.id,
                        created_by,
                        new_group.id,
                        created_by_user.workspace_domain,
                        created_by_user.display_name
                    )
                else:
                    self.notify_service.notify_invite_group(
                        obj.id,
                        created_by,
                        new_group.id,
                        created_by_user.workspace_domain,
                        created_by_user.display_name
                    )
            else:
                # need to call other workspace and create group key
                request = group_pb2.CreateGroupWorkspaceRequest(
                    group_name=group_name,
                    group_type=group_type,
                    from_client_id=created_by,
                    client_id=obj.id,
                    lst_client=new_group.group_clients,
                    owner_group_id=new_group.id,
                    owner_workspace_domain=owner_workspace_domain
                )

                group_res_object = \
                    ClientGroup(obj.workspace_domain).create_group_workspace(
                        request
                    )
                client_group_key = GroupClientKey().set_key(
                    new_group.id, obj.id,
                    group_res_object.client_workspace_domain,
                    group_res_object.group_id)
                client_group_key.add()
        return res_obj
Example #15
0
    def get_group(self, group_id, client_id):
        # get infor of client related to group stored in database by its group_id and client_id
        stored_client_key = GroupClientKey().get(group_id, client_id)
        group = self.model.get(group_id)
        if group is not None:
            obj = group.GroupChat
            res_obj = group_pb2.GroupObjectResponse(
                group_id=obj.id,
                group_name=obj.group_name,
                group_type=obj.group_type,
                group_avatar=obj.group_avatar,
                created_by_client_id=obj.created_by,
                created_at=int(obj.created_at.timestamp() * 1000),
                updated_by_client_id=obj.updated_by,
                group_rtc_token=obj.group_rtc_token
            )
            if obj.updated_at is not None:
                res_obj.updated_at = int(obj.updated_at.timestamp() * 1000)

            # list client in group
            group_clients = json.loads(obj.group_clients)

            for client in group_clients:
                client_in = group_pb2.ClientInGroupResponse(
                    id=client['id'],
                    display_name=client['display_name'],
                    workspace_domain=client['workspace_domain'],
                    status=client['status']
                )
                res_obj.lst_client.append(client_in)

            if stored_client_key is not None:
                res_obj.client_key.workspace_domain = get_owner_workspace_domain()
                res_obj.client_key.clientId = stored_client_key.client_id
                if stored_client_key.device_id is not None:
                    res_obj.client_key.deviceId = stored_client_key.device_id
                if stored_client_key.client_key is not None:
                    res_obj.client_key.clientKeyDistribution = stored_client_key.client_key
                if stored_client_key.client_sender_key_id is not None:
                    res_obj.client_key.senderKeyId = stored_client_key.client_sender_key_id
                if stored_client_key.client_sender_key is not None:
                    res_obj.client_key.senderKey = stored_client_key.client_sender_key
                if stored_client_key.client_public_key is not None:
                    res_obj.client_key.publicKey = stored_client_key.client_public_key
                if stored_client_key.client_private_key is not None:
                    res_obj.client_key.privateKey = stored_client_key.client_private_key

            if obj.last_message_at:
                res_obj.last_message_at = int(obj.last_message_at.timestamp() * 1000)

            # get last message
            if group.Message:
                last_message = group.Message
                res_obj.last_message.id = last_message.id
                res_obj.last_message.group_id = last_message.group_id
                res_obj.last_message.from_client_id = last_message.from_client_id
                res_obj.last_message.message = last_message.message
                res_obj.last_message.created_at = int(last_message.created_at.timestamp() * 1000)

                if last_message.client_id:
                    res_obj.last_message.client_id = last_message.client_id
                if last_message.updated_at:
                    res_obj.last_message.updated_at = int(last_message.updated_at.timestamp() * 1000)
                if last_message.client_id:
                    res_obj.last_message.group_type = "peer"
                else:
                    res_obj.last_message.group_type = "group"

            return res_obj
        else:
            return None