Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

chat.dim:DIMP

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

chat.dim:DIMP

New Protocol designed for decentralized instant messaging.

  • 1.1.0
  • Source
  • Maven
  • Socket score

Version published
Maintainers
1
Source

Decentralized Instant Messaging Protocol (Java)

license Version PRs Welcome Platform

Talk is cheap, show you the codes!

Dependencies

build.gradle

allprojects {
    repositories {
        jcenter()
        mavenCentral()
    }
}

dependencies {

    // https://bintray.com/dimchat/core/dimp
    compile 'chat.dim:DIMP:0.5.3'
//  implementation group: 'chat.dim', name: 'DIMP', version: '0.5.3'

}

pom.xml

<dependencies>

    <!-- https://mvnrepository.com/artifact/chat.dim/DIMP -->
    <dependency>
        <groupId>chat.dim</groupId>
        <artifactId>DIMP</artifactId>
        <version>0.5.3</version>
        <type>pom</type>
    </dependency>

</dependencies>

Common Extensions

Facebook.java

/**
 *  Access database to load/save user's private key, meta and profiles
 */
public class Facebook extends Barrack {
    private static final Facebook ourInstance = new Facebook();
    public static Facebook getInstance() { return ourInstance; }
    
    private Facebook() {
        super();
        //...
    }
    
    public boolean savePrivateKey(PrivateKey privateKey, ID identifier) {
        if (!getMeta(identifier).getKey().matches(privateKey)) {
            return false;
        }
        // TODO: save private key into safety storage
        return true;
    }
    
    public boolean saveMeta(Meta meta, ID identifier) {
        if (!meta.matches(identifier)) {
            return false;
        }
        // TODO: save meta to local/persistent storage
        return true;
    }
    
    public boolean saveProfile(Profile profile) {
        if (!verifyProfile(profile)) {
            return false;
        }
        // TODO: save profile in local storage
        return true;
    }
    
    private boolean verifyProfile(Profile profile) {
        if (profile == null) {
            return false;
        }
        ID identifier = profile.identifier;
        NetworkType type = identifier.getType();
        Meta meta = null;
        if (type.isUser()) {
            // verify with user's meta.key
            meta = getMeta(identifier);
        } else if (type.isGroup()) {
            // verify with group owner's meta.key
            Group group = getGroup(identifier);
            if (group != null) {
                meta = getMeta(group.getOwner());
            }
        }
        return meta != null && profile.verify(meta.key);
    }
    
    //-------- Barrack
    
    @Override
    protected User createUser(ID identifier) {
        if (identifier.isBroadcast()) {
            // create user 'anyone@anywhere'
            return new User(identifier);
        }
        // TODO: check user type
        NetworkType type = identifier.getType();
        if (type.isPerson()) {
            return new User(identifier);
        }
        if (type.isRobot()) {
            return new Robot(identifier);
        }
        if (type.isStation()) {
            return new Station(identifier);
        }
        throw new TypeNotPresentException("Unsupported user type: " + type, null);
    }

    @Override
    protected Group createGroup(ID identifier) {
        if (identifier.isBroadcast()) {
            // create group 'everyone@everywhere'
            return new Group(identifier);
        }
        // TODO: check group type
        NetworkType type = identifier.getType();
        if (type == NetworkType.Polylogue) {
            return new Polylogue(identifier);
        }
        if (type == NetworkType.Chatroom) {
            return new Chatroom(identifier);
        }
        if (type.isProvider()) {
            return new ServiceProvider(identifier);
        }
        throw new TypeNotPresentException("Unsupported group type: " + type, null);
    }
    
    static {
        // mkm.Base64 (for Android)
        chat.dim.format.Base64.coder = new chat.dim.format.BaseCoder() {
            @Override
            public String encode(byte[] data) {
                return android.util.Base64.encodeToString(data, android.util.Base64.DEFAULT);
            }
            
            @Override
            public byte[] decode(String string) {
                return android.util.Base64.decode(string, android.util.Base64.DEFAULT);
            }
        };
    }
}

KeyStore.java

/**
 *  For reusable symmetric key, with direction (from, to)
 */
public class KeyStore extends KeyCache {
    private static final KeyStore ourInstance = new KeyStore();
    public static KeyStore getInstance() { return ourInstance; }
    
    private KeyStore() {
        super();
    }

    @Override
    public boolean saveKeys(Map keyMap) {
        // TODO: save symmetric keys into persistent storage
        return false;
    }

    @Override
    public Map loadKeys() {
        // TODO: load symmetric keys from persistent storage
        return null;
    }

    @Override
    public SymmetricKey reuseCipherKey(ID sender, ID receiver, SymmetricKey key) {
        return super.reuseCipherKey(sender, receiver, key);
    }
}

Messenger.java

/**
 *  Transform and send message
 */
public class Messenger extends Transceiver implements ConnectionDelegate {
    private static final Messenger ourInstance = new Messenger();
    public static Messenger getInstance() { return ourInstance; }
    
    private Messenger()  {
        super();
        setEntityDelegate(Facebook.getInstance());
        setCipherKeyDelegate(KeyStore.getInstance());
    }
    
    public MessengerDelegate delegate = null;

    @Override
    public byte[] encryptContent(Content content, Map<String, Object> password, InstantMessage iMsg) {
        SymmetricKey key = SymmetricKey.getInstance(password);
        // check attachment for File/Image/Audio/Video message content
        if (content instanceof FileContent) {
            FileContent file = (FileContent) content;
            byte[] data = file.getData();
            // encrypt and upload file data onto CDN and save the URL in message content
            data = key.encrypt(data);
            String url = delegate.uploadFileData(data, iMsg);
            if (url != null) {
                // replace 'data' with 'URL'
                file.setUrl(url);
                file.setData(null);
            }
        }
        return super.encryptContent(content, key, iMsg);
    }

    @Override
    public Content decryptContent(byte[] data, Map<String, Object> password, SecureMessage sMsg) {
        SymmetricKey key = SymmetricKey.getInstance(password);
        Content content = super.decryptContent(data, password, sMsg);
        if (content == null) {
            return null;
        }
        // check attachment for File/Image/Audio/Video message content
        if (content instanceof FileContent) {
            FileContent file = (FileContent) content;
            InstantMessage iMsg = new InstantMessage(content, sMsg.envelope);
            // download from CDN
            byte[] fileData = delegate.downloadFileData(file.getUrl(), iMsg);
            if (fileData == null) {
                // save symmetric key for decrypted file data after download from CDN
                file.setPassword(key);
            } else {
                // decrypt file data
                file.setData(key.decrypt(fileData));
                file.setUrl(null);
            }
        }
        return content;
    }
    
    //
    //  Send message
    //
    public boolean sendMessage(InstantMessage iMsg, Callback callback, boolean split) {
        // Send message (secured + certified) to target station
        ReliableMessage rMsg = signMessage(encryptMessage(iMsg));
        Facebook facebook = getFacebook();
        ID receiver = facebook.getID(iMsg.envelope.receiver);
        boolean OK = true;
        if (split && receiver.getType().isGroup()) {
            // split for each members
            List<ID> members = facebook.getMembers(receiver);
            List<SecureMessage> messages;
            if (members == null || members.size() == 0) {
                messages = null;
            } else {
                messages = rMsg.split(members);
            }
            if (messages == null) {
                // failed to split message, send it to group
                OK = sendMessage(rMsg, callback);
            } else {
                for (Message msg : messages) {
                    if (!sendMessage((ReliableMessage) msg, callback)) {
                        OK = false;
                    }
                }
            }
        } else {
            OK = sendMessage(rMsg, callback);
        }
        // TODO: if OK, set iMsg.state = sending; else set iMsg.state = waiting
        return OK;
    }

    private boolean sendMessage(ReliableMessage rMsg, Callback callback) {
        byte[] data = serializeMessage(rMsg);
        MessageCallback handler = new MessageCallback(rMsg, callback);
        return getDelegate().sendPackage(data, handler);
    }
    
    //
    //  ConnectionDelegate
    //
    @Override
    public byte[] onReceiveDataPackage(byte[] data) {
        // 1. deserialize message
        ReliableMessage rMsg = deserializeMessage(data);
        // 2. process message
        Content response = process(rMsg);
        if (response == null) {
            // nothing to response
            return null;
        }
        // 3. pack response
        Facebook facebook = getFacebook();
        User user = facebook.getCurrentUser();
        ID receiver = facebook.getID(rMsg.envelope.sender);
        InstantMessage iMsg = new InstantMessage(response, user.identifier, receiver);
        ReliableMessage nMsg = signMessage(encryptMessage(iMsg));
        // serialize message
        return serializeMessage(nMsg);
    }

    protected Content process(ReliableMessage rMsg) {
        // TODO: try to verify/decrypt message and process it
        return null;
    }
}

User Account

Register.java

    public User register(String username) {
        // 1. generate private key
        PrivateKey sk = PrivateKey.generate(PrivateKey.RSA);
        
        // 2. generate meta with username(as seed) and private key
        String seed = username;
        Meta meta = Meta.generate(Meta.VersionDefault, sk, seed);
        
        // 3. generate ID with network type by meta
        ID identifier = meta.generateID(NetworkType.Main);
        
        // 4. save private key and meta info
        facebook.savePrivateKey(sk, identifier);
        facebook.saveMeta(meta, identifier);
        
        // 5. create user with ID
        return facebook.getUser(identifier);
    }

Messaging

Send.java

    public ReliableMessage pack(Content content, ID sender, ID receiver) {
        // 1. create InstantMessage
        InstantMessage iMsg = new InstantMessage(content, sender, receiver);

        // 2. encrypt 'content' to 'data' for receiver
        SecureMessage sMsg = messenger.encryptMessage(iMsg);

        // 3. sign 'data' by sender
        ReliableMessage rMsg = messenger.signMessage(sMsg);

        // OK
        return rMsg;
    }
    
    public boolean send(Content content, ID sender, ID receiver) {
        // 1. pack message
        ReliableMessage rMsg = pack(content, sender, receiver);
        
        // 2. callback handler
        CompletionHandler handler = new CompletionHandler() {
            @Override
            public void onSuccess() {
                // TODO: remove task
            }

            @Override
            public void onFailed(Error error) {
                // TODO: try again
            }
        };
        
        // 3. encode and send out
        return messenger.sendMessage(rMsg, callback);
    }
    
    public void test() {
        ID moki = facebook.getID("moki@4WDfe3zZ4T7opFSi3iDAKiuTnUHjxmXekk");
        ID hulk = facebook.getID("hulk@4YeVEN3aUnvC1DNUufCq1bs9zoBSJTzVEj");
        
        Content content = new TextContent("Hello world!");
        send(content, moki, hulk);
    }

Receive.java

    public Content unpack(ReliableMessage rMsg) {
        // 1. verify 'data' with 'signature'
        SecureMessage sMsg = verifyMessage(rMsg);

        // 2. check group message
        ID receiver = barrack.getID(sMsg.envelope.receiver);
        if (receiver.getType().isGroup()) {
            // TODO: split it
        }

        // 3. decrypt 'data' to 'content'
        InstantMessage iMsg = decryptMessage(sMsg);

        // OK
        return iMsg.content;
    }
    
    //
    //  StationDelegate
    //
    @Override
    public void didReceivePackage(byte[] data, Station server) {
        // 1. decode message package
        ReliableMessage rMsg = messenger.deserializeMessage(data);
        
        // 2. verify and decrypt message
        Content content = unpack(rMsg);
        
        // TODO: process message content
    }

Copyright © 2019 Albert Moky

FAQs

Package last updated on 28 Aug 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc