Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
]
}
3 changes: 3 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -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]

Expand Down
22 changes: 20 additions & 2 deletions src/app/Http/Middleware/CallBlocklist.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,34 @@ 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");
}
}
}

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;
}
}
2 changes: 1 addition & 1 deletion src/app/Services/SettingsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
124 changes: 120 additions & 4 deletions src/tests/Feature/BlocklistTest.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?php

use App\Services\SettingsService;

beforeAll(function () {
putenv("ENVIRONMENT=test");
});
Expand All @@ -11,8 +14,10 @@
});

test('test the blocklist with an exact 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"=>$caller
]);
Expand All @@ -22,9 +27,25 @@
->assertSeeInOrderExact(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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"
]);
Expand All @@ -33,3 +54,98 @@
->assertHeader("Content-Type", "text/xml; charset=utf-8")
->assertDontSee(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], 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(["<?xml version='1.0' encoding='UTF-8'?><Response><Reject/></Response>"], false);
})->with(['GET', 'POST']);