24
common/Core/Middleware/EnableDebugIfLoggedInAsAdmin.php
Executable file
24
common/Core/Middleware/EnableDebugIfLoggedInAsAdmin.php
Executable file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class EnableDebugIfLoggedInAsAdmin
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($this->loggedInAsAdmin()) {
|
||||
config(['app.debug' => true]);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
protected function loggedInAsAdmin(): bool
|
||||
{
|
||||
return Auth::user() && Auth::user()->hasPermission('admin');
|
||||
}
|
||||
}
|
||||
24
common/Core/Middleware/EnsureEmailIsVerified.php
Executable file
24
common/Core/Middleware/EnsureEmailIsVerified.php
Executable file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Common\Settings\Settings;
|
||||
use Illuminate\Auth\Middleware\EnsureEmailIsVerified as LaravelMiddleware;
|
||||
|
||||
class EnsureEmailIsVerified extends LaravelMiddleware
|
||||
{
|
||||
public function handle($request, Closure $next, $redirectToRoute = null)
|
||||
{
|
||||
// bail if user is not logged in, it will be handled by policies
|
||||
// also bail if email verification is disabled from settings page
|
||||
if (
|
||||
!$request->user() ||
|
||||
!app(Settings::class)->get('require_email_confirmation')
|
||||
) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return parent::handle($request, $next, $redirectToRoute);
|
||||
}
|
||||
}
|
||||
45
common/Core/Middleware/EnsureFrontendRequestsAreStateful.php
Executable file
45
common/Core/Middleware/EnsureFrontendRequestsAreStateful.php
Executable file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful as LaravelMiddleware;
|
||||
|
||||
class EnsureFrontendRequestsAreStateful extends LaravelMiddleware
|
||||
{
|
||||
public static function fromFrontend($request): bool
|
||||
{
|
||||
$domain =
|
||||
$request->headers->get('referer') ?:
|
||||
$request->headers->get('origin');
|
||||
|
||||
if (is_null($domain)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make sure api calls from api docs page are not considered stateful to avoid 419 errors on POST requests
|
||||
if (Str::contains($domain, '/api-docs')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$domain = parse_url($domain, PHP_URL_HOST);
|
||||
$domain = Str::replaceFirst('www.', '', $domain);
|
||||
$domain = Str::endsWith($domain, '/') ? $domain : "{$domain}/";
|
||||
|
||||
$stateful = [
|
||||
...array_filter(config('sanctum.stateful', [])),
|
||||
parse_url(config('app.url'), PHP_URL_HOST),
|
||||
];
|
||||
|
||||
return Str::is(
|
||||
Collection::make($stateful)
|
||||
->map(
|
||||
fn($uri) => Str::replaceFirst('www.', '', trim($uri)) .
|
||||
'/*',
|
||||
)
|
||||
->all(),
|
||||
$domain,
|
||||
);
|
||||
}
|
||||
}
|
||||
25
common/Core/Middleware/IsAdmin.php
Executable file
25
common/Core/Middleware/IsAdmin.php
Executable file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Auth;
|
||||
use Closure;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class IsAdmin
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ( ! Auth::check()) {
|
||||
throw new AuthenticationException();
|
||||
}
|
||||
|
||||
if ( ! Auth::user()->hasPermission('admin')) {
|
||||
throw new AuthorizationException();
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
17
common/Core/Middleware/JsonMiddleware.php
Executable file
17
common/Core/Middleware/JsonMiddleware.php
Executable file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class JsonMiddleware
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$request->headers->set('Accept', 'application/json');
|
||||
//$request->headers->set('Content-Type', 'application/json');
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
92
common/Core/Middleware/PrerenderIfCrawler.php
Executable file
92
common/Core/Middleware/PrerenderIfCrawler.php
Executable file
@@ -0,0 +1,92 @@
|
||||
<?php namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Common\Core\Controllers\HomeController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class PrerenderIfCrawler
|
||||
{
|
||||
protected array $crawlerUserAgents = [
|
||||
'Yahoo! Slurp',
|
||||
'bingbot',
|
||||
'yandex',
|
||||
'baiduspider',
|
||||
'facebookexternalhit',
|
||||
'twitterbot',
|
||||
'rogerbot',
|
||||
'linkedinbot',
|
||||
'embedly',
|
||||
'quora link preview',
|
||||
'showyoubot',
|
||||
'outbrain',
|
||||
'pinterest/0.',
|
||||
'slackbot',
|
||||
'vkShare',
|
||||
'W3C_Validator',
|
||||
'redditbot',
|
||||
'Applebot',
|
||||
'WhatsApp',
|
||||
'flipboard',
|
||||
'tumblr',
|
||||
'bitlybot',
|
||||
'SkypeUriPreview',
|
||||
'nuzzel',
|
||||
'Discordbot',
|
||||
'Qwantify',
|
||||
'pinterestbot',
|
||||
'Bitrix link preview',
|
||||
'XING-contenttabreceiver',
|
||||
'developers.google.com/+/web/snippet',
|
||||
];
|
||||
|
||||
public function handle(
|
||||
Request $request,
|
||||
Closure $next,
|
||||
string $routeName = null
|
||||
) {
|
||||
if ($this->shouldPrerender($request)) {
|
||||
define('SHOULD_PRERENDER', true);
|
||||
|
||||
// Always fallback to client routes if not prerendering
|
||||
// otherwise prerender routes will override client side routing
|
||||
} elseif ($routeName !== 'homepage') {
|
||||
return app(HomeController::class)->show();
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
protected function shouldPrerender(Request $request): bool
|
||||
{
|
||||
$userAgent = strtolower($request->server->get('HTTP_USER_AGENT'));
|
||||
$bufferAgent = $request->server->get('X-BUFFERBOT');
|
||||
|
||||
$shouldPrerender = false;
|
||||
|
||||
if (!$userAgent) {
|
||||
return false;
|
||||
}
|
||||
if (!$request->isMethod('GET')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// prerender if _escaped_fragment_ is in the query string
|
||||
if ($request->query->has('_escaped_fragment_')) {
|
||||
$shouldPrerender = true;
|
||||
}
|
||||
|
||||
// prerender if a crawler is detected
|
||||
foreach ($this->crawlerUserAgents as $crawlerUserAgent) {
|
||||
if (Str::contains($userAgent, strtolower($crawlerUserAgent))) {
|
||||
$shouldPrerender = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($bufferAgent) {
|
||||
$shouldPrerender = true;
|
||||
}
|
||||
|
||||
return $shouldPrerender;
|
||||
}
|
||||
}
|
||||
177
common/Core/Middleware/RestrictDemoSiteFunctionality.php
Executable file
177
common/Core/Middleware/RestrictDemoSiteFunctionality.php
Executable file
@@ -0,0 +1,177 @@
|
||||
<?php namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class RestrictDemoSiteFunctionality
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (
|
||||
Auth::user() &&
|
||||
Auth::user()->email === 'Ic0OdCIodqz8q1r@demo.com'
|
||||
) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$uri = str_replace(
|
||||
['secure/', 'api/v1/'],
|
||||
'',
|
||||
$request->route()->uri(),
|
||||
);
|
||||
|
||||
if ($this->shouldForbidRequest($request, $uri)) {
|
||||
abort(403, "You can't do that on demo site.");
|
||||
}
|
||||
|
||||
if ($uri === 'settings') {
|
||||
return $this->manglePrivateSettings($next($request));
|
||||
}
|
||||
|
||||
if ($uri === 'users' || $uri === 'billing/subscriptions') {
|
||||
return $this->mangleUserEmails($next($request));
|
||||
}
|
||||
|
||||
if (
|
||||
($uri === 'billing/stripe/cards/add' ||
|
||||
$uri === 'billing/subscriptions/paypal/agreement/create') &&
|
||||
(Auth::user() && Auth::user()->email === 'admin@admin.com')
|
||||
) {
|
||||
abort(403, "Demo admin account can't subscribe to plans.");
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if specified request should be forbidden on demo site.
|
||||
*/
|
||||
private function shouldForbidRequest(Request $request, string $uri): bool
|
||||
{
|
||||
$method = $request->method();
|
||||
|
||||
foreach (config('common.demo-blocked-routes') as $route) {
|
||||
if (
|
||||
$method === $route['method'] &&
|
||||
trim($uri) === trim($route['name'])
|
||||
) {
|
||||
$originMatches = true;
|
||||
$paramsMatch = true;
|
||||
|
||||
//block this request only if it originated from specified origin, for example: admin area
|
||||
if (isset($route['origin'])) {
|
||||
$originMatches = Str::contains(
|
||||
$request->server('HTTP_REFERER'),
|
||||
$route['origin'],
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($route['params'])) {
|
||||
$paramsMatch =
|
||||
collect($route['params'])->first(function (
|
||||
$param,
|
||||
$key
|
||||
) use ($request) {
|
||||
$routeParam = $request->route($key);
|
||||
if (is_array($param)) {
|
||||
return in_array($routeParam, $param);
|
||||
} else {
|
||||
return $routeParam == $param;
|
||||
}
|
||||
}) !== null;
|
||||
}
|
||||
|
||||
return $originMatches && $paramsMatch;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mangle settings values, so they are not visible on demo site.
|
||||
*/
|
||||
private function manglePrivateSettings(Response $response): Response
|
||||
{
|
||||
$serverKeys = [
|
||||
'google_id',
|
||||
'google_secret',
|
||||
'twitter_id',
|
||||
'twitter_secret',
|
||||
'facebook_id',
|
||||
'facebook_secret',
|
||||
'spotify_id',
|
||||
'spotify_secret',
|
||||
'lastfm_api_key',
|
||||
'soundcloud_api_key',
|
||||
'sentry_dns',
|
||||
'mailgun_secret',
|
||||
'sentry_dsn',
|
||||
'paypal_client_id',
|
||||
'pusher_key',
|
||||
'pusher_secret',
|
||||
'paypal_secret',
|
||||
'stripe_key',
|
||||
'stripe_secret',
|
||||
'mail_password',
|
||||
'tmdb_api_key',
|
||||
'storage_digitalocean_key',
|
||||
'storage_digitalocean_secret',
|
||||
'stripe_webhook_secret',
|
||||
'openai_api_key',
|
||||
];
|
||||
|
||||
$clientKeys = [
|
||||
'youtube_api_key',
|
||||
'logging.sentry_public',
|
||||
'analytics.google_id',
|
||||
'builder.google_fonts_api_key',
|
||||
'recaptcha.site_key',
|
||||
'recaptcha.secret_key',
|
||||
];
|
||||
|
||||
$settings = json_decode($response->getContent(), true);
|
||||
|
||||
foreach ($serverKeys as $key) {
|
||||
if (isset($settings['server'][$key])) {
|
||||
$settings['server'][$key] = Str::random(30);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($clientKeys as $key) {
|
||||
if (isset($settings['client'][$key])) {
|
||||
$settings['client'][$key] = Str::random(30);
|
||||
}
|
||||
}
|
||||
|
||||
$response->setContent(json_encode($settings));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mangle settings values, so they are not visible on demo site.
|
||||
*/
|
||||
private function mangleUserEmails(Response $response): Response
|
||||
{
|
||||
$pagination = json_decode($response->getContent(), true);
|
||||
|
||||
$pagination['data'] = array_map(function ($item) {
|
||||
if (isset($item['email'])) {
|
||||
$item['email'] = 'hidden@demo.com';
|
||||
} elseif (isset($item['user']['email'])) {
|
||||
$item['user']['email'] = 'hidden@demo.com';
|
||||
}
|
||||
|
||||
return $item;
|
||||
}, Arr::get($pagination, 'data', []));
|
||||
|
||||
$response->setContent(json_encode($pagination));
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
49
common/Core/Middleware/SetAppLocale.php
Executable file
49
common/Core/Middleware/SetAppLocale.php
Executable file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Common\Localizations\Localization;
|
||||
use Common\Localizations\UserLocaleController;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cookie;
|
||||
use Negotiation\LanguageNegotiator;
|
||||
|
||||
class SetAppLocale
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (settings('i18n.enable')) {
|
||||
// 1. Check if current user has manually selected a specific language
|
||||
$langCode =
|
||||
$request->get('lang') ??
|
||||
($request->user()->language ??
|
||||
Cookie::get(UserLocaleController::COOKIE_NAME));
|
||||
|
||||
$defaultLocale = settings('locale.default', 'auto');
|
||||
|
||||
// 2. if admin manually selected a specific default locale, use that
|
||||
if (!$langCode && $defaultLocale && $defaultLocale !== 'auto') {
|
||||
$langCode = $defaultLocale;
|
||||
}
|
||||
|
||||
// 3. Try to use language based on browser settings
|
||||
if (!$langCode && ($header = $request->header('Accept-Language'))) {
|
||||
$languages = Localization::pluck('language');
|
||||
if ($languages->isNotEmpty()) {
|
||||
$bestLanguage = (new LanguageNegotiator())->getBest(
|
||||
$header,
|
||||
$languages->toArray(),
|
||||
);
|
||||
$langCode = $bestLanguage?->getBasePart();
|
||||
}
|
||||
}
|
||||
|
||||
if ($langCode) {
|
||||
app()->setLocale($langCode);
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
23
common/Core/Middleware/SetSentryUserMiddleware.php
Executable file
23
common/Core/Middleware/SetSentryUserMiddleware.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Sentry\State\Scope;
|
||||
use function Sentry\configureScope;
|
||||
|
||||
class SetSentryUserMiddleware
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($user = Auth::user()) {
|
||||
configureScope(function (Scope $scope) use ($user) {
|
||||
$scope->setUser(['email' => $user->email, 'id' => $user->id]);
|
||||
});
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
23
common/Core/Middleware/SimulateSlowConnectionMiddleware.php
Executable file
23
common/Core/Middleware/SimulateSlowConnectionMiddleware.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class SimulateSlowConnectionMiddleware
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if ($speed = config('common.site.simulated_connection')) {
|
||||
if ($speed === 'medium') {
|
||||
// 200ms
|
||||
usleep(200000);
|
||||
} elseif ($speed === 'slow') {
|
||||
// 1s
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
26
common/Core/Middleware/TrustProxies.php
Executable file
26
common/Core/Middleware/TrustProxies.php
Executable file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Common\Core\Middleware;
|
||||
|
||||
use Illuminate\Http\Middleware\TrustProxies as Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends Middleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*/
|
||||
protected $proxies = '*';
|
||||
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
Reference in New Issue
Block a user