Decentralized Instant Messaging Protocol (Java)
![Platform](https://img.shields.io/badge/Platform-Java%208-brightgreen.svg)
Talk is cheap, show you the codes!
Dependencies
build.gradle
allprojects {
repositories {
jcenter()
mavenCentral()
}
}
dependencies {
compile 'chat.dim:DIMP:0.5.3'
}
pom.xml
<dependencies>
<dependency>
<groupId>chat.dim</groupId>
<artifactId>DIMP</artifactId>
<version>0.5.3</version>
<type>pom</type>
</dependency>
</dependencies>
Common Extensions
Facebook.java
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;
}
return true;
}
public boolean saveMeta(Meta meta, ID identifier) {
if (!meta.matches(identifier)) {
return false;
}
return true;
}
public boolean saveProfile(Profile profile) {
if (!verifyProfile(profile)) {
return false;
}
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()) {
meta = getMeta(identifier);
} else if (type.isGroup()) {
Group group = getGroup(identifier);
if (group != null) {
meta = getMeta(group.getOwner());
}
}
return meta != null && profile.verify(meta.key);
}
@Override
protected User createUser(ID identifier) {
if (identifier.isBroadcast()) {
return new User(identifier);
}
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()) {
return new Group(identifier);
}
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 {
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
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) {
return false;
}
@Override
public Map loadKeys() {
return null;
}
@Override
public SymmetricKey reuseCipherKey(ID sender, ID receiver, SymmetricKey key) {
return super.reuseCipherKey(sender, receiver, key);
}
}
Messenger.java
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);
if (content instanceof FileContent) {
FileContent file = (FileContent) content;
byte[] data = file.getData();
data = key.encrypt(data);
String url = delegate.uploadFileData(data, iMsg);
if (url != null) {
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;
}
if (content instanceof FileContent) {
FileContent file = (FileContent) content;
InstantMessage iMsg = new InstantMessage(content, sMsg.envelope);
byte[] fileData = delegate.downloadFileData(file.getUrl(), iMsg);
if (fileData == null) {
file.setPassword(key);
} else {
file.setData(key.decrypt(fileData));
file.setUrl(null);
}
}
return content;
}
public boolean sendMessage(InstantMessage iMsg, Callback callback, boolean split) {
ReliableMessage rMsg = signMessage(encryptMessage(iMsg));
Facebook facebook = getFacebook();
ID receiver = facebook.getID(iMsg.envelope.receiver);
boolean OK = true;
if (split && receiver.getType().isGroup()) {
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) {
OK = sendMessage(rMsg, callback);
} else {
for (Message msg : messages) {
if (!sendMessage((ReliableMessage) msg, callback)) {
OK = false;
}
}
}
} else {
OK = sendMessage(rMsg, callback);
}
return OK;
}
private boolean sendMessage(ReliableMessage rMsg, Callback callback) {
byte[] data = serializeMessage(rMsg);
MessageCallback handler = new MessageCallback(rMsg, callback);
return getDelegate().sendPackage(data, handler);
}
@Override
public byte[] onReceiveDataPackage(byte[] data) {
ReliableMessage rMsg = deserializeMessage(data);
Content response = process(rMsg);
if (response == null) {
return null;
}
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));
return serializeMessage(nMsg);
}
protected Content process(ReliableMessage rMsg) {
return null;
}
}
User Account
Register.java
public User register(String username) {
PrivateKey sk = PrivateKey.generate(PrivateKey.RSA);
String seed = username;
Meta meta = Meta.generate(Meta.VersionDefault, sk, seed);
ID identifier = meta.generateID(NetworkType.Main);
facebook.savePrivateKey(sk, identifier);
facebook.saveMeta(meta, identifier);
return facebook.getUser(identifier);
}
Messaging
Send.java
public ReliableMessage pack(Content content, ID sender, ID receiver) {
InstantMessage iMsg = new InstantMessage(content, sender, receiver);
SecureMessage sMsg = messenger.encryptMessage(iMsg);
ReliableMessage rMsg = messenger.signMessage(sMsg);
return rMsg;
}
public boolean send(Content content, ID sender, ID receiver) {
ReliableMessage rMsg = pack(content, sender, receiver);
CompletionHandler handler = new CompletionHandler() {
@Override
public void onSuccess() {
}
@Override
public void onFailed(Error error) {
}
};
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) {
SecureMessage sMsg = verifyMessage(rMsg);
ID receiver = barrack.getID(sMsg.envelope.receiver);
if (receiver.getType().isGroup()) {
}
InstantMessage iMsg = decryptMessage(sMsg);
return iMsg.content;
}
@Override
public void didReceivePackage(byte[] data, Station server) {
ReliableMessage rMsg = messenger.deserializeMessage(data);
Content content = unpack(rMsg);
}
Copyright © 2019 Albert Moky