diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 000000000..ca423ee85
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,48 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Listen for Xdebug",
+ "type": "php",
+ "request": "launch",
+ "port": 9003
+ },
+ {
+ "name": "Launch currently open script",
+ "type": "php",
+ "request": "launch",
+ "program": "${file}",
+ "cwd": "${fileDirname}",
+ "port": 0,
+ "runtimeArgs": [
+ "-dxdebug.start_with_request=yes"
+ ],
+ "env": {
+ "XDEBUG_MODE": "debug,develop",
+ "XDEBUG_CONFIG": "client_port=${port}"
+ }
+ },
+ {
+ "name": "Launch Built-in web server",
+ "type": "php",
+ "request": "launch",
+ "runtimeArgs": [
+ "-dxdebug.mode=debug",
+ "-dxdebug.start_with_request=yes",
+ "-S",
+ "localhost:8000"
+ ],
+ "env": {
+ "ENVIRONMENT": "dev"
+ },
+ "program": "${workspaceRoot}/src/index.php", // Updated to src directory
+ "cwd": "${workspaceRoot}/src", // Updated working directory to src
+ "port": 9003,
+ "serverReadyAction": {
+ "pattern": "Development Server \\(http://localhost:([0-9]+)\\) started",
+ "uriFormat": "http://localhost:%s",
+ "action": "openExternally"
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index dbf64de5e..27a8383d5 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -1,5 +1,8 @@
# Release Notes
+### 4.4.3 (UNRELEASED)
+* Fix for blocklist capability working inconsistenly [#1329]
+
### 4.4.2 (March 12, 2025)
* Support for Gather 2.0 added. [#1323]
diff --git a/src/app/Http/Middleware/CallBlocklist.php b/src/app/Http/Middleware/CallBlocklist.php
index 3838248a8..64f070f5a 100644
--- a/src/app/Http/Middleware/CallBlocklist.php
+++ b/src/app/Http/Middleware/CallBlocklist.php
@@ -29,11 +29,14 @@ public function __construct(SettingsService $settings)
public function handle(Request $request, Closure $next)
{
if ($this->settings->has("blocklist") &&
- strlen($this->settings->get("blocklist") > 0) &&
+ strlen($this->settings->get("blocklist")) > 0 &&
$request->has("Caller")) {
+ $caller = $this->ensureLeadingPlus($request->get('Caller'));
+
$blocklistItems = explode(",", $this->settings->get('blocklist'));
foreach ($blocklistItems as $blocklistItem) {
- if (str_starts_with($blocklistItem, $request->get('Caller'))) {
+ $blocklistItem = $this->ensureLeadingPlus($blocklistItem);
+ if (str_starts_with($blocklistItem, $caller)) {
return response()->view('rejectCall')->header("Content-Type", "text/xml; charset=utf-8");
}
}
@@ -41,4 +44,19 @@ public function handle(Request $request, Closure $next)
return $next($request);
}
+
+ /**
+ * Ensures a phone number has a leading plus sign and no whitespace
+ *
+ * @param string $number
+ * @return string
+ */
+ private function ensureLeadingPlus(string $number): string
+ {
+ $number = trim($number);
+ if (!str_starts_with($number, '+')) {
+ return '+' . $number;
+ }
+ return $number;
+ }
}
diff --git a/src/app/Services/SettingsService.php b/src/app/Services/SettingsService.php
index 3bbe6dca4..8fd83d8b0 100644
--- a/src/app/Services/SettingsService.php
+++ b/src/app/Services/SettingsService.php
@@ -11,7 +11,7 @@
class SettingsService
{
- private string $version = "4.4.2";
+ private string $version = "4.4.3";
private array $allowlist = [
'announce_servicebody_volunteer_routing' => ['description' => '/helpline/announce_servicebody_volunteer_routing' , 'default' => false, 'overridable' => true, 'hidden' => false],
'blocklist' => ['description' => '/general/blocklist' , 'default' => '', 'overridable' => true, 'hidden' => false],
diff --git a/src/tests/Feature/BlocklistTest.php b/src/tests/Feature/BlocklistTest.php
index f2f76a333..bf38bbbc5 100644
--- a/src/tests/Feature/BlocklistTest.php
+++ b/src/tests/Feature/BlocklistTest.php
@@ -1,4 +1,7 @@
set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
$response = $this->call($method, '/', [
"Caller"=>$caller
]);
@@ -22,9 +27,25 @@
->assertSeeInOrderExact([""], false);
})->with(['GET', 'POST']);
+test('test the blocklist with multiple items and an exact match', function ($method) {
+ $caller = "+15557778888,+15557778890";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', [
+ "Caller"=>"+15557778890"
+ ]);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertSeeInOrderExact([""], false);
+})->with(['GET', 'POST']);
+
test('test the blocklist without a match', function ($method) {
- $caller = "5557778888";
- $_SESSION['override_blocklist'] = $caller;
+ $caller = "+15557778888";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
$response = $this->call($method, '/', [
"Caller"=>"5557778889"
]);
@@ -33,3 +54,98 @@
->assertHeader("Content-Type", "text/xml; charset=utf-8")
->assertDontSee([""], false);
})->with(['GET', 'POST']);
+
+test('test the blocklist with whitespace in caller number', function ($method) {
+ $caller = "+15557778888";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', [
+ "Caller" => " 15557778888 "
+ ]);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertSeeInOrderExact([""], false);
+})->with(['GET', 'POST']);
+
+test('test the blocklist with whitespace in blocklist entries', function ($method) {
+ $caller = " +15557778888 , +15557778890 ";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', [
+ "Caller" => "+15557778890"
+ ]);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertSeeInOrderExact([""], false);
+})->with(['GET', 'POST']);
+
+test('test the blocklist with missing plus sign in caller number', function ($method) {
+ $caller = "+15557778888";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', [
+ "Caller" => "15557778888"
+ ]);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertSeeInOrderExact([""], false);
+})->with(['GET', 'POST']);
+
+test('test the blocklist with missing plus sign in blocklist entries', function ($method) {
+ $caller = "15557778888,15557778890";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', [
+ "Caller" => "+15557778890"
+ ]);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertSeeInOrderExact([""], false);
+})->with(['GET', 'POST']);
+
+test('test the blocklist with empty blocklist', function ($method) {
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", "");
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', [
+ "Caller" => "+15557778888"
+ ]);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertDontSee([""], false);
+})->with(['GET', 'POST']);
+
+test('test the blocklist with missing Caller parameter', function ($method) {
+ $caller = "+15557778888";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', []);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertDontSee([""], false);
+})->with(['GET', 'POST']);
+
+test('test the blocklist with partial match', function ($method) {
+ $caller = "+15557778888";
+ $settingsService = new SettingsService();
+ $settingsService->set("blocklist", $caller);
+ app()->instance(SettingsService::class, $settingsService);
+ $response = $this->call($method, '/', [
+ "Caller" => "+1555777888899"
+ ]);
+ $response
+ ->assertStatus(200)
+ ->assertHeader("Content-Type", "text/xml; charset=utf-8")
+ ->assertDontSee([""], false);
+})->with(['GET', 'POST']);