diff --git a/POO/src/messages/MauvaisTypeMessageException.java b/POO/src/messages/MauvaisTypeMessageException.java deleted file mode 100644 index c7f9644..0000000 --- a/POO/src/messages/MauvaisTypeMessageException.java +++ /dev/null @@ -1,8 +0,0 @@ -package messages; - -public class MauvaisTypeMessageException extends Exception { - - private static final long serialVersionUID = 1L; - - -} diff --git a/POO/src/messages/Message.java b/POO/src/messages/Message.java deleted file mode 100644 index 6036b00..0000000 --- a/POO/src/messages/Message.java +++ /dev/null @@ -1,69 +0,0 @@ -package messages; - -import java.io.Serializable; -import java.lang.instrument.Instrumentation; -import java.util.Arrays; - -import messages.Message.TypeMessage; - -public abstract class Message implements Serializable { - - public enum TypeMessage {JE_SUIS_CONNECTE, JE_SUIS_DECONNECTE, INFO_PSEUDO, TEXTE, IMAGE, FICHIER, MESSAGE_NUL} - protected TypeMessage type; - private static final long serialVersionUID = 1L; - private static Instrumentation inst; - - public TypeMessage getTypeMessage() { - return this.type; - } - - protected abstract String attributsToString(); - - public String toString() { - return this.type+"###"+this.attributsToString(); - } - - public static Message stringToMessage(String messageString) { - try { - String[] parts = messageString.split("###"); - switch (parts[0]) { - case "JE_SUIS_CONNECTE" : - return new MessageSysteme(TypeMessage.JE_SUIS_CONNECTE); - - case "JE_SUIS_DECONNECTE" : - return new MessageSysteme(TypeMessage.JE_SUIS_DECONNECTE); - - case "INFO_PSEUDO" : - return new MessageSysteme(TypeMessage.INFO_PSEUDO, parts[1], parts[2], Integer.parseInt(parts[3]) ); - - case "TEXTE" : - return new MessageTexte(TypeMessage.TEXTE, parts[1]); - - case "IMAGE" : - return new MessageFichier(TypeMessage.IMAGE, parts[1], parts[2]); - - case "FICHIER" : - return new MessageFichier(TypeMessage.FICHIER, parts[1], parts[2]); - } - } catch (MauvaisTypeMessageException e) {} - return null; - } - - //tests ici - public static void main(String[] args) throws MauvaisTypeMessageException { - Message m1 = new MessageSysteme(TypeMessage.JE_SUIS_CONNECTE); - Message m2 = new MessageSysteme(TypeMessage.JE_SUIS_DECONNECTE); - Message m3 = new MessageSysteme(TypeMessage.INFO_PSEUDO, "pseudo156434518", "id236", 1500); - Message m4 = new MessageTexte(TypeMessage.TEXTE, "blablabla"); - Message m5 = new MessageFichier(TypeMessage.FICHIER, "truc", ".pdf"); - - - System.out.println(Message.stringToMessage(m1.toString())); - System.out.println(Message.stringToMessage(m2.toString())); - System.out.println(Message.stringToMessage(m3.toString())); - System.out.println(Message.stringToMessage(m4.toString())); - System.out.println(Message.stringToMessage(m5.toString())); - - } - -} diff --git a/POO/src/messages/MessageFichier.java b/POO/src/messages/MessageFichier.java deleted file mode 100644 index aa8f0bf..0000000 --- a/POO/src/messages/MessageFichier.java +++ /dev/null @@ -1,33 +0,0 @@ -package messages; - -import messages.Message.TypeMessage; - -public class MessageFichier extends Message { - - - private static final long serialVersionUID = 1L; - private String contenu; - private String extension; - - public MessageFichier(TypeMessage type, String contenu, String extension) throws MauvaisTypeMessageException{ - if ((type==TypeMessage.IMAGE)||(type==TypeMessage.FICHIER)) { - this.type=type; - this.contenu=contenu; - this.extension=extension; - } - else throw new MauvaisTypeMessageException(); - } - - public String getContenu() { - return this.contenu; - } - - public String getExtension() { - return this.extension; - } - - @Override - protected String attributsToString() { - return this.contenu+"###"+this.extension; - } -} \ No newline at end of file diff --git a/POO/src/messages/MessageSysteme.java b/POO/src/messages/MessageSysteme.java deleted file mode 100644 index 0ff111d..0000000 --- a/POO/src/messages/MessageSysteme.java +++ /dev/null @@ -1,46 +0,0 @@ -package messages; - -public class MessageSysteme extends Message { - - private static final long serialVersionUID = 1L; - private String pseudo; - private String id; - private int port; - - public MessageSysteme(TypeMessage type) throws MauvaisTypeMessageException{ - if ((type==TypeMessage.JE_SUIS_CONNECTE)||(type==TypeMessage.JE_SUIS_DECONNECTE)||(type==TypeMessage.MESSAGE_NUL)) { - this.type=type; - this.pseudo=""; - this.id=""; - this.port = -1; - } - else throw new MauvaisTypeMessageException(); - } - - public MessageSysteme(TypeMessage type, String pseudo, String id, int port) throws MauvaisTypeMessageException { - if (type==TypeMessage.INFO_PSEUDO) { - this.type=type; - this.pseudo=pseudo; - this.id=id; - this.port = port; - } - else throw new MauvaisTypeMessageException(); - } - - public String getPseudo() { - return this.pseudo; - } - - public String getId() { - return this.id; - } - - public int getPort() { - return this.port; - } - - @Override - protected String attributsToString() { - return this.pseudo+"###"+this.id+"###"+this.port; - } -} diff --git a/POO/src/messages/MessageTexte.java b/POO/src/messages/MessageTexte.java deleted file mode 100644 index e5d354d..0000000 --- a/POO/src/messages/MessageTexte.java +++ /dev/null @@ -1,27 +0,0 @@ -package messages; - -import messages.Message.TypeMessage; - -public class MessageTexte extends Message { - - - private static final long serialVersionUID = 1L; - private String contenu; - - public MessageTexte(TypeMessage type, String contenu) throws MauvaisTypeMessageException{ - if (type==TypeMessage.TEXTE) { - this.type=type; - this.contenu=contenu; - } - else throw new MauvaisTypeMessageException(); - } - - public String getContenu() { - return this.contenu; - } - - @Override - protected String attributsToString() { - return this.contenu; - } -} \ No newline at end of file diff --git a/POO_Server/src/communication/CommunicationUDP.java b/POO_Server/src/communication/CommunicationUDP.java index 9d6a942..aae6850 100644 --- a/POO_Server/src/communication/CommunicationUDP.java +++ b/POO_Server/src/communication/CommunicationUDP.java @@ -139,7 +139,7 @@ public class CommunicationUDP extends Thread { users.remove(index); } try { - Message message = new MessageSysteme(Message.TypeMessage.JE_SUIS_DECONNECTE, idClient); + Message message = new MessageSysteme(Message.TypeMessage.JE_SUIS_DECONNECTE, pseudoClient, idClient, port); observer.update(this, message); } catch (MauvaisTypeMessageException e) { e.printStackTrace(); @@ -152,15 +152,6 @@ public class CommunicationUDP extends Thread { users.remove(0); } } - - - public void sendMessageConnecte() throws UnknownHostException, IOException { - for(int port : this.portOthers) { - try { - this.client.sendMessageUDP_local(new MessageSysteme(Message.TypeMessage.JE_SUIS_CONNECTE, Utilisateur.getSelf().getId()), port, InetAddress.getLocalHost()); - } catch (MauvaisTypeMessageException e) {/*Si ça marche pas essayer là*/} - } - } // Send the message "add,id,pseudo" to localhost on all the ports in @@ -198,20 +189,8 @@ public class CommunicationUDP extends Thread { } catch (MauvaisTypeMessageException e) {e.printStackTrace();} } - - // Send the message "del,id,pseudo" to localhost on all the ports in - // "portOthers" - // This allows the receivers' agent (portOthers) to delete the entry - // corresponding to this agent - public void sendMessageDelete() throws UnknownHostException, IOException { - for(int port : this.portOthers) { - try { - this.client.sendMessageUDP_local(new MessageSysteme(Message.TypeMessage.JE_SUIS_DECONNECTE, Utilisateur.getSelf().getId()), port, InetAddress.getLocalHost()); - } catch (MauvaisTypeMessageException e) {} - } - } - //Broadcast a given message on the local network + //Broadcast a given message on the local network (here podelized by ports) public void sendMessage(Message m) { try { for(int port : this.portOthers) { @@ -233,21 +212,4 @@ public class CommunicationUDP extends Thread { } } - //Pas encore adapte message -// private void sendIDPseudo_broadcast(String prefixe) throws UnknownHostException, IOException { -// Utilisateur self = Utilisateur.getSelf(); -// String idSelf = self.getId(); -// String pseudoSelf = self.getPseudo(); -// -// String message = prefixe+","+idSelf + "," + pseudoSelf; -// -// -// this.client.sendMessageUDP_broadcast(message, this.portServer); -// -// } - -// public synchronized void createSenderUDP(int port, Mode mode) throws SocketException { -// new SenderUDP(mode, port).start(); -// } - } diff --git a/POO_Server/src/communication/TCPClient.java b/POO_Server/src/communication/TCPClient.java deleted file mode 100644 index 68512f9..0000000 --- a/POO_Server/src/communication/TCPClient.java +++ /dev/null @@ -1,57 +0,0 @@ -package communication; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.net.Socket; - -import main.Observer; -//import main.VueSession; -import messages.MessageTexte; -import messages.MauvaisTypeMessageException; -import messages.Message; -import messages.Message.TypeMessage; - -public class TCPClient { - - private Socket sockTCP; - private ObjectOutputStream output; - private TCPInputThread inputThread; - - //Constructor from a TCP-client socket - public TCPClient(Socket sockTCP) throws IOException { - this.sockTCP = sockTCP; - - this.output = new ObjectOutputStream(sockTCP.getOutputStream()) ; - ObjectInputStream input = new ObjectInputStream(sockTCP.getInputStream()); - this.inputThread = new TCPInputThread(input); - } - - //Constructor from an IP address and a port - public TCPClient(InetAddress addr, int port) throws IOException { - this(new Socket(addr, port)) ; - - } - - - public void startInputThread() { - this.inputThread.start(); - } - - - public void sendMessage(String contenu) throws IOException, MauvaisTypeMessageException { - System.out.println("dans write"); - MessageTexte message = new MessageTexte(TypeMessage.TEXTE, contenu); - this.output.writeObject(message); - } - - public void setObserverInputThread(Observer o) { - this.inputThread.setObserver(o); - } -} diff --git a/POO_Server/src/communication/TCPInputThread.java b/POO_Server/src/communication/TCPInputThread.java deleted file mode 100644 index f409f97..0000000 --- a/POO_Server/src/communication/TCPInputThread.java +++ /dev/null @@ -1,65 +0,0 @@ -package communication; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.util.Arrays; - -import main.Observer; -import messages.Message; - -public class TCPInputThread extends Thread { - - private ObjectInputStream input; - private boolean running; - private char[] buffer; - private Observer obs; - - public TCPInputThread(ObjectInputStream input) { - this.input = input; - this.running = true; - this.buffer = new char[200]; - } - - @Override - public void run() { - - while (this.running) { - try { - - - System.out.println("dans read"); - Object o = this.input.readObject(); - this.obs.update(this, o); - - - } catch (IOException | ClassNotFoundException e) { - this.interrupt(); - //e.printStackTrace(); - } - - } - } - - @Override - public void interrupt() { - - try { - this.running = false; - this.input.close(); - //this.obs.update(this, this.input); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - private void flushBuffer() { - Arrays.fill(this.buffer, '\u0000'); - } - - protected void setObserver(Observer o) { - this.obs = o; - } - -} diff --git a/POO_Server/src/communication/TCPServer.java b/POO_Server/src/communication/TCPServer.java deleted file mode 100644 index 71ddf0f..0000000 --- a/POO_Server/src/communication/TCPServer.java +++ /dev/null @@ -1,40 +0,0 @@ -package communication; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; - -import main.Observer; - - -public class TCPServer extends Thread { - - private ServerSocket sockListenTCP; - private Observer obs; - - public TCPServer(int port) throws UnknownHostException, IOException { - this.sockListenTCP = new ServerSocket(port, 5, InetAddress.getLocalHost()); - } - - @Override - public void run() { - System.out.println("TCP running"); - Socket sockAccept; - while(true) { - try { - sockAccept = this.sockListenTCP.accept(); - this.obs.update(this, sockAccept); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - } - - public void addObserver(Observer obs) { - this.obs = obs; - } -} diff --git a/POO_Server/src/database/SQLiteCreateTables.java b/POO_Server/src/database/SQLiteCreateTables.java new file mode 100644 index 0000000..45aa061 --- /dev/null +++ b/POO_Server/src/database/SQLiteCreateTables.java @@ -0,0 +1,73 @@ +package database; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +class SQLiteCreateTables { + + + protected static void createTableUser(Connection connec) throws SQLException { + String createTableUser = "CREATE TABLE IF NOT EXISTS user (\r\n" + + " id INTEGER PRIMARY KEY AUTOINCREMENT,\r\n" + + " username VARCHAR (50) NOT NULL\r\n" + + " UNIQUE ON CONFLICT ROLLBACK,\r\n" + + " pwd_salt BLOB,\r\n" + + " db_datakey_salt BLOB,\r\n" + + " encrypted_pwd_hashsalt BLOB,\r\n" + + " encrypted_db_datakey BLOB,\r\n" + + " iv_datakey BLOB\r\n" + + ");"; + + Statement stmt = connec.createStatement(); + stmt.execute(createTableUser); + + } + + protected static void createTableConversation(Connection connec) throws SQLException { + String createTableConversation = "CREATE TABLE IF NOT EXISTS conversation (\r\n" + + " id_conversation INTEGER PRIMARY KEY AUTOINCREMENT,\r\n" + + " id_emetteur INTEGER REFERENCES user (id) \r\n" + + " NOT NULL,\r\n" + + " id_recepteur INTEGER REFERENCES user (id) \r\n" + + " NOT NULL,\r\n" + +" iv_conversation BLOB NOT NULL" + + ");"; + + Statement stmt = connec.createStatement(); + stmt.execute(createTableConversation); + + } + + protected static void createTableMessage(Connection connec) throws SQLException { + String createTableMessage = "CREATE TABLE IF NOT EXISTS message (\r\n" + + " id_message INTEGER PRIMARY KEY AUTOINCREMENT,\r\n" + + " id_conversation INTEGER REFERENCES conversation (id_conversation) \r\n" + + " NOT NULL,\r\n" + + " id_type INTEGER REFERENCES type (id_type) \r\n" + + " NOT NULL,\r\n" + + " content BLOB,\r\n" + + " date INTEGER NOT NULL,\r\n" + + " extension VARCHAR (20) \r\n" + + ");\r\n"; + + Statement stmt = connec.createStatement(); + stmt.execute(createTableMessage); + } + + protected static void createTableType(Connection connec) throws SQLException { + String createTableType = "CREATE TABLE IF NOT EXISTS type (\r\n" + " id_type INTEGER PRIMARY KEY,\r\n" + + " label VARCHAR (20) NOT NULL\r\n" + ");"; + + Statement stmt = connec.createStatement(); + stmt.execute(createTableType); + + String typeText = "INSERT OR IGNORE INTO type (id_type, label) " + "VALUES (0, 'text');"; + String typeFile = "INSERT OR IGNORE INTO type (id_type, label) " + "VALUES (1, 'file');"; + String typeImage = "INSERT OR IGNORE INTO type (id_type, label) " + "VALUES (2, 'image');"; + + stmt.execute(typeText); + stmt.execute(typeFile); + stmt.execute(typeImage); + } +} diff --git a/POO_Server/src/database/SQLiteEncprytion.java b/POO_Server/src/database/SQLiteEncprytion.java new file mode 100644 index 0000000..38c0916 --- /dev/null +++ b/POO_Server/src/database/SQLiteEncprytion.java @@ -0,0 +1,84 @@ +package database; + + +import java.util.Base64; +import java.util.Random; + +import javax.crypto.*; +import javax.crypto.spec.*; +import java.security.*; +import java.security.spec.*; + +class SQLiteEncprytion { + + private static final Random RANDOM = new SecureRandom(); + private static final int ITERATIONS = 10000; + private static final int KEY_LENGTH = 256; + protected static final String encryptAlgorithm = "AES/CBC/PKCS5Padding"; + + protected static byte[] getNextSalt() { + byte[] salt = new byte[24]; + RANDOM.nextBytes(salt); + return salt; + } + + + protected static byte[] hash(char[] password, byte[] salt) { + return SQLiteEncprytion.getKey(password, salt).getEncoded(); + } + + + protected static SecretKey getKey(char[] password, byte[] salt) { + PBEKeySpec saltpwd = new PBEKeySpec(password, salt, ITERATIONS, KEY_LENGTH); + + try { + SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + SecretKey tmp = skf.generateSecret(saltpwd); + SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES"); + return key; + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + e.printStackTrace(); + } finally { + saltpwd.clearPassword(); + } + return null; + } + + + public static IvParameterSpec generateIv() { + byte[] iv = new byte[16]; + new SecureRandom().nextBytes(iv); + return new IvParameterSpec(iv); + } + + + protected static byte[] encrypt(String algorithm, byte[] input, SecretKey key, IvParameterSpec iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{ + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.ENCRYPT_MODE, key, iv); + byte[] cipherText = cipher.doFinal(input); + return Base64.getEncoder().encode(cipherText); + } + + + protected static byte[] decryptByte(String algorithm, byte[] cipherText, SecretKey key, IvParameterSpec iv) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{ + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.DECRYPT_MODE, key, iv); + byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText)); + return plainText; + } + + protected static String decryptString(String algorithm, byte[] cipherText, SecretKey key, IvParameterSpec iv) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + return new String(SQLiteEncprytion.decryptByte(algorithm, cipherText, key, iv) ); + } + + + public static byte[] keyToByte(SecretKey key) { + return Base64.getEncoder().encode(key.getEncoded()); + } + + + public static SecretKey byteToKey(byte[] encodedKey) { + byte[] decodedKey = Base64.getDecoder().decode(encodedKey); + return new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); + } +} diff --git a/POO_Server/src/database/SQLiteManager.java b/POO_Server/src/database/SQLiteManager.java new file mode 100644 index 0000000..a1d32b2 --- /dev/null +++ b/POO_Server/src/database/SQLiteManager.java @@ -0,0 +1,563 @@ +package database; + +import java.io.File; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; + + +import main.Utilisateur; +import messages.MauvaisTypeMessageException; +import messages.Message; +import messages.MessageTexte; +import messages.Message.TypeMessage; +import messages.MessageFichier; + +public class SQLiteManager { + + private static final String DATABASE_RELATIVE_PATH = "../database"; + + public static String[] hardcodedNames = {"Olivia","Liam","Benjamin","Sophia","Charlotte","Noah","Elijah","Isabella", + "Oliver","Emma","William","Amelia","Evelyn","James","Mia","Ava","Lucas","Mason","Ethan","Harper"}; + + private Connection connec; + private int numDatabase; + private SecretKey dbDataKey; + + public SQLiteManager(int numDatabase) { + this.numDatabase = numDatabase; + + this.openConnection(); + + try { + + SQLiteCreateTables.createTableUser(this.connec); + SQLiteCreateTables.createTableConversation(this.connec); + SQLiteCreateTables.createTableType(this.connec); + SQLiteCreateTables.createTableMessage(this.connec); + + } catch (SQLException e) { + this.closeConnection(); + File db = new File("../database"+this.numDatabase+".db"); + if(db.delete()) { + System.out.println("supp"); + }else { + System.out.println("no supp"); + } + e.printStackTrace(); + } + + this.closeConnection(); + } + + private void openConnection() { + String url = "jdbc:sqlite:"+ DATABASE_RELATIVE_PATH + this.numDatabase + ".db"; + try { + //Class.forName("org.sqlite.JDBC"); + this.connec = DriverManager.getConnection(url); + System.out.println("Connection to bdd established"); + } catch (SQLException /*| ClassNotFoundException*/ e) { + System.out.println(e.getMessage()); + } + } + + private void closeConnection() { + try { + if (this.connec != null) { + this.connec.close(); + } + } catch (SQLException e) { + System.out.println(e.getMessage()); + } + + } + + public int insertAllMessages(ArrayList messages, String usernameSender, String usernameReceiver) throws SQLException{ + int nbRows = 0; + this.openConnection(); + + int idSender = this.getIDUser(usernameSender); + int idReceiver = this.getIDUser(usernameReceiver); + + if(idSender == -1) { + this.insertUser(usernameSender); + idSender = this.getIDUser(usernameSender); + } + + if(idReceiver == -1) { + this.insertUser(usernameReceiver); + idReceiver = this.getIDUser(usernameReceiver); + } + + int idConversation = getIDConversation(idSender, idReceiver); + + if(idConversation == -1) { + this.insertConversation(idSender, idReceiver); + idConversation = getIDConversation(idSender, idReceiver); + } + + IvParameterSpec ivConversation = this.getIvConversation(idConversation); + + this.connec.setAutoCommit(false); + + for(Message m : messages) { + try { + nbRows += this.insertMessage(idConversation, m, ivConversation); + } catch (SQLException e) { + e.printStackTrace(); + this.connec.rollback(); + } + } + + this.connec.commit(); + + this.closeConnection(); + + //System.out.println("Nombre de message(s) insérée(s) : " + nbRows); + + return nbRows; + } + + + public ArrayList getHistoriquesMessages(String usernameOther, String pseudoOther) throws SQLException { + + this.openConnection(); + + + ArrayList messages = new ArrayList(); + + String usernameSelf = Utilisateur.getSelf().getId(); + + int idSelf = this.getIDUser(usernameSelf); + int idOther = this.getIDUser(usernameOther); + + int idConversationSelf = this.getIDConversation(idSelf, idOther); + int idConversationOther = this.getIDConversation(idOther, idSelf); + IvParameterSpec ivConversation = this.getIvConversation(idConversationSelf); +// String str = "datetime(d1,'unixepoch','localtime')"; + + + String getHistoriqueRequest = "SELECT id_conversation, id_type, content, date, extension " + + "FROM message " + + "WHERE id_conversation IN (?,?) " + + "ORDER by date"; + + PreparedStatement prepStmt = this.connec.prepareStatement(getHistoriqueRequest); + prepStmt.setInt(1, idConversationSelf); + prepStmt.setInt(2, idConversationOther); + ResultSet res = prepStmt.executeQuery(); + + //Retrieve the messages one by one + //Create the appropriate message object depending on the type and sender/receiver + //and add the message in the list + while(res.next()) { + int idType = res.getInt("id_type"); + String type = this.getType(idType); + + String content = null; + try { + content = this.bytesToStringContent(res.getBytes("content"), ivConversation); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException + | SQLException e1) { + //System.out.println("erreur déchiffrement"); + } + + Message message = null; + String extension; + + if(!type.equals("")) { + try { + switch(type) { + case "text": + message = new MessageTexte(TypeMessage.TEXTE, content); + break; + case "file": + extension = res.getString("extension"); + message = new MessageFichier(TypeMessage.FICHIER, content, extension); + break; + default: + extension = res.getString("extension"); + message = new MessageFichier(TypeMessage.IMAGE, content, extension); + } + + } catch (MauvaisTypeMessageException e) { + e.printStackTrace(); + } + } + + if(res.getInt("id_conversation") == idConversationSelf) { + message.setSender("Moi"); + }else{ + message.setSender(pseudoOther); + } + message.setDateMessage(res.getString("date")); + if(content != null) { + messages.add(message); + } + + } + + + this.closeConnection(); + + return messages; + } + + + private void insertUser(String username) throws SQLException { + String insertUserRequest = "INSERT INTO user (username) " + "VALUES (?);"; + + PreparedStatement prepStmt = this.connec.prepareStatement(insertUserRequest); + prepStmt.setString(1, username); + prepStmt.executeUpdate(); + } + + + public int getIDUser(String username) throws SQLException { + String getIDRequest = "SELECT id " + " FROM user" + " WHERE username = ? ;"; + + PreparedStatement prepStmt = this.connec.prepareStatement(getIDRequest); + prepStmt.setString(1, username); + ResultSet res = prepStmt.executeQuery(); + + if (res.next()) { + return res.getInt("id"); + } + return -1; + + } + + + private void insertConversation(int idSender, int idReceiver) throws SQLException { + String insertConversationRequest = "INSERT INTO conversation (id_emetteur, id_recepteur, iv_conversation) " + "VALUES " + + "(?, ?, ?)," + + "(?, ?, ?);"; + + byte[] ivConversation = SQLiteEncprytion.generateIv().getIV(); + + PreparedStatement prepStmt = this.connec.prepareStatement(insertConversationRequest); + prepStmt.setInt(1, idSender); + prepStmt.setInt(2, idReceiver); + prepStmt.setBytes(3, ivConversation); + prepStmt.setInt(4, idReceiver); + prepStmt.setInt(5, idSender); + prepStmt.setBytes(6, ivConversation); + + prepStmt.executeUpdate(); + } + + + private int getIDConversation(int idSender, int idReceiver) throws SQLException { + String getIDRequest = "SELECT id_conversation " + "FROM conversation " + "WHERE id_emetteur = ? " + + "AND id_recepteur = ? ;"; + + PreparedStatement prepStmt = this.connec.prepareStatement(getIDRequest); + prepStmt.setInt(1, idSender); + prepStmt.setInt(2, idReceiver); + ResultSet res = prepStmt.executeQuery(); + + if (res.next()) { + return res.getInt("id_conversation"); + } + return -1; + } + + private IvParameterSpec getIvConversation(int idConversation) throws SQLException { + String getIvRequest = "SELECT iv_conversation " + "FROM conversation " + "WHERE id_conversation = ?;"; + + PreparedStatement prepStmt = this.connec.prepareStatement(getIvRequest); + prepStmt.setInt(1, idConversation); + ResultSet res = prepStmt.executeQuery(); + + if (res.next()) { + return new IvParameterSpec(res.getBytes("iv_conversation")); + } + + return null; + } + + + + + private int getIDType(String label) throws SQLException { + String getIDRequest = "SELECT id_type FROM type WHERE label = ?;"; + + PreparedStatement prepStmt = this.connec.prepareStatement(getIDRequest); + prepStmt.setString(1, label); + + ResultSet res = prepStmt.executeQuery(); + + if (res.next()) { + return res.getInt("id_type"); + } + return -1; + } + + + private String getType(int idType) throws SQLException { + String getTypeRequest = "SELECT label FROM type WHERE id_type = ?;"; + + PreparedStatement prepStmt = this.connec.prepareStatement(getTypeRequest); + prepStmt.setInt(1, idType); + + ResultSet res = prepStmt.executeQuery(); + + if(res.next()) { + return res.getString("label"); + } + + return ""; + + } + + + private byte[] stringToBytesContent(Message m, IvParameterSpec iv) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + String content; + if (m.getTypeMessage() == TypeMessage.TEXTE) { + MessageTexte messageTxt = (MessageTexte) m; + content = messageTxt.getContenu(); + }else { + MessageFichier messageFichier = (MessageFichier) m; + content = messageFichier.getContenu(); + } + byte[] encryptedContent = SQLiteEncprytion.encrypt(SQLiteEncprytion.encryptAlgorithm, content.getBytes(), this.dbDataKey, iv); + return encryptedContent; + + } + + private String bytesToStringContent(byte[] encryptedContent, IvParameterSpec iv) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + return SQLiteEncprytion.decryptString(SQLiteEncprytion.encryptAlgorithm, encryptedContent, this.dbDataKey, iv); + } + + + private String processMessageType(Message m) { + switch (m.getTypeMessage()) { + case TEXTE: return "text"; + case FICHIER: return "file"; + case IMAGE: return "image"; + default: return ""; + } + } + + private String processExtension(Message m) { + if(m.getTypeMessage() == TypeMessage.TEXTE) { + return null; + }else { + MessageFichier mFile = (MessageFichier) m; + return mFile.getExtension(); + } + } + + + private int insertMessage(int idConversation, Message m, IvParameterSpec iv) throws SQLException { + + + String dateMessage = m.getDateMessage(); + String extension = this.processExtension(m); + String type = this.processMessageType(m); + int idType = this.getIDType(type); + + byte[] content = null; + + try { + content = this.stringToBytesContent(m, iv); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { + + e.printStackTrace(); + } + + String insertMessageRequest = "INSERT INTO message(id_conversation, id_type, content, date, extension) " + + "VALUES (?, ?, ?, ?, ?);"; + + PreparedStatement prepStmt = this.connec.prepareStatement(insertMessageRequest); + prepStmt.setInt(1, idConversation); + prepStmt.setInt(2, idType); + prepStmt.setBytes(3, content); + prepStmt.setString(4, dateMessage); + prepStmt.setString(5, extension); + + int nbRows = prepStmt.executeUpdate(); + + return nbRows; + } + + public void createNewUserEncrypt(String username, String password) { + + + String algo = SQLiteEncprytion.encryptAlgorithm; + + KeyGenerator keyGen = null; + try { + keyGen = KeyGenerator.getInstance("AES"); + keyGen.init(256); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + byte[] passwordSalt = SQLiteEncprytion.getNextSalt(); + byte[] dbDataKeySalt = SQLiteEncprytion.getNextSalt(); + + SecretKey dbDataKey = keyGen.generateKey(); + + SecretKey dbDataEncryptKey = SQLiteEncprytion.getKey(password.toCharArray(), dbDataKeySalt); + IvParameterSpec ivDbDataKey = SQLiteEncprytion.generateIv(); + + byte[] passwordHash = SQLiteEncprytion.hash(password.toCharArray(), passwordSalt); + + byte[] dbDataKeyEncrypted = null; + byte[] encryptedPasswordHash = null; + + try { + dbDataKeyEncrypted = SQLiteEncprytion.encrypt( + algo, SQLiteEncprytion.keyToByte(dbDataKey), dbDataEncryptKey, ivDbDataKey); + encryptedPasswordHash = SQLiteEncprytion.encrypt( + algo, passwordHash , dbDataKey, ivDbDataKey); + + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + this.openConnection(); + + String createUserRequest = "INSERT INTO user(username, pwd_salt, db_datakey_salt, encrypted_pwd_hashsalt, encrypted_db_datakey, iv_datakey) " + + "VALUES (?, ?, ?, ?, ?, ?); "; + + PreparedStatement prepStmt = null; + try { + prepStmt = this.connec.prepareStatement(createUserRequest); + prepStmt.setString(1, username); + prepStmt.setBytes(2, passwordSalt); + prepStmt.setBytes(3, dbDataKeySalt); + prepStmt.setBytes(4, encryptedPasswordHash); + prepStmt.setBytes(5, dbDataKeyEncrypted); + prepStmt.setBytes(6, ivDbDataKey.getIV()); + + } catch (SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + prepStmt.executeUpdate(); + System.out.println("Utilisateur crée"); + } catch (SQLException e) { + System.out.println("Nom d'utilisateur déjà pris"); + } + + this.closeConnection(); + + } + + /** + * + * @param username + * @param password + * @return -1 if user do not exists, + * 0 if password incorrect, + * 1 if password correct + * @throws SQLException + */ + public int checkPwd(String username, char[] password) throws SQLException { + + this.openConnection(); + + String selectUserDataRequest = "SELECT pwd_salt, db_datakey_salt, encrypted_pwd_hashsalt, encrypted_db_datakey, iv_datakey " + + "FROM user " + + "WHERE username = ?;"; + PreparedStatement prepStmt; + prepStmt = this.connec.prepareStatement(selectUserDataRequest); + prepStmt.setString(1, username); + + ResultSet res = prepStmt.executeQuery(); + if(!res.next()) { + return -1; + } + + byte[] passwordSalt = res.getBytes("pwd_salt"); + byte[] dbDataKeySalt = res.getBytes("db_datakey_salt"); + + SecretKey dbDataEncryptKey = SQLiteEncprytion.getKey(password, dbDataKeySalt); + IvParameterSpec iv = new IvParameterSpec(res.getBytes("iv_datakey")); + + byte[] encryptedDbDataKey = res.getBytes("encrypted_db_datakey"); + + + SecretKey dbDataKey = null; + try { + dbDataKey = SQLiteEncprytion.byteToKey( + SQLiteEncprytion.decryptByte(SQLiteEncprytion.encryptAlgorithm, encryptedDbDataKey, dbDataEncryptKey, iv) + ); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { + //System.out.println("Problème déchiffrement clé db"); + } + + this.dbDataKey = dbDataKey; + + byte[] encryptedPasswordHash = res.getBytes("encrypted_pwd_hashsalt"); + + + byte[] passwordHash = SQLiteEncprytion.hash(password, passwordSalt); + + this.closeConnection(); + + boolean checkHash = this.checkHashPwd(passwordHash ,encryptedPasswordHash, dbDataKey, iv); + if(checkHash) { + return 1; + } + return 0; + } + + + private boolean checkHashPwd(byte[] passwordHash, byte[] encryptedPasswordHash, SecretKey dbDataKey, IvParameterSpec iv) { + + byte[] expectedHash = "".getBytes(); + try { + expectedHash = SQLiteEncprytion.decryptByte(SQLiteEncprytion.encryptAlgorithm, encryptedPasswordHash, dbDataKey, iv); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException + | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { + } + + + + if (passwordHash.length != expectedHash.length) return false; + for (int i = 0; i < passwordHash.length; i++) { + if (passwordHash[i] != expectedHash[i]) return false; + } + return true; + } + + + public static void main(String[] args) { + String[] hardcodedNames = {"Olivia","Liam","Benjamin","Sophia","Charlotte","Noah","Elijah","Isabella", + "Oliver","Emma","William","Amelia","Evelyn","James","Mia","Ava","Lucas","Mason","Ethan","Harper"}; + + String pwdPrefix = "aze1$"; + + SQLiteManager sqlManager = new SQLiteManager(0); + + for(int i=0; i remoteUsers; + private SQLiteManager sqlManager; public ServletPresence() { //A changer en passant aux IP @@ -44,6 +47,8 @@ public class ServletPresence extends HttpServlet implements Observer { } catch (UnknownHostException e) { e.printStackTrace(); } + + sqlManager = new SQLiteManager(0); } private int getIndexByID(String id) { @@ -133,6 +138,19 @@ public class ServletPresence extends HttpServlet implements Observer { out.println( "" ); } + //Affiche un message d'erreur en cas de requête invalide + private void printErrorUnkwownUser(PrintWriter out) { + out.println( "" ); + out.println( ""); + out.println( "Erreur Utilisateur Inconnu" ); + out.println( "" ); + out.println( "" ); + out.println( "

Erreur : l'id que vous avez entrée n'est pas enregistrée

" ); + out.println( "

Veuillez vérifier votre syntaxe et réessayer

" ); + out.println( "" ); + out.println( "" ); + } + //Informe de la modification de la liste tous les utilisateurs internes et externes private void snotify(MessageSysteme message, Utilisateur user) { @@ -164,22 +182,32 @@ public class ServletPresence extends HttpServlet implements Observer { response.setContentType( "text/html" ); PrintWriter out = response.getWriter(); - //Si le pseudo est déjà pris : génère du html pour en informer l'utilisateur - if (comUDP.containsUserFromPseudo(pseudo)||remoteContainsUserFromPseudo(pseudo)) { - printErrorUsedPseudo(out); - } - - //Sinon - else { - Utilisateur user = new Utilisateur(id, pseudo, ip, port); - remoteUsers.add(user); - try { - snotify(new MessageSysteme(Message.TypeMessage.INFO_PSEUDO, pseudo, id, 3334), user); - } catch (MauvaisTypeMessageException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + //Si l'id n'existe pas dans la BDD : génère du html pour en informer l'utilisateur + try { + if (sqlManager.getIDUser(id)==-1) { + printErrorUnkwownUser(out); } - printActiveUsersOnly(out); + + //Si le pseudo est déjà pris : idem + else if (comUDP.containsUserFromPseudo(pseudo)||remoteContainsUserFromPseudo(pseudo)) { + printErrorUsedPseudo(out); + } + + //Sinon + else { + Utilisateur user = new Utilisateur(id, pseudo, ip, port); + remoteUsers.add(user); + try { + snotify(new MessageSysteme(Message.TypeMessage.INFO_PSEUDO, pseudo, id, 3334), user); + } catch (MauvaisTypeMessageException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + printActiveUsersOnly(out); + } + } catch (UnknownHostException | SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } out.close(); } @@ -190,7 +218,7 @@ public class ServletPresence extends HttpServlet implements Observer { Utilisateur user = remoteUsers.get(index); remoteUsers.remove(index); try { - snotify(new MessageSysteme(Message.TypeMessage.JE_SUIS_DECONNECTE, id), user); + snotify(new MessageSysteme(Message.TypeMessage.JE_SUIS_DECONNECTE,"", id, -1), user); } catch (MauvaisTypeMessageException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/POO_Server/src/messages/Message.java b/POO_Server/src/messages/Message.java index 334f39c..fc5c65b 100644 --- a/POO_Server/src/messages/Message.java +++ b/POO_Server/src/messages/Message.java @@ -1,21 +1,46 @@ package messages; import java.io.Serializable; -import java.lang.instrument.Instrumentation; -import java.util.Arrays; - -import messages.Message.TypeMessage; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; public abstract class Message implements Serializable { - public enum TypeMessage {JE_SUIS_CONNECTE, JE_SUIS_DECONNECTE, INFO_PSEUDO, TEXTE, IMAGE, FICHIER, MESSAGE_NUL} + public enum TypeMessage {JE_SUIS_CONNECTE, JE_SUIS_DECONNECTE, INFO_PSEUDO, TEXTE, IMAGE, FICHIER, MESSAGE_NUL, FICHIER_INIT, FICHIER_ANSWER} protected TypeMessage type; + private String dateMessage; + private String sender; private static final long serialVersionUID = 1L; - private static Instrumentation inst; - + + + public static String getDateAndTime() { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + LocalDateTime now = LocalDateTime.now(); + return dtf.format(now); + } + + public TypeMessage getTypeMessage() { return this.type; } + + public void setDateMessage(String dateMessage) { + this.dateMessage = dateMessage; + } + + public String getDateMessage() { + return this.dateMessage; + } + + public String getSender() { + return this.sender ; + } + + public void setSender(String sender) { + this.sender = sender; + } + + protected abstract String attributsToString(); @@ -28,10 +53,10 @@ public abstract class Message implements Serializable { String[] parts = messageString.split("###"); switch (parts[0]) { case "JE_SUIS_CONNECTE" : - return new MessageSysteme(TypeMessage.JE_SUIS_CONNECTE, parts[2]); + return new MessageSysteme(TypeMessage.JE_SUIS_CONNECTE); case "JE_SUIS_DECONNECTE" : - return new MessageSysteme(TypeMessage.JE_SUIS_DECONNECTE, parts[2]); + return new MessageSysteme(TypeMessage.JE_SUIS_DECONNECTE, parts[1], parts[2], Integer.parseInt(parts[3]) ); case "INFO_PSEUDO" : return new MessageSysteme(TypeMessage.INFO_PSEUDO, parts[1], parts[2], Integer.parseInt(parts[3]) ); @@ -51,8 +76,8 @@ public abstract class Message implements Serializable { //tests ici public static void main(String[] args) throws MauvaisTypeMessageException { - Message m1 = new MessageSysteme(TypeMessage.JE_SUIS_CONNECTE, "sahiu"); - Message m2 = new MessageSysteme(TypeMessage.JE_SUIS_DECONNECTE, "putbezfjk"); + Message m1 = new MessageSysteme(TypeMessage.JE_SUIS_CONNECTE); + Message m2 = new MessageSysteme(TypeMessage.JE_SUIS_DECONNECTE,"aker", "man", 5000); Message m3 = new MessageSysteme(TypeMessage.INFO_PSEUDO, "pseudo156434518", "id236", 1500); Message m4 = new MessageTexte(TypeMessage.TEXTE, "blablabla"); Message m5 = new MessageFichier(TypeMessage.FICHIER, "truc", ".pdf"); diff --git a/POO_Server/src/messages/MessageFichier.java b/POO_Server/src/messages/MessageFichier.java index aa8f0bf..15b2ded 100644 --- a/POO_Server/src/messages/MessageFichier.java +++ b/POO_Server/src/messages/MessageFichier.java @@ -1,7 +1,5 @@ package messages; -import messages.Message.TypeMessage; - public class MessageFichier extends Message { @@ -10,10 +8,11 @@ public class MessageFichier extends Message { private String extension; public MessageFichier(TypeMessage type, String contenu, String extension) throws MauvaisTypeMessageException{ - if ((type==TypeMessage.IMAGE)||(type==TypeMessage.FICHIER)) { + if ((type==TypeMessage.IMAGE)||(type==TypeMessage.FICHIER) ||(type==TypeMessage.FICHIER_INIT) || (type==TypeMessage.FICHIER_ANSWER) ) { this.type=type; this.contenu=contenu; this.extension=extension; + this.setDateMessage(Message.getDateAndTime()); } else throw new MauvaisTypeMessageException(); } @@ -30,4 +29,18 @@ public class MessageFichier extends Message { protected String attributsToString() { return this.contenu+"###"+this.extension; } + + public String toString() { + if(this.type == TypeMessage.IMAGE) { + return this.contenu; + }else { + String suffixe; + if(this.getSender().equals("Moi")) { + suffixe = "envoyé\n"; + }else { + suffixe = "reçu\n"; + } + return "<"+this.getDateMessage()+"> : "+this.contenu+" "+suffixe; + } + } } \ No newline at end of file diff --git a/POO_Server/src/messages/MessageSysteme.java b/POO_Server/src/messages/MessageSysteme.java index 06d3e07..9c76271 100644 --- a/POO_Server/src/messages/MessageSysteme.java +++ b/POO_Server/src/messages/MessageSysteme.java @@ -7,18 +7,18 @@ public class MessageSysteme extends Message { private String id; private int port; - public MessageSysteme(TypeMessage type, String id) throws MauvaisTypeMessageException{ - if ((type==TypeMessage.JE_SUIS_CONNECTE)||(type==TypeMessage.JE_SUIS_DECONNECTE)||(type==TypeMessage.MESSAGE_NUL)) { + public MessageSysteme(TypeMessage type) throws MauvaisTypeMessageException{ + if ((type==TypeMessage.JE_SUIS_CONNECTE)||(type==TypeMessage.MESSAGE_NUL)) { this.type=type; this.pseudo=""; - this.id=id; + this.id=""; this.port = -1; } else throw new MauvaisTypeMessageException(); } public MessageSysteme(TypeMessage type, String pseudo, String id, int port) throws MauvaisTypeMessageException { - if (type==TypeMessage.INFO_PSEUDO) { + if (type==TypeMessage.INFO_PSEUDO ||(type==TypeMessage.JE_SUIS_DECONNECTE)) { this.type=type; this.pseudo=pseudo; this.id=id; @@ -27,6 +27,7 @@ public class MessageSysteme extends Message { else throw new MauvaisTypeMessageException(); } + public String getPseudo() { return this.pseudo; } diff --git a/POO_Server/src/messages/MessageTexte.java b/POO_Server/src/messages/MessageTexte.java index e5d354d..434598b 100644 --- a/POO_Server/src/messages/MessageTexte.java +++ b/POO_Server/src/messages/MessageTexte.java @@ -1,17 +1,17 @@ package messages; -import messages.Message.TypeMessage; - public class MessageTexte extends Message { private static final long serialVersionUID = 1L; private String contenu; + public MessageTexte(TypeMessage type, String contenu) throws MauvaisTypeMessageException{ if (type==TypeMessage.TEXTE) { this.type=type; this.contenu=contenu; + this.setDateMessage(Message.getDateAndTime()); } else throw new MauvaisTypeMessageException(); } @@ -19,9 +19,15 @@ public class MessageTexte extends Message { public String getContenu() { return this.contenu; } + @Override protected String attributsToString() { return this.contenu; } + + @Override + public String toString() { + return "<"+this.getDateMessage()+"> "+this.getSender()+" : "+this.contenu+"\n"; + } } \ No newline at end of file diff --git a/database0.db b/database0.db new file mode 100644 index 0000000..3c04169 Binary files /dev/null and b/database0.db differ diff --git a/javax.servlet-api-3.1.0.jar b/javax.servlet-api-3.1.0.jar new file mode 100644 index 0000000..6b14c3d Binary files /dev/null and b/javax.servlet-api-3.1.0.jar differ diff --git a/sqlite-jdbc-3.32.3.2.jar b/sqlite-jdbc-3.32.3.2.jar new file mode 100644 index 0000000..b6f55b7 Binary files /dev/null and b/sqlite-jdbc-3.32.3.2.jar differ