Decentralized Instant Messaging Protocol
Project description
Decentralized Instant Messaging Protocol (Python)
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)
Built Distribution
dimp-0.8.1-py3-none-any.whl
(32.9 kB
view details)
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
Algorithm | Hash digest | |
---|---|---|
SHA256 | 7d821b5afb4eae78cd23eae0698afbb858624561a9a7cb09ca80bcc3c45e18c2 |
|
MD5 | ee732263dbb39f608b8bf06c0b16bdeb |
|
BLAKE2b-256 | 600753b5724b6f781c60292b8109c1797ff26d7e0234b8fd7c18af837aa006b3 |
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
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4ede90d1e54794f010532067bdf25205af86a0906c85c02777f1678b848d0cfe |
|
MD5 | d56445f34bcca3225852324e028af956 |
|
BLAKE2b-256 | 21f41fbe4135fe97ee3331134ace3b402bf884ac6807f7532de7d06b03748cad |