From 825794319ce97e6e22056605b8553c0c149990ea Mon Sep 17 00:00:00 2001
From: Romeo Papa <romeopapa@caramail.com>
Date: Wed, 12 Aug 2015 22:08:36 +0200
Subject: [PATCH 4/4] Validates SMTP host and port, (as well as SOCKS host and
 port)

---
 whisperBack/whisperback.py | 61 ++++++++++++++++++++++++++--------------------
 1 file changed, 35 insertions(+), 26 deletions(-)

diff --git a/whisperBack/whisperback.py b/whisperBack/whisperback.py
index 30fa6c7..126a8af 100644
--- a/whisperBack/whisperback.py
+++ b/whisperBack/whisperback.py
@@ -44,7 +44,7 @@ class WhisperBack(object):
     """
     This class contains the backend which actually sends the feedback
     """
-    
+
     def set_contact_email(self, email):
         """Sets an optional email address to be used for furether communication
 
@@ -82,8 +82,8 @@ class WhisperBack(object):
 
     def __init__(self, subject = "", message = ""):
         """Initialize a feedback object with the given contents
-        
-        @param subject The topic of the feedback 
+
+        @param subject The topic of the feedback
         @param message The content of the feedback
         """
         self.__thread = None
@@ -127,7 +127,7 @@ class WhisperBack(object):
     def __load_conf(self, config_file_path):
         """Loads a configuration file from config_file_path and executes it
         inside the current class.
-        
+
         @param config_file_path The path on the configuration file to load
         """
 
@@ -171,50 +171,59 @@ class WhisperBack(object):
 
         # XXX: Add sanity checks
 
-        if not isinstance(self.socks_host, str):
-            raise TypeError("socks_host's type is invalid, it must " \
-                            "be a string.")
-        if len(self.socks_host) > 255:
-            raise ValueError("socks_host's value is too long: a " \
-                             "hostname must be below 255 characters.")
-        if not self.validateHostnameOrIPv4(self.socks_host):
-            raise ValueError("socks_host's value is not a correct IPv4 " \
-                             "address or hostname.")
+        self.validateHostnameOrIpv4(self.smtp_host, "smtp_host")
+        self.validatePortValue(self.smtp_port, "smtp_port")
+        self.validateHostnameOrIpv4(self.socks_host, "socks_host")
+        self.validatePortValue(self.socks_port, "socks_port")
+
+    def validatePortValue(self, port, valuename):
+        """Validates a port value (must be an integer between 1 and 65535)
+
+        @param port The port's value
+        @param valuename The name of the value (for debugging)
+        """
         try:
-            int(self.socks_port)
+            int(port)
         except:
-            raise TypeError("socks_port's type is invalid, it must " \
+            raise TypeError(valuename+"'s type is invalid, it must " \
                             "be an integer.")
-        if self.socks_port < 1 or self.socks_port > 65535:
-            raise ValueError("socks_port's value is invalid, it must " \
+        if port < 1 or port > 65535:
+            raise ValueError(valuename+"'s value is invalid, it must " \
                              "between 1 and 65535.")
 
-    def validateHostnameOrIPv4(self, hostname_or_ipv4):
+    def validateHostnameOrIpv4(self, hostname_or_ipv4, valuename):
         """Validates a hostname or IPv4 address
 
         pySocks is not compatible with ipv6, hostname specs follow RFC 1123
 
         @param hostname_or_ipv4 The hostname or IPV4 to validate
+        @param valuename The name of the value (for debugging)
         """
+        if not isinstance(self.socks_host, str):
+            raise TypeError(valuename+"'s type is invalid, it must " \
+                            "be a string.")
+        if len(self.socks_host) > 255:
+            raise ValueError(valuename+"'s value is too long: a " \
+                            "hostname must be below 255 characters.")
 
         # regex from http://stackoverflow.com/a/106223
         ip_address_regex = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$");
         hostname_regex = re.compile("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$");
 
-        if ip_address_regex.match(hostname_or_ipv4) or hostname_regex.match(hostname_or_ipv4):
-            return True
-        return False
+        if not ip_address_regex.match(hostname_or_ipv4) and not hostname_regex.match(hostname_or_ipv4):
+            raise ValueError(valuename+"'s value is not a correct IPv4 " \
+                             "address or hostname.")
 
-    def execute_threaded(self, func, args, progress_callback=None, 
+    def execute_threaded(self, func, args, progress_callback=None,
                            finished_callback=None, polling_freq=100):
         """Execute a function in another thread and handle it.
-        
+
         Execute the function `func` with arguments `args` in another thread,
         and poll whether the thread is alive, executing the callback
         `progress_callback` every `polling_frequency`. When the function
         thread terminates, saves the execption it eventually raised and pass
         it to `finished_callback`.
-        
+
         @param func               the function to execute.
         @param args               the tuple to pass as arguments to `func`.
         @param progress_callback  (optional) a callback function to call
@@ -306,8 +315,8 @@ class WhisperBack(object):
 
     def send(self, progress_callback=None, finished_callback=None):
         """Actually sends the message
-        
-        @param progress_callback 
+
+        @param progress_callback
         @param finished_callback
         """
 
-- 
2.1.4

