From 903895814ace77cd30c22b57de16f9e22daf21e4 Mon Sep 17 00:00:00 2001
From: Dan Brown <ssddanbrown@googlemail.com>
Date: Sat, 26 Aug 2023 20:13:37 +0100
Subject: [PATCH] SSR: Updated allow list handling & covered webhook usage

- Covered webhook SSR allow list useage via test.
- Updated allow list handling to use trailing slash, or hash, or end of
  line as late anchor for better handling for hosts (prevent .co.uk
passing for .co domain host)
---
 app/Util/SsrUrlValidator.php       |  4 ++--
 tests/Actions/WebhookCallTest.php  | 14 ++++++++++++++
 tests/Unit/SsrUrlValidatorTest.php |  3 +++
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/app/Util/SsrUrlValidator.php b/app/Util/SsrUrlValidator.php
index 722a45f7b..0b3a6a31d 100644
--- a/app/Util/SsrUrlValidator.php
+++ b/app/Util/SsrUrlValidator.php
@@ -41,7 +41,7 @@ class SsrUrlValidator
 
     protected function urlMatchesPattern($url, $pattern): bool
     {
-        $pattern = trim($pattern);
+        $pattern = rtrim(trim($pattern), '/');
         $url = trim($url);
 
         if (empty($pattern) || empty($url)) {
@@ -51,7 +51,7 @@ class SsrUrlValidator
         $quoted = preg_quote($pattern, '/');
         $regexPattern = str_replace('\*', '.*', $quoted);
 
-        return preg_match('/^' . $regexPattern . '.*$/i', $url);
+        return preg_match('/^' . $regexPattern . '($|\/.*$|#.*$)/i', $url);
     }
 
     /**
diff --git a/tests/Actions/WebhookCallTest.php b/tests/Actions/WebhookCallTest.php
index fc49a524e..0746aa3a1 100644
--- a/tests/Actions/WebhookCallTest.php
+++ b/tests/Actions/WebhookCallTest.php
@@ -101,6 +101,20 @@ class WebhookCallTest extends TestCase
         $this->assertNotNull($webhook->last_errored_at);
     }
 
+    public function test_webhook_uses_ssr_hosts_option_if_set()
+    {
+        config()->set('app.ssr_hosts', 'https://*.example.com');
+        $http = Http::fake();
+
+        $webhook = $this->newWebhook(['active' => true, 'endpoint' => 'https://wh.example.co.uk'], ['all']);
+        $this->runEvent(ActivityType::ROLE_CREATE);
+        $http->assertNothingSent();
+
+        $webhook->refresh();
+        $this->assertEquals('The URL does not match the configured allowed SSR hosts', $webhook->last_error);
+        $this->assertNotNull($webhook->last_errored_at);
+    }
+
     public function test_webhook_call_data_format()
     {
         Http::fake([
diff --git a/tests/Unit/SsrUrlValidatorTest.php b/tests/Unit/SsrUrlValidatorTest.php
index 1443eedd7..8fb538916 100644
--- a/tests/Unit/SsrUrlValidatorTest.php
+++ b/tests/Unit/SsrUrlValidatorTest.php
@@ -25,6 +25,9 @@ class SsrUrlValidatorTest extends TestCase
             ['config' => 'https://*.example.com', 'url' => 'https://test.example.com', 'result' => true],
             ['config' => '*//example.com', 'url' => 'https://example.com', 'result' => true],
             ['config' => '*//example.com', 'url' => 'http://example.com', 'result' => true],
+            ['config' => '*//example.co', 'url' => 'http://example.co.uk', 'result' => false],
+            ['config' => '*//example.co/bookstack', 'url' => 'https://example.co/bookstack/a/path', 'result' => true],
+            ['config' => '*//example.co*', 'url' => 'https://example.co.uk/bookstack/a/path', 'result' => true],
             ['config' => 'https://example.com', 'url' => 'https://example.com/a/b/c?test=cat', 'result' => true],
             ['config' => 'https://example.com', 'url' => 'https://example.co.uk', 'result' => false],