From 5e206cb063c209ebf56bc83c33f2906167f734f4 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Fri, 21 Apr 2017 20:15:44 +0200
Subject: [PATCH] Fixed #77 - whitelist for host/ips with self-signed
 certificates

-connection error detail message added to alert text
-fixed prorgram not starting if settings.json is missing
---
 .../budgetmaster/logic/ServerConnection.java  |  6 ++--
 .../budgetmaster/logic/Settings.java          | 15 ++++++++-
 .../budgetmaster/ui/CategoryController.java   |  2 +-
 .../budgetmaster/ui/Controller.java           |  8 +++--
 .../budgetmaster/ui/HomeController.java       |  9 ++++--
 .../ui/NewCategoryController.java             |  4 +--
 .../budgetmaster/ui/NewPaymentController.java | 10 +++---
 .../budgetmaster/ui/PaymentController.java    |  6 ++--
 .../budgetmaster/ui/SettingsController.java   | 31 +++++++++++++++++++
 .../budgetmaster/ui/SettingsTab.fxml          | 21 +++++++++++--
 10 files changed, 91 insertions(+), 21 deletions(-)

diff --git a/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java b/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java
index b6a04d740..c26597f25 100644
--- a/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java
+++ b/src/de/deadlocker8/budgetmaster/logic/ServerConnection.java
@@ -48,8 +48,10 @@ public class ServerConnection
 		// Install the all-trusting trust manager
 		SSLContext sc = SSLContext.getInstance("SSL");
 		sc.init(null, trustAllCerts, new java.security.SecureRandom());
-		HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
-		HttpsURLConnection.setDefaultHostnameVerifier((hostname, sslSession) -> hostname.equals("localhost"));
+		HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());		
+		
+		//check whitelist
+		HttpsURLConnection.setDefaultHostnameVerifier((hostname, sslSession)->settings.getTrustedHosts().contains(hostname));		
 	}
 
 	/*
diff --git a/src/de/deadlocker8/budgetmaster/logic/Settings.java b/src/de/deadlocker8/budgetmaster/logic/Settings.java
index 84a6b6ff5..f95ce9620 100644
--- a/src/de/deadlocker8/budgetmaster/logic/Settings.java
+++ b/src/de/deadlocker8/budgetmaster/logic/Settings.java
@@ -1,11 +1,14 @@
 package de.deadlocker8.budgetmaster.logic;
 
+import java.util.ArrayList;
+
 public class Settings
 {
 	private String url;
 	private String secret;
 	private String currency;
 	private boolean restActivated;
+	private ArrayList<String> trustedHosts;
 	
 	public Settings()
 	{
@@ -51,10 +54,20 @@ public class Settings
 	{
 		this.restActivated = restActivated;
 	}
+	
+	public ArrayList<String> getTrustedHosts()
+	{
+		return trustedHosts;
+	}
+
+	public void setTrustedHosts(ArrayList<String> trustedHosts)
+	{
+		this.trustedHosts = trustedHosts;
+	}
 
 	@Override
 	public String toString()
 	{
-		return "Settings [url=" + url + ", secret=" + secret + ", currency=" + currency + ", restActivated=" + restActivated + "]";
+		return "Settings [url=" + url + ", secret=" + secret + ", currency=" + currency + ", restActivated=" + restActivated + ", trustedHosts=" + trustedHosts + "]";
 	}
 }
\ No newline at end of file
diff --git a/src/de/deadlocker8/budgetmaster/ui/CategoryController.java b/src/de/deadlocker8/budgetmaster/ui/CategoryController.java
index 0cdb686ec..33cbba28c 100644
--- a/src/de/deadlocker8/budgetmaster/ui/CategoryController.java
+++ b/src/de/deadlocker8/budgetmaster/ui/CategoryController.java
@@ -162,7 +162,7 @@ public class CategoryController implements Refreshable
 		catch(Exception e)
 		{
 			e.printStackTrace();
-			controller.showConnectionErrorAlert();
+			controller.showConnectionErrorAlert(e.getMessage());
 		}
 	}
 	
diff --git a/src/de/deadlocker8/budgetmaster/ui/Controller.java b/src/de/deadlocker8/budgetmaster/ui/Controller.java
index 0c7c7cbf7..59ae5fa8c 100644
--- a/src/de/deadlocker8/budgetmaster/ui/Controller.java
+++ b/src/de/deadlocker8/budgetmaster/ui/Controller.java
@@ -1,6 +1,7 @@
 package de.deadlocker8.budgetmaster.ui;
 
 import java.io.IOException;
+import java.net.ConnectException;
 import java.util.ArrayList;
 import java.util.Locale;
 import java.util.ResourceBundle;
@@ -228,7 +229,7 @@ public class Controller
 		return currentDate;
 	}
 
-	public void showConnectionErrorAlert()
+	public void showConnectionErrorAlert(String errorMessage)
 	{
 		if(!alertIsShowing)
 		{
@@ -237,7 +238,8 @@ public class Controller
 				Alert alert = new Alert(AlertType.ERROR);
 				alert.setTitle("Fehler");
 				alert.setHeaderText("");
-				alert.setContentText("Beim Herstellen der Verbindung zum Server ist ein Fehler aufgetreten. Bitte überprüfe deine Einstellungen und ob der Server läuft.");
+				alert.setContentText("Beim Herstellen der Verbindung zum Server ist ein Fehler aufgetreten. Bitte überprüfe deine Einstellungen und ob der Server läuft.\n\n"
+						+ "Fehlerdetails:\n" + errorMessage);
 				Stage dialogStage = (Stage)alert.getDialogPane().getScene().getWindow();
 				dialogStage.getIcons().add(icon);
 				dialogStage.initOwner(stage);
@@ -313,7 +315,7 @@ public class Controller
 		{
 			Logger.error(e);
 			categoryHandler = new CategoryHandler(null);			
-			showConnectionErrorAlert();
+			showConnectionErrorAlert(e.getMessage());
 		}
 
 		refreshAllTabs();		
diff --git a/src/de/deadlocker8/budgetmaster/ui/HomeController.java b/src/de/deadlocker8/budgetmaster/ui/HomeController.java
index ab2bb3520..a17c5d1ef 100644
--- a/src/de/deadlocker8/budgetmaster/ui/HomeController.java
+++ b/src/de/deadlocker8/budgetmaster/ui/HomeController.java
@@ -77,7 +77,12 @@ public class HomeController implements Refreshable
 		{
 			Budget budget = new Budget(controller.getPaymentHandler().getPayments());	
 			double remaining = budget.getIncomeSum() + budget.getPaymentSum();
-			labelBudget.setText(String.valueOf(Helpers.NUMBER_FORMAT.format(remaining).replace(".", ",")) + " " + controller.getSettings().getCurrency());
+			String currency = "€";
+			if(controller.getSettings() != null)
+			{
+				currency = controller.getSettings().getCurrency();
+			}
+			labelBudget.setText(String.valueOf(Helpers.NUMBER_FORMAT.format(remaining).replace(".", ",")) + " " + currency);
 			if(remaining <= 0)
 			{
 				labelBudget.setStyle("-fx-text-fill: #CC0000");
@@ -86,7 +91,7 @@ public class HomeController implements Refreshable
 			{
 				labelBudget.setStyle("-fx-text-fill: " + controller.getBundle().getString("color.text"));
 			}
-			labelStartBudget.setText("von " + String.valueOf(Helpers.NUMBER_FORMAT.format(budget.getIncomeSum()).replace(".", ",")) + " " + controller.getSettings().getCurrency() + " verbleibend");
+			labelStartBudget.setText("von " + String.valueOf(Helpers.NUMBER_FORMAT.format(budget.getIncomeSum()).replace(".", ",")) + " " + currency + " verbleibend");
 			
 			double factor = remaining / budget.getIncomeSum();
 			if(factor < 0)
diff --git a/src/de/deadlocker8/budgetmaster/ui/NewCategoryController.java b/src/de/deadlocker8/budgetmaster/ui/NewCategoryController.java
index 4a94063bf..235bf4d99 100644
--- a/src/de/deadlocker8/budgetmaster/ui/NewCategoryController.java
+++ b/src/de/deadlocker8/budgetmaster/ui/NewCategoryController.java
@@ -147,7 +147,7 @@ public class NewCategoryController
 			}
 			catch(Exception e)
 			{
-				controller.showConnectionErrorAlert();
+				controller.showConnectionErrorAlert(e.getMessage());
 			}			
 		}
 		else
@@ -161,7 +161,7 @@ public class NewCategoryController
 			}
 			catch(Exception e)
 			{				
-				controller.showConnectionErrorAlert();
+				controller.showConnectionErrorAlert(e.getMessage());
 			}	
 		}
 		
diff --git a/src/de/deadlocker8/budgetmaster/ui/NewPaymentController.java b/src/de/deadlocker8/budgetmaster/ui/NewPaymentController.java
index 51355b5c2..52a55f021 100644
--- a/src/de/deadlocker8/budgetmaster/ui/NewPaymentController.java
+++ b/src/de/deadlocker8/budgetmaster/ui/NewPaymentController.java
@@ -138,7 +138,7 @@ public class NewPaymentController
 		}
 		catch(Exception e)
 		{
-			controller.showConnectionErrorAlert();
+			controller.showConnectionErrorAlert(e.getMessage());
 			stage.close();
 			return;
 		}
@@ -308,7 +308,7 @@ public class NewPaymentController
 				catch(Exception e)
 				{
 					Logger.error(e);
-					controller.showConnectionErrorAlert();
+					controller.showConnectionErrorAlert(e.getMessage());
 				}
 			}
 			else
@@ -322,7 +322,7 @@ public class NewPaymentController
 				catch(Exception e)
 				{
 					Logger.error(e);
-					controller.showConnectionErrorAlert();
+					controller.showConnectionErrorAlert(e.getMessage());
 				}
 			}
 		}
@@ -348,7 +348,7 @@ public class NewPaymentController
 				catch(Exception e)
 				{
 					Logger.error(e);
-					controller.showConnectionErrorAlert();
+					controller.showConnectionErrorAlert(e.getMessage());
 				}
 			}
 			else
@@ -362,7 +362,7 @@ public class NewPaymentController
 				catch(Exception e)
 				{
 					Logger.error(e);
-					controller.showConnectionErrorAlert();
+					controller.showConnectionErrorAlert(e.getMessage());
 				}
 			}
 		}
diff --git a/src/de/deadlocker8/budgetmaster/ui/PaymentController.java b/src/de/deadlocker8/budgetmaster/ui/PaymentController.java
index db5adcc84..5c2307764 100644
--- a/src/de/deadlocker8/budgetmaster/ui/PaymentController.java
+++ b/src/de/deadlocker8/budgetmaster/ui/PaymentController.java
@@ -204,7 +204,7 @@ public class PaymentController implements Refreshable
 		catch(Exception e)
 		{
 			e.printStackTrace();
-			controller.showConnectionErrorAlert();
+			controller.showConnectionErrorAlert(e.getMessage());
 		}
 	}
 
@@ -219,7 +219,7 @@ public class PaymentController implements Refreshable
 		catch(Exception e)
 		{
 			e.printStackTrace();
-			controller.showConnectionErrorAlert();
+			controller.showConnectionErrorAlert(e.getMessage());
 		}
 	}
 
@@ -238,7 +238,7 @@ public class PaymentController implements Refreshable
 		catch(Exception e)
 		{
 			e.printStackTrace();
-			controller.showConnectionErrorAlert();
+			controller.showConnectionErrorAlert(e.getMessage());
 		}
 	}
 	
diff --git a/src/de/deadlocker8/budgetmaster/ui/SettingsController.java b/src/de/deadlocker8/budgetmaster/ui/SettingsController.java
index 471619dc9..47cf97c44 100644
--- a/src/de/deadlocker8/budgetmaster/ui/SettingsController.java
+++ b/src/de/deadlocker8/budgetmaster/ui/SettingsController.java
@@ -1,6 +1,7 @@
 package de.deadlocker8.budgetmaster.ui;
 
 import java.io.IOException;
+import java.util.ArrayList;
 
 import de.deadlocker8.budgetmaster.logic.Settings;
 import de.deadlocker8.budgetmaster.logic.Utils;
@@ -9,6 +10,7 @@ import javafx.scene.control.Alert.AlertType;
 import javafx.scene.control.Button;
 import javafx.scene.control.Label;
 import javafx.scene.control.RadioButton;
+import javafx.scene.control.TextArea;
 import javafx.scene.control.TextField;
 import javafx.scene.control.ToggleGroup;
 import javafx.scene.layout.AnchorPane;
@@ -27,6 +29,7 @@ public class SettingsController
 	@FXML private Button buttonSave;
 	@FXML private RadioButton radioButtonRestActivated;
 	@FXML private RadioButton radioButtonRestDeactivated;
+	@FXML private TextArea textAreaTrustedHosts;
 
 	private Controller controller;
 
@@ -46,6 +49,7 @@ public class SettingsController
 			{
 				radioButtonRestDeactivated.setSelected(true);
 			}
+			setTextAreaTrustedHosts(controller.getSettings().getTrustedHosts());
 		}
 		
 		anchorPaneMain.setStyle("-fx-background-color: #F4F4F4;");
@@ -55,12 +59,24 @@ public class SettingsController
 		buttonSave.setStyle("-fx-background-color: #2E79B9; -fx-text-fill: white; -fx-font-weight: bold; -fx-font-size: 16;");	
 		textFieldURL.setPromptText("z.B. https://yourdomain.de");
 		textFieldCurrency.setPromptText("z.B. €, CHF, $");
+		textAreaTrustedHosts.setPromptText("z.B. localhost");
 		
 		ToggleGroup toggleGroup = new ToggleGroup();
 		radioButtonRestActivated.setToggleGroup(toggleGroup);
 		radioButtonRestDeactivated.setToggleGroup(toggleGroup);
 	}
 	
+	private void setTextAreaTrustedHosts(ArrayList<String> trustedHosts)
+	{
+		StringBuilder trustedHostsString = new StringBuilder();
+		for(String currentHost : trustedHosts)
+		{
+			trustedHostsString.append(currentHost);
+			trustedHostsString.append("\n");
+		}
+		textAreaTrustedHosts.setText(trustedHostsString.toString());
+	}
+	
 	public void save()
 	{
 		String url = textFieldURL.getText().trim();
@@ -72,12 +88,26 @@ public class SettingsController
 			{
 				if(currency != null && !currency.equals(""))
 				{
+					ArrayList<String> trustedHosts = new ArrayList<>();
+					String trustedHostText = textAreaTrustedHosts.getText();
+					String[] trustedHostsArray = trustedHostText.split("\n");
+					for(String currentHost : trustedHostsArray)
+					{
+						currentHost = currentHost.trim();
+						if(!currentHost.equals(""))
+						{
+							trustedHosts.add(currentHost);
+						}
+					}
+					setTextAreaTrustedHosts(trustedHosts);
+					
 					if(controller.getSettings() != null)
 					{
 						controller.getSettings().setUrl(url);
 						controller.getSettings().setSecret(secret);	
 						controller.getSettings().setCurrency(currency);
 						controller.getSettings().setRestActivated(radioButtonRestActivated.isSelected());
+						controller.getSettings().setTrustedHosts(trustedHosts);
 					}
 					else
 					{
@@ -86,6 +116,7 @@ public class SettingsController
 						settings.setSecret(secret);
 						settings.setCurrency(currency);
 						settings.setRestActivated(radioButtonRestActivated.isSelected());
+						settings.setTrustedHosts(trustedHosts);
 						controller.setSettings(settings);
 					}
 					
diff --git a/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml b/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml
index 0fc94536e..67116a650 100644
--- a/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml
+++ b/src/de/deadlocker8/budgetmaster/ui/SettingsTab.fxml
@@ -4,9 +4,11 @@
 <?import javafx.scene.control.Button?>
 <?import javafx.scene.control.Label?>
 <?import javafx.scene.control.RadioButton?>
+<?import javafx.scene.control.TextArea?>
 <?import javafx.scene.control.TextField?>
 <?import javafx.scene.layout.AnchorPane?>
 <?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.Region?>
 <?import javafx.scene.layout.VBox?>
 <?import javafx.scene.text.Font?>
 
@@ -14,7 +16,7 @@
    <children>
       <VBox alignment="TOP_CENTER" layoutY="24.0" prefHeight="562.0" prefWidth="772.0" spacing="25.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="25.0">
          <children>
-            <HBox prefHeight="70.0">
+            <HBox prefHeight="334.0" prefWidth="722.0">
                <children>
                   <VBox alignment="CENTER_RIGHT" prefHeight="25.0" prefWidth="158.0" spacing="20.0">
                      <children>
@@ -41,6 +43,20 @@
                               <Font name="System Bold" size="16.0" />
                            </font>
                         </Label>
+                        <Label fx:id="labelSecret111" alignment="CENTER_RIGHT" contentDisplay="RIGHT" maxHeight="-Infinity" minHeight="60.0" prefWidth="158.0" text="Vertrauenswürdige Hosts:" textAlignment="RIGHT" wrapText="true">
+                           <font>
+                              <Font name="System Bold" size="16.0" />
+                           </font>
+                        </Label>
+                        <Label fx:id="labelSecret1111" alignment="CENTER" contentDisplay="CENTER" maxHeight="-Infinity" text="(ein Host pro Zeile)" textAlignment="CENTER" wrapText="true">
+                           <font>
+                              <Font size="14.0" />
+                           </font>
+                           <VBox.margin>
+                              <Insets top="-20.0" />
+                           </VBox.margin>
+                        </Label>
+                        <Region prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
                      </children>
                      <HBox.margin>
                         <Insets right="25.0" />
@@ -51,7 +67,7 @@
                         <TextField fx:id="textFieldURL" />
                         <TextField fx:id="textFieldSecret" />
                         <TextField fx:id="textFieldCurrency" />
-                        <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0">
+                        <HBox alignment="CENTER" prefHeight="11.0" prefWidth="539.0">
                            <children>
                               <RadioButton fx:id="radioButtonRestActivated" maxWidth="1.7976931348623157E308" mnemonicParsing="false" text="aktiviert">
                                  <font>
@@ -68,6 +84,7 @@
                               </RadioButton>
                            </children>
                         </HBox>
+                        <TextArea fx:id="textAreaTrustedHosts" prefHeight="136.0" prefWidth="539.0" VBox.vgrow="ALWAYS" />
                      </children>
                   </VBox>
                </children>
-- 
GitLab