Repository: shapesecurity/salvation
Pull request #127 (2016-04-11 01:21:51)

more tests for querying media type, make hash case-insensitive


Patch:
diff --git a/src/main/java/com/shapesecurity/salvation/data/GUID.java b/src/main/java/com/shapesecurity/salvation/data/GUID.java
index 6e4548c..22b92bb 100644
--- a/src/main/java/com/shapesecurity/salvation/data/GUID.java
+++ b/src/main/java/com/shapesecurity/salvation/data/GUID.java
@@ -12,11 +12,11 @@ public class GUID extends Origin {
     @Override public boolean equals(Object other) {
         if (!(other instanceof GUID))
             return false;
-        return ((GUID) other).value.equals(this.value);
+        return ((GUID) other).value.equalsIgnoreCase(this.value);
     }
 
     @Override public int hashCode() {
-        return this.value.hashCode();
+        return this.value.toLowerCase().hashCode();
     }
 
     @Nonnull @Override public String show() {
diff --git a/src/main/java/com/shapesecurity/salvation/data/Policy.java b/src/main/java/com/shapesecurity/salvation/data/Policy.java
index b076495..9dea583 100644
--- a/src/main/java/com/shapesecurity/salvation/data/Policy.java
+++ b/src/main/java/com/shapesecurity/salvation/data/Policy.java
@@ -142,7 +142,7 @@ public class Policy implements Show {
                     Set<SourceExpression> newSources = sourceListDirective.values()
                         // * remove all other host sources in a source list that contains *
                         .filter(x -> !(x instanceof HostSource))
-                        // * remove schemes sources other than data:, blob:, and filesystem: in source list that contains *
+                        // * remove schemes sources other than about:, data:, blob:, and filesystem: in source list that contains *
                         .filter(x -> !(x instanceof SchemeSource) || ((SchemeSource) x).matchesProtectedScheme())
                         .collect(Collectors.toCollection(LinkedHashSet::new));
                     newSources.add(star.get());
@@ -522,4 +522,12 @@ public class Policy implements Show {
         }
         return frameAncestorsDirective.matchesSource(this.origin, source);
     }
+
+    public boolean allowsFrameAncestor(@Nonnull GUID source) {
+        FrameAncestorsDirective frameAncestorsDirective = this.getDirectiveByType(FrameAncestorsDirective.class);
+        if (frameAncestorsDirective == null) {
+            return true;
+        }
+        return frameAncestorsDirective.matchesSource(this.origin, source);
+    }
 }
diff --git a/src/main/java/com/shapesecurity/salvation/directiveValues/MediaType.java b/src/main/java/com/shapesecurity/salvation/directiveValues/MediaType.java
index 9dd6065..c4c3555 100644
--- a/src/main/java/com/shapesecurity/salvation/directiveValues/MediaType.java
+++ b/src/main/java/com/shapesecurity/salvation/directiveValues/MediaType.java
@@ -26,7 +26,7 @@ public class MediaType implements DirectiveValue, MatchesMediaType {
     }
 
     @Override public int hashCode() {
-        return (this.type.hashCode() ^ 0x887E088E) ^ (this.subtype.hashCode() ^ 0x33E42712);
+        return (this.type.toLowerCase().hashCode() ^ 0x887E088E) ^ (this.subtype.toLowerCase().hashCode() ^ 0x33E42712);
     }
 
     @Nonnull @Override public String show() {
diff --git a/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java b/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java
index 2bbd071..44b7b0e 100644
--- a/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java
+++ b/src/main/java/com/shapesecurity/salvation/directiveValues/SchemeSource.java
@@ -21,11 +21,12 @@ public class SchemeSource implements SourceExpression, AncestorSource, MatchesSo
     }
 
     @Override public boolean matchesSource(@Nonnull Origin origin, @Nonnull GUID source) {
-        return source.value.startsWith(this.value + ":");
+        return source.value.toLowerCase().startsWith(this.value.toLowerCase() + ":");
     }
 
     public boolean matchesProtectedScheme() {
-        return this.value.equals("data") || this.value.equals("blob") || this.value.equals("filesystem");
+        return this.value.equalsIgnoreCase("about") || this.value.equalsIgnoreCase("blob") ||
+            this.value.equalsIgnoreCase("data") || this.value.equalsIgnoreCase("filesystem");
     }
 
     @Override public boolean equals(@Nullable Object other) {


Test patch:
diff --git a/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java b/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java
index 4b5a466..a55b75a 100644
--- a/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java
+++ b/src/test/java/com/shapesecurity/salvation/PolicyQueryingTest.java
@@ -139,9 +139,9 @@ public class PolicyQueryingTest extends CSPTest {
     }
 
     @Test public void testAllowsPlugin() {
-        Policy p;
-
-        assertTrue("plugin is allowed", parse("plugin-types a/b c/d").allowsPlugin(new MediaType("a", "b")));
+        assertTrue("plugin is allowed", parse("plugin-types a/b c/d").allowsPlugin(new MediaType("A", "b")));
+        assertTrue("plugin is allowed", parse("plugin-types a/b c/d").allowsPlugin(new MediaType("a", "B")));
+        assertTrue("plugin is allowed", parse("plugin-types a/b c/d").allowsPlugin(new MediaType("A", "B")));
         assertTrue("plugin is allowed", parse("plugin-types a/b c/d").allowsPlugin(new MediaType("a", "b")));
         assertFalse("plugin is not allowed", parse("default-src 'none'").allowsPlugin(new MediaType("z", "b")));
         assertFalse("plugin is not allowed", parse("plugin-types a/b c/d").allowsPlugin(new MediaType("z", "b")));
@@ -290,6 +290,37 @@ public class PolicyQueryingTest extends CSPTest {
         assertFalse(p.allowsScriptFromSource(URI.parse("http://example.com/a/b/C")));
     }
 
+    @Test public void testLocalSchemes() {
+        Policy p = Parser.parse("script-src *.example.com data: blob:; frame-ancestors data: about:", "http://example.com");
+        assertTrue(p.allowsScriptFromSource(new GUID("data:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("DATA:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("blob:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("BLOB:")));
+        assertFalse(p.allowsScriptFromSource(new GUID("about::")));
+        assertFalse(p.allowsScriptFromSource(new GUID("ABOUT:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("data:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("DATA:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("about:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("ABOUT:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("blob:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("BLOB:")));
+
+        p = Parser.parse("script-src *.example.com DATA: BLOB:; frame-ancestors DATA: ABOUT:", "http://example.com");
+        assertTrue(p.allowsScriptFromSource(new GUID("data:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("DATA:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("blob:")));
+        assertTrue(p.allowsScriptFromSource(new GUID("BLOB:")));
+        assertFalse(p.allowsScriptFromSource(new GUID("about::")));
+        assertFalse(p.allowsScriptFromSource(new GUID("ABOUT:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("data:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("DATA:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("about:")));
+        assertTrue(p.allowsFrameAncestor(new GUID("ABOUT:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("blob:")));
+        assertFalse(p.allowsFrameAncestor(new GUID("BLOB:")));
+
+    }
+
     @Test public void testWildcards() {
         Policy p;