157 lines
5.6 KiB
PHP
157 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace App\Providers;
|
|
|
|
use App\Models\Answer;
|
|
use App\Models\Brand;
|
|
use App\Models\Customer;
|
|
use App\Models\CustomerInfo;
|
|
use App\Models\Question;
|
|
use App\Models\Service;
|
|
use App\Models\SingleOptin;
|
|
use Illuminate\Cache\RateLimiting\Limit;
|
|
use Illuminate\Contracts\Database\Eloquent\Builder;
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\RateLimiter;
|
|
use Illuminate\Support\Facades\Route;
|
|
|
|
class RouteServiceProvider extends ServiceProvider
|
|
{
|
|
/**
|
|
* The path to the "home" route for your application.
|
|
*
|
|
* This is used by Laravel authentication to redirect users after login.
|
|
*
|
|
* @var string
|
|
*/
|
|
public const HOME = '/';
|
|
|
|
/**
|
|
* Define your route model bindings, pattern filters, etc.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function boot(): void
|
|
{
|
|
$this->configureRateLimiting();
|
|
|
|
$this->cspReportRoute();
|
|
|
|
$this->routes(function () {
|
|
// @codeCoverageIgnoreStart
|
|
Route::prefix('api')->middleware('api')
|
|
->namespace($this->namespace)
|
|
->group(base_path('routes/api.php'));
|
|
|
|
Route::middleware('web')
|
|
->namespace($this->namespace)
|
|
->group(base_path('routes/web-bo.php'));
|
|
|
|
Route::middleware('web')
|
|
->namespace($this->namespace)
|
|
->group(base_path('routes/web-fo.php'));
|
|
// @codeCoverageIgnoreEnd
|
|
});
|
|
|
|
Route::model('brand', Brand::class);
|
|
Route::model('service', Service::class);
|
|
Route::model('single_optin', SingleOptin::class);
|
|
Route::model('question', Question::class);
|
|
Route::model('answer', Answer::class);
|
|
Route::model('customer', Customer::class);
|
|
|
|
// * Api parameters Bind.
|
|
Route::model('serviceQuestion', Question::class);
|
|
Route::bind('serviceCustomer', function ($value) {
|
|
// * Load brand
|
|
/** @var \App\Models\Brand $brand */
|
|
$brand = app(Service::class)->brand;
|
|
|
|
// ? Parameter is email
|
|
if (strpos($value, '@') !== false) {
|
|
$customer = Customer::query()->whereHas('brands', function (Builder $q) use ($brand) {
|
|
$q->where('brands.id', '=', $brand->id);
|
|
})->where('email', '=', $value)->firstOrFail();
|
|
}
|
|
|
|
try {
|
|
// ? Have we found a customer yet
|
|
if (!isset($customer) or \get_class($customer) !== Customer::class) {
|
|
// ? Parameter is hashcode
|
|
$customer = CustomerInfo::query()->whereHas('brand', function (Builder $q) use ($brand) {
|
|
$q->where('brands.id', '=', $brand->id);
|
|
})->where('hashcode', $value)
|
|
->with('customer')->firstOrFail()->customer;
|
|
}
|
|
|
|
// * Load Customer Login and Info for this brand.
|
|
/** @var \App\Models\Customer $customer */
|
|
|
|
return $customer->loadBrandData($brand);
|
|
} catch (ModelNotFoundException $e) {
|
|
// * Uniform Not found exception using model Customer.
|
|
throw (new ModelNotFoundException())->setModel(Customer::class);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Configure the rate limiters for the application.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function configureRateLimiting(): void
|
|
{
|
|
RateLimiter::for('web', function (Request $request) {
|
|
// @codeCoverageIgnoreStart
|
|
return Limit::perMinute(25)
|
|
->by(optional($request->user())->id ?: app('clientIp'));
|
|
// @codeCoverageIgnoreEnd
|
|
});
|
|
RateLimiter::for('api', function () {
|
|
return Limit::perMinute(config('api.apiRequestRatePerMinute', 100))
|
|
->by(app('clientIp'));
|
|
});
|
|
RateLimiter::for('credentials', function (Request $request) {
|
|
return Limit::perMinute(30)->by($request->user()?->id ?: app('clientIp'));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* * Register CSP report URI
|
|
*
|
|
* Put this function inside RouteServiceProvider,
|
|
* and call it in RouteServiceProvider::boot
|
|
*
|
|
* @return void
|
|
*/
|
|
private function cspReportRoute()
|
|
{
|
|
// * CSP REPORT URI, Please add /csp-report to VerifyCsrfToken $except middleware
|
|
\Illuminate\Support\Facades\Route::post('/csp-report', function () {
|
|
$isCspRequest = request()->header('Content-Type') === 'application/csp-report';
|
|
if (!$isCspRequest or !request()->json('csp-report') or !is_array(request()->json('csp-report'))) {
|
|
abort(401);
|
|
}
|
|
// * Flatten if needed
|
|
$cspReport = collect(request()->json('csp-report'))
|
|
->flatMap(function ($v, $k) {
|
|
return [$k => is_array($v) ? collect($v)->flatten()->implode(', ') : $v];
|
|
})->all();
|
|
// * Filter array keys
|
|
$cspReport = collect(array_intersect_key($cspReport, [
|
|
'blocked-uri' => '', 'document-uri' => '', 'original-policy' => '',
|
|
'referrer' => '', 'violated-directive' => ''
|
|
]));
|
|
\Illuminate\Support\Facades\Log::warning(sprintf(
|
|
"CSP REPORT for %s : \n %s",
|
|
$cspReport->get('document-uri'),
|
|
$cspReport->implode("\n")
|
|
));
|
|
})->middleware('throttle:5,2')
|
|
->withoutMiddleware(\App\Http\Middleware\VerifyCsrfToken::class)
|
|
->name('cspReportUri');
|
|
}
|
|
}
|