mirror of
https://github.com/ChronosX88/Influence-P2P.git
synced 2024-11-22 07:12:19 +00:00
Made creating chat system. Added KeyPairManager
This commit is contained in:
parent
a65b871eab
commit
2680a86ba8
@ -3,9 +3,6 @@
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<compositeConfiguration>
|
||||
<compositeBuild compositeDefinitionSource="SCRIPT" />
|
||||
</compositeConfiguration>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
|
@ -44,4 +44,5 @@ dependencies {
|
||||
implementation 'com.google.android.material:material:1.1.0-alpha04'
|
||||
implementation 'androidx.preference:preference:1.1.0-alpha03'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
//implementation group: 'com.github.demidenko05', name: 'a-javabeans', version: '1.0.4'
|
||||
}
|
||||
|
@ -6,5 +6,4 @@ import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||
|
||||
public interface ChatListLogicContract {
|
||||
List<ChatEntity> loadAllChats();
|
||||
void createChatBySender(ChatEntity entity);
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
package io.github.chronosx88.influence.helpers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public class KeyPairManager {
|
||||
private File keyPairDir;
|
||||
|
||||
public KeyPairManager() {
|
||||
this.keyPairDir = new File(AppHelper.getContext().getFilesDir().getAbsoluteFile(), "keyPairs");
|
||||
}
|
||||
|
||||
public KeyPair openMainKeyPair() {
|
||||
return getKeyPair("mainKeyPair");
|
||||
}
|
||||
|
||||
public KeyPair getKeyPair(String keyPairName) {
|
||||
KeyPair keyPair = null;
|
||||
keyPairName = keyPairName + ".kp";
|
||||
File keyPairFile = new File(keyPairDir, keyPairName);
|
||||
if (!keyPairFile.exists()) {
|
||||
return createKeyPairFile(keyPairFile);
|
||||
}
|
||||
return openKeyPairFile(keyPairFile);
|
||||
}
|
||||
|
||||
private synchronized KeyPair openKeyPairFile(File keyPairFile) {
|
||||
KeyPair keyPair = null;
|
||||
try {
|
||||
FileInputStream inputStream = new FileInputStream(keyPairFile);
|
||||
byte[] serializedKeyPair = new byte[(int) keyPairFile.length()];
|
||||
inputStream.read(serializedKeyPair);
|
||||
inputStream.close();
|
||||
keyPair = Serializer.deserializeObject(new String(serializedKeyPair, StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
private synchronized KeyPair createKeyPairFile(File keyPairFile) {
|
||||
KeyPair keyPair = null;
|
||||
try {
|
||||
keyPairFile.createNewFile();
|
||||
keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
||||
FileOutputStream outputStream = new FileOutputStream(keyPairFile);
|
||||
outputStream.write(Serializer.serializeObject(keyPair).getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.close();
|
||||
} catch (IOException | NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
public synchronized void saveKeyPair(String keyPairID, KeyPair keyPair) {
|
||||
File keyPairFile = new File(keyPairDir, keyPairID + ".kp");
|
||||
if(!keyPairFile.exists()) {
|
||||
try {
|
||||
FileOutputStream outputStream = new FileOutputStream(keyPairFile);
|
||||
outputStream.write(Serializer.serializeObject(keyPair).getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import net.tomp2p.peers.PeerAddress;
|
||||
import io.github.chronosx88.influence.contracts.observer.Observer;
|
||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||
import io.github.chronosx88.influence.observable.MainObservable;
|
||||
|
||||
public class NetworkHandler implements Observer {
|
||||
@ -27,7 +28,7 @@ public class NetworkHandler implements Observer {
|
||||
switch (object.get("action").getAsInt()) {
|
||||
case NetworkActions.START_CHAT: {
|
||||
String chatStarterPlainAddress = object.get("senderAddress").getAsString();
|
||||
createChatEntry(object.get("chatID").getAsString(), chatStarterPlainAddress);
|
||||
createChatEntry(object.get("chatID").getAsString(), object.get("senderID").getAsString(), chatStarterPlainAddress);
|
||||
handleIncomingChat(object.get("chatID").getAsString(), PrepareData.prepareFromStore(chatStarterPlainAddress));
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", UIActions.NEW_CHAT);
|
||||
@ -36,9 +37,9 @@ public class NetworkHandler implements Observer {
|
||||
}
|
||||
|
||||
case NetworkActions.SUCCESSFULL_CREATE_CHAT: {
|
||||
createChatEntry(object.get("chatID").getAsString(), object.get("senderAddress").getAsString());
|
||||
createChatEntry(object.get("chatID").getAsString(), object.get("senderID").getAsString(), object.get("senderAddress").getAsString());
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", UIActions.SUCCESSFULL_CREATE_CHAT);
|
||||
jsonObject.addProperty("action", UIActions.NEW_CHAT);
|
||||
AppHelper.getObservable().notifyObservers(jsonObject, MainObservable.UI_ACTIONS_CHANNEL);
|
||||
break;
|
||||
}
|
||||
@ -46,14 +47,15 @@ public class NetworkHandler implements Observer {
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void createChatEntry(String chatID, String peerAddress) {
|
||||
// TODO: make saving chat in db
|
||||
private void createChatEntry(String chatID, String name, String peerAddress) {
|
||||
AppHelper.getChatDB().chatDao().addChat(new ChatEntity(chatID, name, peerAddress, ""));
|
||||
}
|
||||
|
||||
private void handleIncomingChat(String chatID, PeerAddress chatStarterAddress) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", NetworkActions.SUCCESSFULL_CREATE_CHAT);
|
||||
jsonObject.addProperty("chatID", chatID);
|
||||
jsonObject.addProperty("senderID", AppHelper.getPeerID());
|
||||
jsonObject.addProperty("senderAddress", PrepareData.prepareToStore(peerDHT.peerAddress()));
|
||||
AppHelper.getPeerDHT().peer().sendDirect(chatStarterAddress).object(gson.toJson(jsonObject)).start().awaitUninterruptibly();
|
||||
}
|
||||
|
@ -1,42 +1,15 @@
|
||||
package io.github.chronosx88.influence.logic;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.github.chronosx88.influence.contracts.chatlist.ChatListLogicContract;
|
||||
import io.github.chronosx88.influence.contracts.observer.Observer;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||
import io.github.chronosx88.influence.models.roomEntities.ChatEntity;
|
||||
import io.github.chronosx88.influence.observable.MainObservable;
|
||||
|
||||
public class ChatListLogic implements ChatListLogicContract, Observer {
|
||||
public ChatListLogic() {
|
||||
AppHelper.getObservable().register(this, MainObservable.OTHER_ACTIONS_CHANNEL);
|
||||
}
|
||||
public class ChatListLogic implements ChatListLogicContract {
|
||||
|
||||
@Override
|
||||
public List<ChatEntity> loadAllChats() {
|
||||
return AppHelper.getChatDB().chatDao().getAllChats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(JsonObject object) {
|
||||
switch (object.get("action").getAsInt()) {
|
||||
case NetworkActions.START_CHAT: {
|
||||
createChatBySender(new ChatEntity(object.get("chatID").getAsString(), object.get("name").getAsString(), ""));
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", UIActions.NEW_CHAT);
|
||||
AppHelper.getObservable().notifyObservers(jsonObject, MainObservable.UI_ACTIONS_CHANNEL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createChatBySender(ChatEntity entity) {
|
||||
AppHelper.getChatDB().chatDao().addChat(entity);
|
||||
}
|
||||
}
|
||||
|
@ -25,21 +25,16 @@ import net.tomp2p.storage.Data;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.UUID;
|
||||
|
||||
import io.github.chronosx88.influence.contracts.main.MainLogicContract;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
||||
import io.github.chronosx88.influence.helpers.Serializer;
|
||||
import io.github.chronosx88.influence.helpers.StorageMVStore;
|
||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
||||
@ -57,11 +52,13 @@ public class MainLogic implements MainLogicContract {
|
||||
private PeerAddress bootstrapPeerAddress = null;
|
||||
private Gson gson;
|
||||
private AutoReplication replication;
|
||||
private KeyPairManager keyPairManager;
|
||||
|
||||
public MainLogic() {
|
||||
this.context = AppHelper.getContext();
|
||||
this.preferences = context.getSharedPreferences("io.github.chronosx88.influence_preferences", context.MODE_PRIVATE);
|
||||
gson = new Gson();
|
||||
keyPairManager = new KeyPairManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,7 +132,7 @@ public class MainLogic implements MainLogicContract {
|
||||
Gson gson = new Gson();
|
||||
JsonObject publicProfile = new JsonObject();
|
||||
publicProfile.addProperty("peerAddress", Base64.encodeToString(Serializer.serializeObject(peerDHT.peerAddress()).getBytes(StandardCharsets.UTF_8), Base64.URL_SAFE));
|
||||
peerDHT.put(Number160.createHash(preferences.getString("peerID", null) + "_profile")).data(new Data(gson.toJson(publicProfile)).protectEntry(createMainKeyPair())).start().awaitUninterruptibly();
|
||||
peerDHT.put(Number160.createHash(preferences.getString("peerID", null) + "_profile")).data(new Data(gson.toJson(publicProfile)).protectEntry(keyPairManager.openMainKeyPair())).start().awaitUninterruptibly();
|
||||
replication = new AutoReplication(peerDHT.peer()).start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -214,34 +211,4 @@ public class MainLogic implements MainLogicContract {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private KeyPair createMainKeyPair() {
|
||||
KeyPair kp = null;
|
||||
try {
|
||||
File keyPairDir = new File(AppHelper.getContext().getFilesDir().getAbsoluteFile(), "keyPairs");
|
||||
if (!keyPairDir.exists())
|
||||
keyPairDir.mkdir();
|
||||
File mainKeyPairFile = new File(keyPairDir, "mainKeyPair.kp");
|
||||
if (!mainKeyPairFile.exists()) {
|
||||
mainKeyPairFile.createNewFile();
|
||||
try {
|
||||
kp = KeyPairGenerator.getInstance("RSA").generateKeyPair();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
FileOutputStream outputStream = new FileOutputStream(mainKeyPairFile);
|
||||
outputStream.write(Serializer.serializeObject(kp).getBytes(StandardCharsets.UTF_8));
|
||||
outputStream.close();
|
||||
return kp;
|
||||
}
|
||||
FileInputStream inputStream = new FileInputStream(mainKeyPairFile);
|
||||
byte[] serializedKeyPair = new byte[(int) mainKeyPairFile.length()];
|
||||
inputStream.read(serializedKeyPair);
|
||||
inputStream.close();
|
||||
kp = Serializer.deserializeObject(new String(serializedKeyPair, StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return kp;
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,19 @@
|
||||
package io.github.chronosx88.influence.logic;
|
||||
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import net.tomp2p.dht.FutureGet;
|
||||
import net.tomp2p.dht.FuturePut;
|
||||
import net.tomp2p.dht.PeerDHT;
|
||||
import net.tomp2p.futures.FuturePing;
|
||||
import net.tomp2p.peers.Number160;
|
||||
import net.tomp2p.peers.PeerAddress;
|
||||
import net.tomp2p.storage.Data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -18,6 +21,7 @@ import java.util.UUID;
|
||||
|
||||
import io.github.chronosx88.influence.contracts.startchat.StartChatLogicContract;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.KeyPairManager;
|
||||
import io.github.chronosx88.influence.helpers.PrepareData;
|
||||
import io.github.chronosx88.influence.helpers.Serializer;
|
||||
import io.github.chronosx88.influence.helpers.actions.NetworkActions;
|
||||
@ -27,10 +31,13 @@ import io.github.chronosx88.influence.observable.MainObservable;
|
||||
public class StartChatLogic implements StartChatLogicContract {
|
||||
private PeerDHT peerDHT;
|
||||
private Gson gson;
|
||||
private KeyPairManager keyPairManager;
|
||||
private final static String LOG_TAG = "StartChatLogic";
|
||||
|
||||
public StartChatLogic() {
|
||||
peerDHT = AppHelper.getPeerDHT();
|
||||
gson = new Gson();
|
||||
keyPairManager = new KeyPairManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -45,16 +52,32 @@ public class StartChatLogic implements StartChatLogicContract {
|
||||
}
|
||||
String peerAddressString = recipientPublicProfile.get("peerAddress").getAsString();
|
||||
PeerAddress peerAddress = Serializer.deserializeObject(new String(Base64.decode(peerAddressString, Base64.URL_SAFE), StandardCharsets.UTF_8));
|
||||
String chatID = UUID.randomUUID().toString();
|
||||
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", NetworkActions.START_CHAT);
|
||||
jsonObject.addProperty("chatID", chatID);
|
||||
jsonObject.addProperty("senderID", AppHelper.getPeerID());
|
||||
// TODO: Append public key to new chat request (for encryption)
|
||||
jsonObject.addProperty("senderAddress", PrepareData.prepareToStore(peerDHT.peerAddress()));
|
||||
|
||||
FuturePing ping = peerDHT.peer().ping().peerAddress(peerAddress).start().awaitUninterruptibly();
|
||||
if(ping.isSuccess()) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty("action", NetworkActions.START_CHAT);
|
||||
jsonObject.addProperty("chatID", UUID.randomUUID().toString());
|
||||
// TODO: Append public key to new chat request (for encryption)
|
||||
jsonObject.addProperty("senderAddress", PrepareData.prepareToStore(peerDHT.peerAddress()));
|
||||
peerDHT.peer().sendDirect(peerAddress).object(gson.toJson(jsonObject)).start();
|
||||
} else {
|
||||
// TODO: put chat entry to "*peerID*_newChats". That peer later will fetch this new chats
|
||||
try {
|
||||
FuturePut futurePut = peerDHT
|
||||
.put(Number160.createHash(peerID))
|
||||
.data(Number160.createHash(UUID.randomUUID().toString()), new Data(gson.toJson(jsonObject))
|
||||
.protectEntry(keyPairManager.openMainKeyPair())).start().awaitUninterruptibly();
|
||||
if(futurePut.isSuccess()) {
|
||||
Log.i(LOG_TAG, "# Create new offline chat request is successful! ChatID: " + chatID);
|
||||
} else {
|
||||
Log.e(LOG_TAG, "# Failed to create chat: " + futurePut.failedReason());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import androidx.room.PrimaryKey;
|
||||
@Entity(tableName = "chats")
|
||||
public class ChatEntity {
|
||||
@NonNull @PrimaryKey String id;
|
||||
@ColumnInfo String name;
|
||||
@ColumnInfo String peerAddresses;
|
||||
@ColumnInfo String keyPairID;
|
||||
@ColumnInfo public String name;
|
||||
@ColumnInfo public String peerAddresses;
|
||||
@ColumnInfo public String keyPairID;
|
||||
|
||||
public ChatEntity(String id, String name, String peerAddresses, String keyPairID) {
|
||||
this.id = id;
|
||||
@ -27,7 +27,7 @@ public class ChatEntity {
|
||||
return keyPairID;
|
||||
}
|
||||
|
||||
public String getPeerAddress() { return peerAddresses; }
|
||||
public String getPeerAddress() { return peerAddresses; }
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
|
@ -1,12 +1,18 @@
|
||||
package io.github.chronosx88.influence.presenters;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import io.github.chronosx88.influence.contracts.chatlist.ChatListLogicContract;
|
||||
import io.github.chronosx88.influence.contracts.chatlist.ChatListPresenterContract;
|
||||
import io.github.chronosx88.influence.contracts.chatlist.ChatListViewContract;
|
||||
import io.github.chronosx88.influence.contracts.observer.Observer;
|
||||
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||
import io.github.chronosx88.influence.helpers.ChatListAdapter;
|
||||
import io.github.chronosx88.influence.helpers.actions.UIActions;
|
||||
import io.github.chronosx88.influence.logic.ChatListLogic;
|
||||
import io.github.chronosx88.influence.observable.MainObservable;
|
||||
|
||||
public class ChatListPresenter implements ChatListPresenterContract {
|
||||
public class ChatListPresenter implements ChatListPresenterContract, Observer {
|
||||
private ChatListViewContract view;
|
||||
private ChatListLogicContract logic;
|
||||
private ChatListAdapter chatListAdapter;
|
||||
@ -16,6 +22,7 @@ public class ChatListPresenter implements ChatListPresenterContract {
|
||||
chatListAdapter = new ChatListAdapter();
|
||||
this.logic = new ChatListLogic();
|
||||
this.view.setRecycleAdapter(chatListAdapter);
|
||||
AppHelper.getObservable().register(this, MainObservable.UI_ACTIONS_CHANNEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -28,4 +35,13 @@ public class ChatListPresenter implements ChatListPresenterContract {
|
||||
public void openChat(String chatID) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(JsonObject object) {
|
||||
switch (object.get("action").getAsInt()) {
|
||||
case UIActions.NEW_CHAT: {
|
||||
updateChatList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class StartChatPresenter implements StartChatPresenterContract, Observer
|
||||
|
||||
@Override
|
||||
public void startChatWithPeer(String peerID) {
|
||||
// TODO
|
||||
logic.sendStartChatMessage(peerID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,6 +10,7 @@ import com.google.gson.JsonObject;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import io.github.chronosx88.influence.R;
|
||||
import io.github.chronosx88.influence.contracts.chatlist.ChatListPresenterContract;
|
||||
@ -41,6 +42,7 @@ public class ChatListFragment extends Fragment implements ChatListViewContract,
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
chatList = view.findViewById(R.id.chatlist_container);
|
||||
chatList.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
presenter = new ChatListPresenter(this);
|
||||
presenter.updateChatList();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user