Adds a scope-based access control layer to all 81 existing API routes. Sits alongside existing session-cookie auth (does not replace it). What this PR does: - Audits every existing route and documents required scope per route (see documentation/auth/route-scope-audit.md) - Adds classes/auth/scope.php with 10 scope constants and role→scope defaults - Adds classes/auth/scope_middleware.php with requireScope/requireAnyScope/requireRole - Applies require*() calls to all 81 existing routes - Adds ScopeMiddlewareTest (unit, 178 lines) and RouteScopeTest (integration, 212 lines) Coexistence note: This branch's classes/auth/scope.php is a stub that will be replaced by classes/auth/scope_registry.php (from TRU-145 / PR #396) when that PR merges first. The two have compatible APIs. Refs: TRU-149
210 lines
9.4 KiB
PHP
210 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace routes;
|
|
|
|
use classes\authentication;
|
|
use objects\logs_o;
|
|
use objects\product_options_o;
|
|
use traits\route_t;
|
|
|
|
use app\auth\Scope;
|
|
use app\auth\ScopeMiddleware;
|
|
|
|
class productOptionsRoute
|
|
{
|
|
use route_t;
|
|
|
|
public function run(): void
|
|
{
|
|
$this->get('/product/options', function () {
|
|
ScopeMiddleware::requireScope(Scope::CUSTOMER_READ, '/product/options');
|
|
|
|
// Require the user to be logged in
|
|
global $response;
|
|
$this->requirePermission('list_product_options');
|
|
// Get the user object
|
|
$user = (new authentication())->get_user();
|
|
// Check if the request was successful
|
|
if ($user) {
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, $user->id, 'LIST_PRODUCT_OPTIONS', 'User listed product options');
|
|
// Return the list of departments
|
|
$response->success(
|
|
(new product_options_o())
|
|
->setSearchableFields([
|
|
// The fields that can be searched. This would otherwise make it possible to get secret information from the database, simply by searching for it and getting the result count back
|
|
'id',
|
|
'product_id',
|
|
'option_id',
|
|
'name',
|
|
'min',
|
|
'max',
|
|
'created_at',
|
|
'updated_at'
|
|
])
|
|
->listObjectsWithPaginationIfSet(
|
|
function ($option) use ($user) {
|
|
// Return the object as an array
|
|
return [
|
|
'id' => (int)$option['id'],
|
|
'product_id' => (int)$option['product_id'],
|
|
'option_id' => (int)$option['option_id'],
|
|
'name' => (string)$option['name'],
|
|
'min' => $option['min'] === null ? null : (int)$option['min'],
|
|
'max' => $option['max'] === null ? null : (int)$option['max'],
|
|
'created_at' => (string)$option['created_at'],
|
|
'updated_at' => (string)$option['updated_at'],
|
|
];
|
|
}
|
|
)
|
|
);
|
|
} else {
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, 0, 'LIST_PRODUCT_OPTIONS', 'User tried to list product options without being logged in');
|
|
// Return an error
|
|
$response->error('Invalid session', 400);
|
|
}
|
|
},
|
|
[
|
|
'list_product_options' => 'List all product options'
|
|
]
|
|
);
|
|
|
|
$this->post('/product/options', function () {
|
|
ScopeMiddleware::requireScope(Scope::CUSTOMER_WRITE, '/product/options');
|
|
// Require the user to be logged in
|
|
global $response;
|
|
$this->requirePermission('add_product_option');
|
|
// Get the user object
|
|
$user = (new authentication())->get_user();
|
|
// Check if the request was successful
|
|
if ($user) {
|
|
// Check if the required parameters are set
|
|
self::requireParameters(['product_id', 'option_id']);
|
|
// Check if the parameters are of the correct type
|
|
self::requireType(self::getParameter('product_id'), self::TYPE_INT());
|
|
self::requireType(self::getParameter('option_id'), self::TYPE_INT());
|
|
// Create the object
|
|
$product_options = new product_options_o();
|
|
// Add the object
|
|
$product_options->add(
|
|
self::getParameter('product_id'),
|
|
self::getParameter('option_id')
|
|
);
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, $user->id, 'ADD_PRODUCT_OPTION', 'User added a product option');
|
|
// Return the object
|
|
$response->success(
|
|
$product_options->__toString()
|
|
);
|
|
} else {
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, 0, 'ADD_PRODUCT_OPTION', 'User tried to add a product option without being logged in');
|
|
// Return an error
|
|
$response->error('Invalid session', 400);
|
|
}
|
|
},
|
|
[
|
|
'add_product_option' => 'Add a product option'
|
|
]
|
|
);
|
|
|
|
$this->put('/product/options', function () {
|
|
ScopeMiddleware::requireScope(Scope::CUSTOMER_WRITE, '/product/options');
|
|
// Require the user to be logged in
|
|
global $response;
|
|
$this->requirePermission('edit_product_option');
|
|
// Get the user object
|
|
$user = (new authentication())->get_user();
|
|
// Check if the request was successful
|
|
if ($user) {
|
|
// Check if the required parameters are set
|
|
self::requireParameters(['id']);
|
|
// Check if the parameters are of the correct type
|
|
self::requireType(self::getParameter('id'), self::TYPE_INT());
|
|
// Create the object
|
|
$product_options = new product_options_o();
|
|
// Select the object
|
|
$product_options->select(self::getParameter('id'));
|
|
// Check what the user wants to edit
|
|
|
|
// Option name
|
|
if (self::isParametersSet(['name'])) {
|
|
// Check if the parameters are of the correct type
|
|
self::requireType(self::getParameter('name'), self::TYPE_STRING());
|
|
// Set the name
|
|
$product_options->set_name(self::getParameter('name'));
|
|
}
|
|
// Option min
|
|
if (self::isParametersSet(['min'])) {
|
|
// Check if the parameters are of the correct type (Or NULL)
|
|
self::requireTypeIn(self::getParameter('min'), [self::TYPE_INT(), self::TYPE_NULL()]);
|
|
// Set the min value
|
|
$product_options->set_min(self::getParameter('min'));
|
|
}
|
|
// Option max
|
|
if (self::isParametersSet(['max'])) {
|
|
// Check if the parameters are of the correct type
|
|
self::requireType(self::getParameter('max'), self::TYPE_INT());
|
|
// Set the max value
|
|
$product_options->set_max(self::getParameter('max'));
|
|
}
|
|
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, $user->id, 'EDIT_PRODUCT_OPTION', 'User edited a product option');
|
|
// Return the object
|
|
$response->success(
|
|
$product_options->__toString()
|
|
);
|
|
} else {
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, 0, 'EDIT_PRODUCT_OPTION', 'User tried to edit a product option without being logged in');
|
|
// Return an error
|
|
$response->error('Invalid session', 400);
|
|
}
|
|
},
|
|
[
|
|
'edit_product_option' => 'Edit a product option'
|
|
]
|
|
);
|
|
|
|
$this->delete('/product/options', function () {
|
|
ScopeMiddleware::requireScope(Scope::CUSTOMER_WRITE, '/product/options');
|
|
// Require the user to be logged in
|
|
global $response;
|
|
$this->requirePermission('delete_product_option');
|
|
// Get the user object
|
|
$user = (new authentication())->get_user();
|
|
// Check if the request was successful
|
|
if ($user) {
|
|
// Check if the required parameters are set
|
|
self::requireParameters(['id']);
|
|
// Check if the parameters are of the correct type
|
|
self::requireType((int)self::getParameter('id'), self::TYPE_INT());
|
|
// Require the minimum value to be above 0
|
|
self::requireMinValue((int)self::getParameter('id'), 1);
|
|
// Create the object
|
|
$product_options = new product_options_o();
|
|
// Select the object
|
|
$product_options->select((int)self::getParameter('id'));
|
|
// Delete the object
|
|
$product_options->delete();
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, $user->id, 'DELETE_PRODUCT_OPTION', 'User deleted a product option');
|
|
// Return the object
|
|
$response->success(
|
|
'Product option deleted'
|
|
);
|
|
} else {
|
|
// Log the incident
|
|
(new logs_o())->add('product_options', 'global', 1, 0, 'DELETE_PRODUCT_OPTION', 'User tried to delete a product option without being logged in');
|
|
// Return an error
|
|
$response->error('Invalid session', 400);
|
|
}
|
|
},
|
|
[
|
|
'delete_product_option' => 'Delete a product option'
|
|
]
|
|
);
|
|
}
|
|
} |