[VRAC] Corrections de bug #1/?

Bug détectés restants :
 - MainFrame pas mise à jour avec le compte utilisateur connecté lorsqu'on switch dessus depuis la StartFrame
 - Le serveur renvoie REFUSED_QUERY lorsqu'on tente de se déconnecter
This commit is contained in:
Notmoo-PC\Notmoo 2017-11-01 21:22:23 +01:00
parent d697c1b123
commit aad90bb989
15 changed files with 183 additions and 22 deletions

View File

@ -58,9 +58,12 @@ public class Main extends Application{
}
private IStartupFrameModelListener getStartupFrameListener(Stage primaryStage, Scene sceneToDisplay){
return () -> trySwitchScene(primaryStage, sceneToDisplay, true);
return () -> {
Platform.runLater(()->trySwitchScene(primaryStage, sceneToDisplay, true));
};
}
private IMainFrameModelListener getMainFrameListener(Stage primaryStage, Scene sceneToDisplay){
return () -> trySwitchScene(primaryStage, sceneToDisplay, false);
}

View File

@ -35,7 +35,7 @@ public class StartupFrameController implements IStartupFrameModelListener {
view.getAccountUsernameTextFieldContent(),
view.getAccountPasswordTextFieldContent()
);
}catch(NullPointerException | IllegalArgumentException e){
}catch(Exception e){
view.displayError(GUIStringTool.getExceptionFormatter().render(e));
}
}

View File

@ -2,6 +2,7 @@ package com.pqt.client.gui.startup_frame;
import com.pqt.client.gui.startup_frame.listeners.procedure.IStartupProcedureEventFirerer;
import com.pqt.client.gui.startup_frame.listeners.procedure.IStartupProcedureListener;
import com.pqt.client.gui.startup_frame.listeners.procedure.SimpleStartupProcedureEventFirerer;
import com.pqt.client.module.account.AccountService;
import com.pqt.client.module.account.listeners.AccountListenerAdapter;
import com.pqt.client.module.account.listeners.IAccountListener;
@ -22,6 +23,7 @@ class StartupProcedureHandler {
StartupProcedureHandler(NetworkService networkService, AccountService accountService) {
this.networkService = networkService;
this.accountService = accountService;
firerer = new SimpleStartupProcedureEventFirerer();
}
StartupProcedureHandler init(String host, Integer port, String username, String password){
@ -39,13 +41,13 @@ class StartupProcedureHandler {
private void testConnection(){
networkService.addListener(getPingListener());
networkService.setActiveServer(host, port);
networkService.sendPQTPing(host, port);
}
private void useRequestedServer(){
//Server found
firerer.fireServerFoundEvent(host, port);
networkService.setActiveServer(host, port);
accountService.addListener(getUpdateAccountListListener());
accountService.refreshAccounts();
}

View File

@ -1,6 +1,7 @@
package com.pqt.client.module.connection.senders;
import com.pqt.client.module.connection.listeners.IConnectionListener;
import com.sun.javafx.binding.StringFormatter;
import java.io.BufferedReader;
import java.io.DataOutputStream;
@ -14,7 +15,10 @@ public class HttpTextSender implements ITextSender{
@Override
public void send(String url, String text, IConnectionListener listener) {
try {
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
String trueURL = String.format("http://%s?message=%s", url, text);
HttpURLConnection con = (HttpURLConnection) new URL(trueURL).openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type", "application/json");
con.setConnectTimeout(5000);

View File

@ -73,7 +73,9 @@ public class NetworkService {
}
public void setActiveServer(String host, Integer port){
connectionService.setServerUrl(String.format("%s:%s", host, port));
//TODO changer le nom de context de la webapp
String webAppContext = "pqt-server";
connectionService.setServerUrl(String.format("%s:%s/%s", host, port, webAppContext));
}
private void sendConfigRequest(String host, Integer port){

View File

@ -4,6 +4,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
@ -20,13 +21,55 @@ public class GSonMessageToolFactory implements IMessageToolFactory {
return (obj)->gson.toJson(obj);
}
public <T> IObjectParser<T> getObjectParser(Class<T> clazz){
return (str)->gson.fromJson(str, clazz);
return (str)->gson.fromJson(str, new Element<>(clazz));
}
public <T> IObjectFormatter<List<T>> getListFormatter(Class<T> clazz){
return (obj)->gson.toJson(obj);
}
public <T> IObjectParser<List<T>> getListParser(Class<T> clazz){
Type listType = new TypeToken<ArrayList<T>>(){}.getType();
return (str)->gson.fromJson(str, listType);
//Type listType = new TypeToken<ArrayList<T>>(){}.getType();
return (str)->gson.fromJson(str, new ListWithElements<>(clazz));
}
private class Element<T> implements ParameterizedType {
private Class<T> cl;
public Element(Class<T> cl) {
this.cl = cl;
}
public Type[] getActualTypeArguments() {
return new Type[] {cl};
}
public Type getRawType() {
return cl;
}
public Type getOwnerType() {
return null;
}
}
private class ListWithElements<T> implements ParameterizedType {
private Class<T> elementsClass;
public ListWithElements(Class<T> elementsClass) {
this.elementsClass = elementsClass;
}
public Type[] getActualTypeArguments() {
return new Type[] {elementsClass};
}
public Type getRawType() {
return List.class;
}
public Type getOwnerType() {
return null;
}
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
<context-param>
<param-name>res-file.location</param-name>
<param-value>G:\temp\</param-value>
</context-param>
</web-app>

View File

@ -5,6 +5,7 @@ import com.pqt.core.entities.user_account.AccountLevel;
import com.pqt.server.tools.io.ISerialFileManager;
import com.pqt.server.tools.io.SimpleSerialFileManagerFactory;
import com.pqt.server.tools.security.IHashTool;
import com.pqt.server.tools.security.RandomString;
import com.pqt.server.tools.security.SHA256HashTool;
import java.util.*;
@ -22,19 +23,22 @@ import java.util.stream.Collectors;
* Cette classe manipule les mot de passe sous forme chiffrée via un système de hash (SHA-256) + salt, et ne fait pas
* persister les mots de passes non-chiffrées. Les noms d'utilisateurs sont stockés sans chiffrage.
*/
class FileAccountDao implements IAccountDao {
public class FileAccountDao implements IAccountDao {
private static final String ACCOUNT_FILE_NAME = "acc.pqt";
//TODO to modify
private static final String ACCOUNT_FILE_NAME = "G:\\temp\\acc.pqt";
private Set<AccountEntry> accountEntries;
private Set<AccountEntry> connectedAccount;
private IHashTool hashTool;
private RandomString randomString;
private ISerialFileManager<AccountEntry> fileManager;
FileAccountDao() {
public FileAccountDao() {
accountEntries = new HashSet<>();
connectedAccount = new HashSet<>();
hashTool = new SHA256HashTool();
randomString = new RandomString(10);
fileManager = SimpleSerialFileManagerFactory.getFileManager(AccountEntry.class, ACCOUNT_FILE_NAME);
loadFromFile();
}
@ -96,7 +100,7 @@ class FileAccountDao implements IAccountDao {
}
/**
* Passe un comtpe connecté dans l'état déconnecté. N'effectue le changement que si un compte connecté correspond
* Passe un compte connecté dans l'état déconnecté. N'effectue le changement que si un compte connecté correspond
* aux données fournies.
* @param account données à utiliser pour efffectuer la correspondance avec un compte
* @return {@code true} si le changement d'état a eu lieu, {@code false sinon}
@ -134,6 +138,18 @@ class FileAccountDao implements IAccountDao {
fileManager.saveSetToFile(accountEntries);
}
public boolean addAccount(Account account){
if(accountEntries.stream().filter(accountEntry -> accountEntry.getUsername().equals(account.getUsername())).count()==0) {
String salt = randomString.nextString();
String passwordHash = hashTool.hashAndSalt(account.getPassword(), salt);
accountEntries.add(new AccountEntry(account.getUsername(), passwordHash, salt, account.getPermissionLevel()));
saveToFile();
return true;
}else{
return false;
}
}
/**
* Charge les données des comptes depuis le fichier de sauvegarde.
* <p/>

View File

@ -16,7 +16,7 @@ import java.util.List;
*
* @author Guillaume "Cess" Prost
*/
interface IAccountDao {
public interface IAccountDao {
/**
* @see AccountService#isAccountConnected(Account)
@ -59,4 +59,14 @@ interface IAccountDao {
* de données.
*/
List<Account> getAccountList();
/**
* Ajoute un objet {@link Account} dans la collection de comptes utilisateurs.
* <p/>
* Les implémentations doivent en outre effectuer une vérification pour s'assurer que le compte à rajouter ne pas
* un nom d'utilisateur qui existe déjà. Dans ce cas de figure, l'ajout du nouveau compte doit échouer.
* @param account
* @return
*/
boolean addAccount(Account account);
}

View File

@ -19,14 +19,15 @@ import java.util.*;
*/
public class FileStockDao implements IStockDao {
private static final String STOCK_FILE_NAME = "stock.pqt";
//TODO to modify
private static final String STOCK_FILE_NAME = "G:\\temp\\stock.pqt";
private ISerialFileManager<Product> fileManager;
private long nextProductId;
private Random random;
private Map<Long, Product> products;
FileStockDao() {
public FileStockDao() {
random = new Random();
fileManager = SimpleSerialFileManagerFactory.getFileManager(Product.class, STOCK_FILE_NAME);
loadFromFile();

View File

@ -28,10 +28,16 @@ public class QueryServlet extends HttpServlet {
IMessageToolFactory messageToolFactory = new GSonMessageToolFactory();
IMessageHandler msgHandler = new SimpleMessageHandler();
if (request.getParameter("message") != null) {
Message resp = msgHandler.handleMessage(messageToolFactory.getObjectParser(Message.class).parse(request.getParameter("message")));
if (request.getQueryString() != null && !request.getQueryString().isEmpty() && request.getParameter("message")!=null) {
try {
Message resp = msgHandler.handleMessage(messageToolFactory.getObjectParser(Message.class).parse(request.getParameter("message")));
response.getWriter().write(messageToolFactory.getObjectFormatter(Message.class).format(resp));
response.getWriter().write(messageToolFactory.getObjectFormatter(Message.class).format(resp));
}catch(Exception e){
response.getWriter().write(String.format("%s : %s", e.getClass().getName(), e.getMessage()));
}
}else{
response.getWriter().write("Query message was not correctly made : "+request.getQueryString());
}
}
}

View File

@ -23,7 +23,7 @@ public class FileUtil {
* @throws IOException if any IOException happend during this method's execution.
*/
public static boolean createFileIfNotExist(Path filePath) throws IOException {
if(FileUtil.exist(filePath)){
if(!FileUtil.exist(filePath)){
Files.createFile(filePath);
return true;
}

View File

@ -38,7 +38,7 @@ public class SimpleSerialFileManager<T> implements ISerialFileManager<T> {
}catch(IOException | ClassNotFoundException e){
e.printStackTrace();
}
return null;
return new ArrayList<>();
}
@Override
@ -52,7 +52,7 @@ public class SimpleSerialFileManager<T> implements ISerialFileManager<T> {
}catch(IOException | ClassNotFoundException e){
e.printStackTrace();
}
return null;
return new HashSet<>();
}
private void fillCollection(Collection<T> collection) throws IOException, ClassNotFoundException {

View File

@ -1,12 +1,13 @@
package com.pqt.server.tools.io;
import java.nio.file.Path;
import java.nio.file.Paths;
public class SimpleSerialFileManagerFactory {
protected SimpleSerialFileManagerFactory(){}
public static <T> ISerialFileManager<T> getFileManager(Class<T> clazz, String filePath){
return new SimpleSerialFileManager<>(filePath, clazz);
return SimpleSerialFileManagerFactory.getFileManager(clazz, Paths.get(filePath));
}
public static <T> ISerialFileManager<T> getFileManager(Class<T> clazz, Path filePath){

View File

@ -0,0 +1,62 @@
package com.pqt.server.tools.security;
import java.security.SecureRandom;
import java.util.Locale;
import java.util.Objects;
import java.util.Random;
public class RandomString {
/**
* Generate a random string.
*/
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx)
buf[idx] = symbols[random.nextInt(symbols.length)];
return new String(buf);
}
public static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String lower = upper.toLowerCase(Locale.ROOT);
public static final String digits = "0123456789";
public static final String alphanum = upper + lower + digits;
private final Random random;
private final char[] symbols;
private final char[] buf;
public RandomString(int length, Random random, String symbols) {
if (length < 1) throw new IllegalArgumentException();
if (symbols.length() < 2) throw new IllegalArgumentException();
this.random = Objects.requireNonNull(random);
this.symbols = symbols.toCharArray();
this.buf = new char[length];
}
/**
* Create an alphanumeric string generator.
*/
public RandomString(int length, Random random) {
this(length, random, alphanum);
}
/**
* Create an alphanumeric strings from a secure generator.
*/
public RandomString(int length) {
this(length, new SecureRandom());
}
/**
* Create session identifiers.
*/
public RandomString() {
this(21);
}
}