diff --git a/web/app/Helpers/MaintenanceHelper.php b/web/app/Helpers/MaintenanceHelper.php new file mode 100644 index 0000000..4e0c1be --- /dev/null +++ b/web/app/Helpers/MaintenanceHelper.php @@ -0,0 +1,31 @@ +isDownForMaintenance() && !MaintenanceHelper::hasValidBypassCookie($request, $data)); + } + + protected static function hasValidBypassCookie(Request $request, array $data) + { + return isset($data['secret']) && + $request->cookie('gt_constraint') && + MaintenanceModeBypassCookie::isValid( + $request->cookie('gt_constraint'), + $data['secret'] + ); + } +} diff --git a/web/app/Http/Controllers/MaintenanceController.php b/web/app/Http/Controllers/MaintenanceController.php index fceb5bf..23e6c00 100644 --- a/web/app/Http/Controllers/MaintenanceController.php +++ b/web/app/Http/Controllers/MaintenanceController.php @@ -10,8 +10,11 @@ use App\Models\WebsiteConfiguration; class MaintenanceController extends Controller { - public function showPage() { - return view('maintenance'); + public function showPage() + { + $data = json_decode(file_get_contents(storage_path('framework/down')), true); + + return view('maintenance', ['hideLogin' => !isset($data['secret'])]); } /** @@ -25,8 +28,7 @@ class MaintenanceController extends Controller $buttons = $request->input('buttons'); if(!$password || !$buttons) { - return response('{"errors":[{"code":400,"message":"BadRequest"}]}') - ->setStatusCode(400) + return response('{"errors":[{"code":400,"message":"BadRequest"}]}', 400) ->header('Cache-Control', 'private') ->header('Content-Type', 'application/json; charset=utf-8'); } @@ -43,7 +45,7 @@ class MaintenanceController extends Controller if(isset($data['secret']) && $btns === $mtconf->combination) { $trustedHosts = explode(',', env('TRUSTED_HOSTS')); - $origin = parse_url($request->headers->get('origin'), PHP_URL_HOST); + $origin = join('.', array_slice(explode('.', $request->headers->get('origin')), -2)); $passCheck = false; foreach($trustedHosts as &$host) @@ -52,11 +54,14 @@ class MaintenanceController extends Controller $passCheck = true; } + $expiresAt = Carbon::now()->addHours(24); $bypassCookie = new Cookie('gt_constraint', base64_encode(json_encode([ 'expires_at' => $expiresAt->getTimestamp(), 'mac' => hash_hmac('SHA256', $expiresAt->getTimestamp(), $data['secret']), ])), $expiresAt); + $bypassCookie = $bypassCookie->withSecure(false); + //$bypassCookie = $bypassCookie->withSameSite('none'); if($passCheck) $bypassCookie = $bypassCookie->withDomain('.' . $origin); @@ -66,7 +71,6 @@ class MaintenanceController extends Controller } } - return response('') - ->setStatusCode(403); + return response('', 403); } } diff --git a/web/app/Http/Kernel.php b/web/app/Http/Kernel.php index c056a06..8233601 100644 --- a/web/app/Http/Kernel.php +++ b/web/app/Http/Kernel.php @@ -43,7 +43,6 @@ class Kernel extends HttpKernel 'api' => [ // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, - 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, ], diff --git a/web/app/Http/Middleware/PreventRequestsDuringMaintenance.php b/web/app/Http/Middleware/PreventRequestsDuringMaintenance.php index fb1511e..37ef5e3 100644 --- a/web/app/Http/Middleware/PreventRequestsDuringMaintenance.php +++ b/web/app/Http/Middleware/PreventRequestsDuringMaintenance.php @@ -2,14 +2,17 @@ namespace App\Http\Middleware; +use App\Helpers\MaintenanceHelper; + use Closure; use Illuminate\Support\Facades\Route; +use Illuminate\Http\Request; class PreventRequestsDuringMaintenance { - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { - if(app()->isDownForMaintenance()) { + if(MaintenanceHelper::isDown($request)) { if(in_array('web', $request->route()->middleware())) { if($request->route()->uri() != 'maintenance') @@ -17,6 +20,9 @@ class PreventRequestsDuringMaintenance } else { + if(in_array('api', $request->route()->middleware()) && str_starts_with($request->route()->uri(), 'v1/maintenance')) + return $next($request); + return response(['errors' => [['code' => 503, 'message' => 'ServiceUnavailable']]], 503) ->header('Cache-Control', 'private') ->header('Content-Type', 'application/json; charset=utf-8'); diff --git a/web/app/Providers/MaintenanceServiceProvider.php b/web/app/Providers/MaintenanceServiceProvider.php index d068827..6fd1a8d 100644 --- a/web/app/Providers/MaintenanceServiceProvider.php +++ b/web/app/Providers/MaintenanceServiceProvider.php @@ -32,7 +32,7 @@ class MaintenanceServiceProvider extends ServiceProvider public function boot() { Blade::directive('live', function() { - return 'isDownForMaintenance()): ?>'; + return ''; }); Blade::directive('endlive', function() { diff --git a/web/app/Providers/RouteServiceProvider.php b/web/app/Providers/RouteServiceProvider.php index 3f1d593..9b58e15 100644 --- a/web/app/Providers/RouteServiceProvider.php +++ b/web/app/Providers/RouteServiceProvider.php @@ -2,10 +2,8 @@ namespace App\Providers; -use Illuminate\Cache\RateLimiting\Limit; 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 @@ -20,15 +18,6 @@ class RouteServiceProvider extends ServiceProvider public const HOME = '/home'; protected $namespace = 'App\Http\Controllers'; - - /** - * The controller namespace for the application. - * - * When present, controller route declarations will automatically be prefixed with this namespace. - * - * @var string|null - */ - // protected $namespace = 'App\\Http\\Controllers'; /** * Define your route model bindings, pattern filters, etc. @@ -81,16 +70,4 @@ class RouteServiceProvider extends ServiceProvider ->group(base_path('routes/web.php')); }); } - -// /** -// * Configure the rate limiters for the application. -// * -// * @return void -// */ -// protected function configureRateLimiting() -// { -// RateLimiter::for('api', function (Request $request) { -// return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip()); -// }); -// } } diff --git a/web/public/mix-manifest.json b/web/public/mix-manifest.json index 7b4515d..f6ed187 100644 --- a/web/public/mix-manifest.json +++ b/web/public/mix-manifest.json @@ -1,5 +1,5 @@ { "/js/app.js": "/js/app.js?id=cd2fb1cee326ab151ccc", - "/js/pages/maintenance.js": "/js/pages/maintenance.js?id=8b2854bc9146fb6d6d92", + "/js/pages/maintenance.js": "/js/pages/maintenance.js?id=48c6a431110c9ea51807", "/css/graphictoria.css": "/css/graphictoria.css?id=569f8477631683f9ea96" } diff --git a/web/resources/js/util/HTTP.js b/web/resources/js/util/HTTP.js index 45dbe1c..249a5b1 100644 --- a/web/resources/js/util/HTTP.js +++ b/web/resources/js/util/HTTP.js @@ -4,7 +4,7 @@ const urlObject = new URL(document.location.href); export function getCurrentDomain() { - return urlObject.hostname.replace(/^[^.]+\./g, ''); + return urlObject.hostname.split('.').slice(-2).join('.'); }; export function getProtocol() { diff --git a/web/resources/views/home.blade.php b/web/resources/views/home.blade.php index 767e1f3..28adbb4 100644 --- a/web/resources/views/home.blade.php +++ b/web/resources/views/home.blade.php @@ -5,7 +5,8 @@

Graphictoria

-
Graphictoria aims to revive the classic Roblox experience. Join 8k+ other users and relive your childhood!
+ {{-- TODO: make the user count automatic via a model --}} +
Graphictoria aims to revive the classic Roblox experience. Join 9k+ other users and relive your childhood!

* Graphictoria is not affiliated with, endorsed by, or sponsored by Roblox Corporation.

Create your account diff --git a/web/resources/views/maintenance.blade.php b/web/resources/views/maintenance.blade.php index bdc6e2f..8282134 100644 --- a/web/resources/views/maintenance.blade.php +++ b/web/resources/views/maintenance.blade.php @@ -19,11 +19,13 @@ $buttons = str_split('Graphictoria')

Graphictoria is currently under maintenance.

Our cyborg team of highly trained code-monkes are working to make Graphictoria better. We'll be back soon!

-
- - @foreach($buttons as $index => $button) - - @endforeach -
+ @if(!$hideLogin) +
+ + @foreach($buttons as $index => $button) + + @endforeach +
+ @endif
@endsection