Skip to main content

Decentralized Instant Messaging Protocol

Project description

Decentralized Instant Messaging Protocol (Python)

license Version PRs Welcome Platform

Talk is cheap, show you the codes!

Dependencies

pip3 install dimp

Common Extensions

facebook.py

class Facebook(Barrack):
    """ Access database to load/save user's private key, meta and profiles """

    def save_private_key(self, private_key: PrivateKey, identifier: ID) -> bool:
        # TODO: save private key into safety storage
        pass

    def save_meta(self, meta: Meta, identifier: ID) -> bool:
        if not meta.match_identifier(identifier):
            return False
        # TODO: save meta to local/persistent storage
        pass

    def save_profile(self, profile: Profile) -> bool:
        if not self.verify_profile(profile):
            return False
        # TODO: save to local storage
        pass

    def verify_profile(self, profile: Profile) -> bool:
        if profile is None:
            return False
        elif profile.valid:
            # already verified
            return True
        identifier = profile.identifier
        meta = None
        if identifier.type.is_user():
            # verify with user's meta.key
            meta = self.meta(identifier=identifier)
        elif identifier.type.is_group():
            # verify with group owner's meta.key
            group = self.group(identifier=identifier)
            if group is not None:
                meta = self.meta(identifier=group.owner)
        if meta is not None:
            return profile.verify(public_key=meta.key)

    #
    #   SocialNetworkDelegate
    #
    def user(self, identifier: ID) -> User:
        entity = super().user(identifier=identifier)
        if entity is not None:
            return entity
        meta = self.meta(identifier=identifier)
        if meta is not None:
            entity = User(identifier=identifier)
            self.cache_user(user=entity)
            return entity

    def group(self, identifier: ID) -> Group:
        entity = super().group(identifier=identifier)
        if entity is not None:
            return entity
        meta = self.meta(identifier=identifier)
        if meta is not None:
            entity = Group(identifier=identifier)
            self.cache_group(group=entity)
            return entity


#
#  global
#
facebook = Facebook()

keystore.py

class KeyStore(KeyCache):
    """ For reuse symmetric key """

    def save_keys(self, key_map: dict) -> bool:
        # TODO: save to local cache
        pass

    def load_keys(self) -> dict:
        # TODO: load from local cache
        pass


#
#  global
#
keystore = KeyStore()

messenger.py

class MessengerDelegate(metaclass=ABCMeta):

    @abstractmethod
    def send_package(self, data: bytes) -> bool:
        """
        Send out a data package onto network

        :param data:    package data
        :return: True on success
        """
        pass


class Messenger(Transceiver, ConnectionDelegate):
    """ Transform and send/receive message """

    def __init__(self):
        super().__init__()
        self.delegate: MessengerDelegate = None

    @property
    def current_user(self) -> Optional[User]:
        # TODO: get current user from context
        pass

    #
    #  Conveniences
    #
    def encrypt_sign(self, msg: InstantMessage) -> ReliableMessage:
        # 1. encrypt 'content' to 'data' for receiver
        s_msg = self.encrypt_message(msg=msg)
        # 1.1. check group
        group = msg.content.group
        if group is not None:
            # NOTICE: this help the receiver knows the group ID
            #         when the group message separated to multi-messages,
            #         if don't want the others know you are the group members,
            #         remove it.
            s_msg.envelope.group = group
        # 1.2. copy content type to envelope
        #      NOTICE: this help the intermediate nodes to recognize message type
        s_msg.envelope.type = msg.content.type
        # 2. sign 'data' by sender
        r_msg = self.sign_message(msg=s_msg)
        # OK
        return r_msg

    def verify_decrypt(self, msg: ReliableMessage) -> Optional[InstantMessage]:
        # 1. verify 'data' with 'signature'
        s_msg = self.verify_message(msg=msg)
        if s_msg is None:
            # failed to verify message
            return None
        # 2. decrypt 'data' to 'content'
        i_msg = self.decrypt_message(msg=s_msg)
        # OK
        return i_msg

    #
    #   Sending
    #
    def send_content(self, content: Content, receiver: ID) -> bool:
        sender = self.current_user.identifier
        i_msg = InstantMessage.new(content=content, sender=sender, receiver=receiver)
        return self.send_message(msg=i_msg)

    def send_message(self, msg: InstantMessage) -> bool:
        r_msg = messenger.encrypt_sign(msg=msg)
        data = messenger.serialize_message(msg=r_msg)
        package = data + b'\n'
        self.delegate.send_package(data=package)

    #
    #   ConnectionDelegate
    #
    def received_package(self, data: bytes) -> Optional[bytes]:
        """ Processing received message package """
        r_msg = self.deserialize_message(data=data)
        response = self.process_message(msg=r_msg)
        if response is None:
            # nothing to response
            return None
        # response to the sender
        sender = self.current_user.identifier
        receiver = self.barrack.identifier(r_msg.envelope.sender)
        i_msg = InstantMessage.new(content=response, sender=sender, receiver=receiver)
        msg_r = self.encrypt_sign(msg=i_msg)
        return self.serialize_message(msg=msg_r)

    def process_message(self, msg: ReliableMessage) -> Optional[Content]:
        # TODO: verify, decrypt and process this message
        #       return a receipt as response
        pass


#
#  global
#
messenger = Messenger()
messenger.barrack = facebook
messenger.key_cache = keystore

User Account

register.py

def register(username: str) -> User:
    # 1. generate private key
    sk = PrivateKey({'algorithm': 'RSA'})

    # 2. generate meta with username(as seed) and private key
    meta = Meta.generate(private_key=sk, seed=username)

    # 3. generate ID with network type by meta
    identifier = meta.generate_identifier(network=network)

    # 4. save private key and meta info
    facebook.save_private_key(private_key=sk, identifier=identifier)
    facebook.save_meta(meta=meta, identifier=identifier)

    # 5. create user with ID
    return facebook.user(identifier)

Messaging

send.py

def pack(content: Content, sender: ID, receiver: ID) -> bytes:
    i_msg = InstantMessage.new(content=content, sender=sender, receiver=receiver)
    r_msg = messenger.encrypt_sign(msg=i_msg)
    return messenger.serialize_message(msg=r_msg)


def send(text: str, receiver: str, sender: str) -> bool:
    sender = facebook.identifier(sender)
    receiver = facebook.identifier(receiver)
    content = TextContent.new(text=text)
    data = pack(content=content, sender=sender, receiver=receiver)
    request = data + b'\n'
    # TODO: send out the request data


if __name__ == '__main__':
    moki = 'moki@4WDfe3zZ4T7opFSi3iDAKiuTnUHjxmXekk'
    hulk = 'hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj'
    # Say Hi
    send(text='Hello world!', sender=moki, receiver=hulk)

receive.py

def unpack(data: bytes) -> InstantMessage:
    r_msg = messenger.deserialize_message(data=data)
    return messenger.verify_decrypt(r_msg)


def process(content: Content, sender: ID) -> Content:
    # TODO: process message content from sender
    pass


def receive(pack: bytes) -> Content:
    i_msg = unpack(data)
    sender = facebook.identifier(i_msg.envelope.sender)
    return process(content=i_msg.content, sender=sender)

Copyright © 2019 Albert Moky

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dimp-0.8.1.tar.gz (19.5 kB view details)

Uploaded Source

Built Distribution

dimp-0.8.1-py3-none-any.whl (32.9 kB view details)

Uploaded Python 3

File details

Details for the file dimp-0.8.1.tar.gz.

File metadata

  • Download URL: dimp-0.8.1.tar.gz
  • Upload date:
  • Size: 19.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.0 CPython/3.7.2

File hashes

Hashes for dimp-0.8.1.tar.gz
Algorithm Hash digest
SHA256 7d821b5afb4eae78cd23eae0698afbb858624561a9a7cb09ca80bcc3c45e18c2
MD5 ee732263dbb39f608b8bf06c0b16bdeb
BLAKE2b-256 600753b5724b6f781c60292b8109c1797ff26d7e0234b8fd7c18af837aa006b3

See more details on using hashes here.

File details

Details for the file dimp-0.8.1-py3-none-any.whl.

File metadata

  • Download URL: dimp-0.8.1-py3-none-any.whl
  • Upload date:
  • Size: 32.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.12.1 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.6.3 requests-toolbelt/0.8.0 tqdm/4.29.0 CPython/3.7.2

File hashes

Hashes for dimp-0.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4ede90d1e54794f010532067bdf25205af86a0906c85c02777f1678b848d0cfe
MD5 d56445f34bcca3225852324e028af956
BLAKE2b-256 21f41fbe4135fe97ee3331134ace3b402bf884ac6807f7532de7d06b03748cad

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page