From b9c3f78233e178293f922b1512eaba0a2d973034 Mon Sep 17 00:00:00 2001
From: Arshan Dabirsiaghi <arshan.dabirsiaghi@gmail.com>
Date: Wed, 4 Oct 2023 10:06:55 -0400
Subject: [PATCH 1/3] add new domain validation api

---
 .../io/github/pixee/security/HostValidator.java  | 12 ++++++++++++
 .../java/io/github/pixee/security/UrlsTest.java  | 16 ++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/src/main/java/io/github/pixee/security/HostValidator.java b/src/main/java/io/github/pixee/security/HostValidator.java
index dc5e764..80eb132 100644
--- a/src/main/java/io/github/pixee/security/HostValidator.java
+++ b/src/main/java/io/github/pixee/security/HostValidator.java
@@ -47,4 +47,16 @@ public boolean isAllowed(final String host) {
   static HostValidator fromAllowedHostPattern(final Pattern allowPattern) {
     return new PatternBasedHostValidator(allowPattern);
   }
+
+    /**
+     * Return a {@link HostValidator} that will assure a given domain is within the allowed domain. For example, given
+     * a domain of "good.com", this validator will allow "good.com", "www.good.com", "internal.good.com", etc.
+     *
+     * @param domainName the domain to allow, e.g., "good.com", or "internal-host"
+     * @return a validator that will only allow hosts within the given domain space
+     */
+    static HostValidator fromAllowedHostDomain(final String domainName) {
+        Pattern p = Pattern.compile("(.*\\." + Pattern.quote(domainName) + "|" + Pattern.quote(domainName) +")");
+        return new PatternBasedHostValidator(p);
+    }
 }
diff --git a/src/test/java/io/github/pixee/security/UrlsTest.java b/src/test/java/io/github/pixee/security/UrlsTest.java
index 39a1fa0..c4ab57f 100644
--- a/src/test/java/io/github/pixee/security/UrlsTest.java
+++ b/src/test/java/io/github/pixee/security/UrlsTest.java
@@ -7,6 +7,7 @@
 
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.List;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 import org.junit.jupiter.api.Test;
@@ -138,6 +139,21 @@ void it_disallows_bad_domains() throws MalformedURLException {
         () -> {
           Urls.create("https://evil.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotCom);
         });
+
+    HostValidator allowsOnlyGoodDotComByDomainString = HostValidator.fromAllowedHostDomain("good.com");
+    Urls.create("https://good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+    Urls.create("https://sub.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+    Urls.create("https://different-sub-123.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+    Urls.create("https://.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+
+    List.of("https://goodAcom/", "https://evil.com", "https://good.com.evil", "https://good.com.").stream().forEach(badDomain -> {
+      assertThrows(
+              SecurityException.class,
+              () -> {
+                Urls.create(badDomain, setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
+              });
+    });
+
   }
 
   @Test

From dfe37fbaee2515a3be4be36765a07a8011944ec5 Mon Sep 17 00:00:00 2001
From: Arshan Dabirsiaghi <arshan.dabirsiaghi@gmail.com>
Date: Wed, 4 Oct 2023 10:12:56 -0400
Subject: [PATCH 2/3] use 1.8 api

---
 .../io/github/pixee/security/UrlsTest.java    | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/test/java/io/github/pixee/security/UrlsTest.java b/src/test/java/io/github/pixee/security/UrlsTest.java
index c4ab57f..c96972e 100644
--- a/src/test/java/io/github/pixee/security/UrlsTest.java
+++ b/src/test/java/io/github/pixee/security/UrlsTest.java
@@ -1,19 +1,19 @@
 package io.github.pixee.security;
 
-import static io.github.pixee.security.J8ApiBridge.setOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.*;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.List;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
+
+import static io.github.pixee.security.J8ApiBridge.setOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 final class UrlsTest {
 
@@ -146,7 +146,7 @@ void it_disallows_bad_domains() throws MalformedURLException {
     Urls.create("https://different-sub-123.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
     Urls.create("https://.good.com/", setOf(UrlProtocol.HTTPS), allowsOnlyGoodDotComByDomainString);
 
-    List.of("https://goodAcom/", "https://evil.com", "https://good.com.evil", "https://good.com.").stream().forEach(badDomain -> {
+    Stream.of("https://goodAcom/", "https://evil.com", "https://good.com.evil", "https://good.com.").forEach(badDomain -> {
       assertThrows(
               SecurityException.class,
               () -> {

From d26ec30e7e9ce0cb238cbdd80954066abaa48bce Mon Sep 17 00:00:00 2001
From: Jacoco Coverage Update Action <pixee@users.noreply.github.com>
Date: Wed, 4 Oct 2023 14:15:00 +0000
Subject: [PATCH 3/3] Autogenerated JaCoCo coverage badge

---
 .github/badges/jacoco.svg | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/badges/jacoco.svg b/.github/badges/jacoco.svg
index de06873..65ea9eb 100644
--- a/.github/badges/jacoco.svg
+++ b/.github/badges/jacoco.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="106" height="20" role="img" aria-label="coverage: 81.1%"><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="106" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="45" height="20" fill="#a4a61d"/><rect width="106" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="315" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="510">coverage</text><text x="315" y="140" transform="scale(.1)" fill="#fff" textLength="510">coverage</text><text aria-hidden="true" x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">81.1%</text><text x="825" y="140" transform="scale(.1)" fill="#fff" textLength="350">81.1%</text></g></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" width="106" height="20" role="img" aria-label="coverage: 81.2%"><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="106" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="45" height="20" fill="#a4a61d"/><rect width="106" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="315" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="510">coverage</text><text x="315" y="140" transform="scale(.1)" fill="#fff" textLength="510">coverage</text><text aria-hidden="true" x="825" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">81.2%</text><text x="825" y="140" transform="scale(.1)" fill="#fff" textLength="350">81.2%</text></g></svg>
\ No newline at end of file
