SEBA-469 Validate filenames with quotes

Change-Id: If2b2e9f7b09f3fcbc58822b1e786ed2b2d128955
diff --git a/VERSION b/VERSION
index 4739442..1c8f011 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-2.1.45
+2.1.46
 
diff --git a/containers/chameleon/Dockerfile.chameleon b/containers/chameleon/Dockerfile.chameleon
index 300ee40..3db9c58 100644
--- a/containers/chameleon/Dockerfile.chameleon
+++ b/containers/chameleon/Dockerfile.chameleon
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/chameleon
-FROM xosproject/xos-base:2.1.45
+FROM xosproject/xos-base:2.1.46
 
 # xos-base already has protoc and dependencies installed
 
diff --git a/containers/xos/Dockerfile.client b/containers/xos/Dockerfile.client
index b3793ca..f15eeef 100644
--- a/containers/xos/Dockerfile.client
+++ b/containers/xos/Dockerfile.client
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-client
-FROM xosproject/xos-libraries:2.1.45
+FROM xosproject/xos-libraries:2.1.46
 
 # Install XOS client
 COPY lib/xos-api /tmp/xos-api
diff --git a/containers/xos/Dockerfile.libraries b/containers/xos/Dockerfile.libraries
index 67a7948..fb4837a 100644
--- a/containers/xos/Dockerfile.libraries
+++ b/containers/xos/Dockerfile.libraries
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-libraries
-FROM xosproject/xos-base:2.1.45
+FROM xosproject/xos-base:2.1.46
 
 # Add libraries
 COPY lib /opt/xos/lib
diff --git a/containers/xos/Dockerfile.synchronizer-base b/containers/xos/Dockerfile.synchronizer-base
index 738c070..5b0d5f4 100644
--- a/containers/xos/Dockerfile.synchronizer-base
+++ b/containers/xos/Dockerfile.synchronizer-base
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-synchronizer-base
-FROM xosproject/xos-client:2.1.45
+FROM xosproject/xos-client:2.1.46
 
 COPY xos/synchronizers/new_base /opt/xos/synchronizers/new_base
 COPY xos/xos/logger.py /opt/xos/xos/logger.py
diff --git a/containers/xos/Dockerfile.xos-core b/containers/xos/Dockerfile.xos-core
index 0ccfc89..e91ea86 100644
--- a/containers/xos/Dockerfile.xos-core
+++ b/containers/xos/Dockerfile.xos-core
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-core
-FROM xosproject/xos-libraries:2.1.45
+FROM xosproject/xos-libraries:2.1.46
 
 # Install XOS
 ADD xos /opt/xos
diff --git a/xos/coreapi/dynamicbuild.py b/xos/coreapi/dynamicbuild.py
index 582fd8b..cc55fac 100644
--- a/xos/coreapi/dynamicbuild.py
+++ b/xos/coreapi/dynamicbuild.py
@@ -15,6 +15,7 @@
 import json
 import hashlib
 import os
+import re
 import shutil
 import tempfile
 from xosgenx.generator import XOSProcessor, XOSProcessorArgs
@@ -43,8 +44,9 @@
         )
 
     def pre_validate_file(self, item):
-        # someone might be trying to trick us into writing files outside the designated directory
-        if "/" in item.filename:
+        # various filename validations
+        #   alphas (upper and lower), digits, underscore, dash, and period.
+        if not re.match("^[\w.-]+$", item.filename):
             raise Exception("illegal character in filename %s" % item.filename)
 
     def pre_validate_python(self, item):
diff --git a/xos/coreapi/test_dynamicbuild.py b/xos/coreapi/test_dynamicbuild.py
index 8931355..6982747 100644
--- a/xos/coreapi/test_dynamicbuild.py
+++ b/xos/coreapi/test_dynamicbuild.py
@@ -121,6 +121,76 @@
     def test_pre_validate_file(self):
         self.builder.pre_validate_file(self.example_xproto_item)
 
+        # dashes are okay
+        item = DynamicLoadItem(
+            filename="example-service.xproto", contents=self.example_xproto
+        )
+        self.builder.pre_validate_file(item)
+
+        # undestcores are okay
+        item = DynamicLoadItem(
+            filename="example_service.xproto", contents=self.example_xproto
+        )
+        self.builder.pre_validate_file(item)
+
+        # mixed case is okay
+        item = DynamicLoadItem(
+            filename="ExampleService.xproto", contents=self.example_xproto
+        )
+        self.builder.pre_validate_file(item)
+
+        # no "." is still considered valid
+        item = DynamicLoadItem(
+            filename="ExampleServicexproto", contents=self.example_xproto
+        )
+        self.builder.pre_validate_file(item)
+
+    def test_pre_validate_file_illegal_char(self):
+        item = DynamicLoadItem(
+            filename="/exampleservice.xproto", contents=self.example_xproto
+        )
+        with self.assertRaises(Exception) as e:
+            self.builder.pre_validate_file(item)
+        self.assertEqual(
+            str(e.exception), "illegal character in filename /exampleservice.xproto"
+        )
+
+        item = DynamicLoadItem(
+            filename="\"exampleservice.xproto\"", contents=self.example_xproto
+        )
+        with self.assertRaises(Exception) as e:
+            self.builder.pre_validate_file(item)
+        self.assertEqual(
+            str(e.exception), "illegal character in filename \"exampleservice.xproto\""
+        )
+
+        item = DynamicLoadItem(
+            filename="'exampleservice.xproto'", contents=self.example_xproto
+        )
+        with self.assertRaises(Exception) as e:
+            self.builder.pre_validate_file(item)
+        self.assertEqual(
+            str(e.exception), "illegal character in filename 'exampleservice.xproto'"
+        )
+
+        item = DynamicLoadItem(
+            filename="example service.xproto", contents=self.example_xproto
+        )
+        with self.assertRaises(Exception) as e:
+            self.builder.pre_validate_file(item)
+        self.assertEqual(
+            str(e.exception), "illegal character in filename example service.xproto"
+        )
+
+        item = DynamicLoadItem(
+            filename="", contents=self.example_xproto
+        )
+        with self.assertRaises(Exception) as e:
+            self.builder.pre_validate_file(item)
+        self.assertEqual(
+            str(e.exception), "illegal character in filename "
+        )
+
     def test_pre_validate_models(self):
         self.builder.pre_validate_models(self.example_request)
 
@@ -322,7 +392,7 @@
             self.builder.pre_validate_python(python_item)
 
         self.assertEqual(
-            e.exception.message, "python file somefile.py failed compile test"
+            str(e.exception), "python file somefile.py failed compile test"
         )