Merge pull request #176 from copenhagentruckwash/fix-property-gate-command-authorization-bypass
Restore explicit permissions for property gate commands to fix authorization bypass
This commit is contained in:
@@ -9330,10 +9330,10 @@ paths:
|
||||
description: |
|
||||
Send a command (e.g., start, stop, reset) to a self-serve lane.
|
||||
Property gate commands (`OPEN_PROPERTY_ACCESS_GATE`, `OPEN_PROPERTY_EXIT_GATE`) are also supported here.
|
||||
Property gate commands require the matching explicit command permissions.
|
||||
Operator callers require the base command permission plus the command-specific permission. Authenticated
|
||||
customers with `list_own_department_selfserve_vehicle_conditions` may send `START` on enabled self-serve
|
||||
lanes. Customer `STOP` and property gate commands require the customer's active self-serve wash in the target
|
||||
department.
|
||||
lanes. Customer `STOP` requires the customer's active self-serve wash in the target department.
|
||||
operationId: sendSelfServeLaneCommand
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -21322,5 +21322,3 @@ components:
|
||||
success: { type: boolean, example: true }
|
||||
data:
|
||||
$ref: '#/components/schemas/DepartmentDailyReportOutsideHoursTrendPayload'
|
||||
|
||||
|
||||
|
||||
@@ -513,18 +513,10 @@ class moduleSelfServeRoute
|
||||
);
|
||||
break;
|
||||
case selfserve_lane_command::OPEN_PROPERTY_ACCESS_GATE:
|
||||
$this->requirePropertyGateCommandPermission(
|
||||
'modules_selfserve_lane_command_execute_open_property_access_gate',
|
||||
$lane,
|
||||
$customer_number
|
||||
);
|
||||
self::requirePermission('modules_selfserve_lane_command_execute_open_property_access_gate');
|
||||
break;
|
||||
case selfserve_lane_command::OPEN_PROPERTY_EXIT_GATE:
|
||||
$this->requirePropertyGateCommandPermission(
|
||||
'modules_selfserve_lane_command_execute_open_property_exit_gate',
|
||||
$lane,
|
||||
$customer_number
|
||||
);
|
||||
self::requirePermission('modules_selfserve_lane_command_execute_open_property_exit_gate');
|
||||
break;
|
||||
}
|
||||
// Execute the command
|
||||
@@ -1562,7 +1554,6 @@ class moduleSelfServeRoute
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function requestedShellyTransportOverride(): ?string
|
||||
{
|
||||
$transport = null;
|
||||
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
|
||||
app_require('routes/moduleSelfServeRoute.php');
|
||||
app_require('modules/selfserve/classes/selfserve_lane.php');
|
||||
app_require('objects/department_lanes_o.php');
|
||||
app_require('classes/object_property.php');
|
||||
|
||||
use classes\object_property;
|
||||
use modules\selfserve\classes\selfserve_lane;
|
||||
use objects\department_lanes_o;
|
||||
use routes\moduleSelfServeRoute;
|
||||
|
||||
class SelfservePropertyGatePermissionBypassRouteHarness extends moduleSelfServeRoute
|
||||
{
|
||||
public bool $activeWashResult = false;
|
||||
/** @var array<string,bool> */
|
||||
public array $permissions = [
|
||||
'list_own_department_selfserve_vehicle_conditions' => true,
|
||||
];
|
||||
/** @var array<int,array{department_id:int,customer_number:int}> */
|
||||
public array $activeWashChecks = [];
|
||||
|
||||
public function hasPermission(string|\classes\permission_node $permission, int $customer_number = null): bool
|
||||
{
|
||||
$key = $permission instanceof \classes\permission_node ? (string)$permission->permission : $permission;
|
||||
return $this->permissions[$key] ?? false;
|
||||
}
|
||||
|
||||
public function canUsePropertyGate(selfserve_lane $lane, int $customer_number): bool
|
||||
{
|
||||
return $this->canCustomerUsePropertyGateForLane($lane, $customer_number);
|
||||
}
|
||||
|
||||
protected function isLaneSelfServeOperationallyEnabled(selfserve_lane $lane): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function customerHasActiveSelfServeWashInDepartment(int $department_id, int $customer_number): bool
|
||||
{
|
||||
$this->activeWashChecks[] = [
|
||||
'department_id' => $department_id,
|
||||
'customer_number' => $customer_number,
|
||||
];
|
||||
|
||||
return $this->activeWashResult;
|
||||
}
|
||||
}
|
||||
|
||||
class SelfservePropertyGatePermissionBypassDepartmentLaneFake extends department_lanes_o
|
||||
{
|
||||
public function __construct(int $department_id)
|
||||
{
|
||||
$this->id = -1;
|
||||
$this->department = new object_property('department_lanes', -1, 'department', 'int');
|
||||
$this->department->set($department_id);
|
||||
}
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
// Skip database bootstrap for this unit test.
|
||||
}
|
||||
}
|
||||
|
||||
function selfserve_property_gate_permission_lane_for_department(int $department_id): selfserve_lane
|
||||
{
|
||||
$reflection = new ReflectionClass(selfserve_lane::class);
|
||||
/** @var selfserve_lane $lane */
|
||||
$lane = $reflection->newInstanceWithoutConstructor();
|
||||
$lane->id = 77;
|
||||
$lane->department_lane = new SelfservePropertyGatePermissionBypassDepartmentLaneFake($department_id);
|
||||
|
||||
return $lane;
|
||||
}
|
||||
|
||||
it('allows property gate commands for customers with an active wash in the target department', function (): void {
|
||||
$route = new SelfservePropertyGatePermissionBypassRouteHarness();
|
||||
$route->activeWashResult = true;
|
||||
$lane = selfserve_property_gate_permission_lane_for_department(6);
|
||||
|
||||
expect($route->canUsePropertyGate($lane, 12345679))->toBeTrue();
|
||||
expect($route->activeWashChecks)->toBe([
|
||||
[
|
||||
'department_id' => 6,
|
||||
'customer_number' => 12345679,
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not bypass property gate permissions without a positive customer number', function (): void {
|
||||
$route = new SelfservePropertyGatePermissionBypassRouteHarness();
|
||||
$route->activeWashResult = true;
|
||||
$lane = selfserve_property_gate_permission_lane_for_department(6);
|
||||
|
||||
expect($route->canUsePropertyGate($lane, 0))->toBeFalse();
|
||||
expect($route->activeWashChecks)->toBe([]);
|
||||
});
|
||||
|
||||
it('does not bypass property gate permissions without customer self-serve permission', function (): void {
|
||||
$route = new SelfservePropertyGatePermissionBypassRouteHarness();
|
||||
$route->activeWashResult = true;
|
||||
$route->permissions = [];
|
||||
$lane = selfserve_property_gate_permission_lane_for_department(6);
|
||||
|
||||
expect($route->canUsePropertyGate($lane, 12345679))->toBeFalse();
|
||||
expect($route->activeWashChecks)->toBe([]);
|
||||
});
|
||||
|
||||
it('does not bypass property gate permissions when the customer has no active wash in the target department', function (): void {
|
||||
$route = new SelfservePropertyGatePermissionBypassRouteHarness();
|
||||
$route->activeWashResult = false;
|
||||
$lane = selfserve_property_gate_permission_lane_for_department(6);
|
||||
|
||||
expect($route->canUsePropertyGate($lane, 12345679))->toBeFalse();
|
||||
expect($route->activeWashChecks)->toBe([
|
||||
[
|
||||
'department_id' => 6,
|
||||
'customer_number' => 12345679,
|
||||
],
|
||||
]);
|
||||
});
|
||||
Reference in New Issue
Block a user