indev maintenance page, indev /asset impl
This commit is contained in:
parent
73547da723
commit
5f96ecd96f
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class ContentController extends Controller
|
||||
{
|
||||
public function fetchAsset(Request $request) {
|
||||
// Temporary
|
||||
// TODO: Fetch assets from DB, if it doesn't exist then redirect to roblox's assetdelivery.
|
||||
return redirect('https://assetdelivery.roblox.com/v1/asset/?id=' . $request->input('id'));
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,10 @@ use App\Models\WebsiteConfiguration;
|
|||
|
||||
class MaintenanceController extends Controller
|
||||
{
|
||||
public function showPage() {
|
||||
return view('maintenance');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the maintenance bypass request.
|
||||
*
|
||||
|
|
@ -20,50 +24,49 @@ class MaintenanceController extends Controller
|
|||
$password = $request->input('password');
|
||||
$buttons = $request->input('buttons');
|
||||
|
||||
if($password && $buttons)
|
||||
{
|
||||
$mtconf = json_decode(WebsiteConfiguration::whereName('MaintenancePassword')->first()->value);
|
||||
|
||||
if($password == $mtconf->password)
|
||||
{
|
||||
$btns = array_slice($buttons, -count($mtconf->combination));
|
||||
$data = json_decode(file_get_contents(storage_path('framework/down')), true);
|
||||
|
||||
if(isset($data['secret']) && $btns === $mtconf->combination)
|
||||
{
|
||||
$trustedHosts = explode(',', env('TRUSTED_HOSTS'));
|
||||
$origin = parse_url($request->headers->get('origin'), PHP_URL_HOST);
|
||||
$passCheck = false;
|
||||
|
||||
foreach($trustedHosts as &$host)
|
||||
{
|
||||
if(str_ends_with($origin, $host))
|
||||
$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);
|
||||
|
||||
if($passCheck)
|
||||
$bypassCookie = $bypassCookie->withDomain('.' . $origin);
|
||||
|
||||
return response('')
|
||||
->withCookie($bypassCookie);
|
||||
}
|
||||
}
|
||||
|
||||
return response('')
|
||||
->setStatusCode(403);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$password || !$buttons) {
|
||||
return response('{"errors":[{"code":400,"message":"BadRequest"}]}')
|
||||
->setStatusCode(400)
|
||||
->header('Cache-Control', 'private')
|
||||
->header('Content-Type', 'application/json; charset=utf-8');
|
||||
}
|
||||
|
||||
/* */
|
||||
|
||||
$mtconf = json_decode(WebsiteConfiguration::whereName('MaintenancePassword')->first()->value);
|
||||
|
||||
if(file_exists(storage_path('framework/down')) && $password == $mtconf->password)
|
||||
{
|
||||
$btns = array_slice($buttons, -count($mtconf->combination));
|
||||
$data = json_decode(file_get_contents(storage_path('framework/down')), true);
|
||||
|
||||
if(isset($data['secret']) && $btns === $mtconf->combination)
|
||||
{
|
||||
$trustedHosts = explode(',', env('TRUSTED_HOSTS'));
|
||||
$origin = parse_url($request->headers->get('origin'), PHP_URL_HOST);
|
||||
$passCheck = false;
|
||||
|
||||
foreach($trustedHosts as &$host)
|
||||
{
|
||||
if(str_ends_with($origin, $host))
|
||||
$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);
|
||||
|
||||
if($passCheck)
|
||||
$bypassCookie = $bypassCookie->withDomain('.' . $origin);
|
||||
|
||||
return response('')
|
||||
->withCookie($bypassCookie);
|
||||
}
|
||||
}
|
||||
|
||||
return response('')
|
||||
->setStatusCode(403);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class Kernel extends HttpKernel
|
|||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
],
|
||||
|
||||
'admin' => [
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class PreventRequestsDuringMaintenance
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = ['banners/data', 'maintenance/bypass'];
|
||||
protected $except = ['maintenance', 'maintenance/bypass'];
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AssetGenre extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
||||
|
|
@ -102,6 +102,26 @@ return [
|
|||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'mysql-asset' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_ASSET_DATABASE', 'gtoriadev_primary'),
|
||||
'username' => env('DB_USERNAME', 'gtoriadev_primary'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => '',
|
||||
'prefix_indexes' => true,
|
||||
'strict' => true,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
|
|
|
|||
|
|
@ -6,6 +6,13 @@ use Illuminate\Support\Facades\Schema;
|
|||
|
||||
class CreateAssetTypesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* The database connection that should be used by the migration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connection = 'mysql-asset';
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
|
|
@ -15,6 +22,8 @@ class CreateAssetTypesTable extends Migration
|
|||
{
|
||||
Schema::create('asset_types', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->longText('name');
|
||||
$table->boolean('binaryFormat')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,13 @@ use Illuminate\Support\Facades\Schema;
|
|||
|
||||
class CreateAssetsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* The database connection that should be used by the migration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connection = 'mysql-asset';
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
|
|
@ -13,8 +20,19 @@ class CreateAssetsTable extends Migration
|
|||
*/
|
||||
public function up()
|
||||
{
|
||||
// TODO: relational genres?
|
||||
// god i fucking hate foreign keys
|
||||
Schema::create('assets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('creatorId');
|
||||
$table->longText('title');
|
||||
$table->longText('description');
|
||||
$table->json('settings');
|
||||
$table->boolean('commentsEnabled')->default(true);
|
||||
$table->boolean('purchasable')->default(false);
|
||||
$table->unsignedBigInteger('assetVersionId');
|
||||
$table->unsignedBigInteger('assetTypeId');
|
||||
$table->unsignedBigInteger('assetGenreId');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,13 @@ use Illuminate\Support\Facades\Schema;
|
|||
|
||||
class CreateAssetVersionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* The database connection that should be used by the migration.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $connection = 'mysql-asset';
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
|
|
@ -15,6 +22,8 @@ class CreateAssetVersionsTable extends Migration
|
|||
{
|
||||
Schema::create('asset_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('assetId');
|
||||
$table->longText('cdnHash');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateAssetGenresTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('asset_genres', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->longText('name');
|
||||
$table->longText('iconUrl');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('asset_genres');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"/js/app.js": "/js/app.js",
|
||||
"/js/pages/maintenance.js": "/js/pages/maintenance.js",
|
||||
"/css/graphictoria.css": "/css/graphictoria.css"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import React, { useRef, Suspense } from 'react';
|
||||
|
||||
import { buildGenericApiUrl } from '../util/HTTP.js';
|
||||
|
||||
import { Canvas, useFrame } from '@react-three/fiber';
|
||||
import { Instances, Instance, PerspectiveCamera, useGLTF } from '@react-three/drei';
|
||||
|
||||
const randomVector = (r) => [r / 2 - Math.random() * r, r / 2 - Math.random() * r, r / 2 - Math.random() * r];
|
||||
const randomEuler = () => [Math.random() * Math.PI, Math.random() * Math.PI, Math.random() * Math.PI];
|
||||
const randomData = Array.from({ length: 2000 }, (r = 200) => ({ random: Math.random(), position: randomVector(r), rotation: randomEuler() }));
|
||||
|
||||
function Scene() {
|
||||
const { nodes, materials } = useGLTF('/models/graphictoriapart.glb');
|
||||
|
||||
return (
|
||||
<>
|
||||
<ambientLight />
|
||||
<pointLight position={[10, 10, 10]} />
|
||||
<Instances range={2000} material={materials.Material} geometry={nodes.Cube.geometry} >
|
||||
{
|
||||
randomData.map((props, i) => (
|
||||
<Box key={i} {...props} />
|
||||
))
|
||||
}
|
||||
</Instances>
|
||||
<Camera makeDefault />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Box({ random, ...props }){
|
||||
const ref = useRef()
|
||||
useFrame((state) => {
|
||||
const t = state.clock.getElapsedTime() + random * 10000
|
||||
ref.current.rotation.set(Math.cos(t / 4) / 2, Math.sin(t / 4) / 2, Math.cos(t / 1.5) / 2)
|
||||
ref.current.position.y = Math.sin(t / 1.5) / 2
|
||||
});
|
||||
return (
|
||||
<group {...props}>
|
||||
<Instance ref={ref} />
|
||||
</group>
|
||||
)
|
||||
}
|
||||
|
||||
function Camera({ ...props }){
|
||||
const ref = useRef()
|
||||
useFrame((state) => {
|
||||
const t = state.clock.getElapsedTime() / 30
|
||||
ref.current.position.x = 10 * Math.cos(t);
|
||||
ref.current.position.y = 4 * Math.sin(t);
|
||||
ref.current.position.z = 10 * Math.sin(t);
|
||||
ref.current.lookAt(0, 0, 0);
|
||||
});
|
||||
return (
|
||||
<PerspectiveCamera ref={ref} {...props} />
|
||||
)
|
||||
}
|
||||
|
||||
let ButtonHistory = []
|
||||
|
||||
function attemptBypass() {
|
||||
axios.post(buildGenericApiUrl('apis', 'v1/maintenance/bypass'), {
|
||||
'password': $('#gt_mt_buttons > input').val(),
|
||||
'buttons': ButtonHistory.slice(-40)
|
||||
})
|
||||
.then((response) => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
ReactDOM.render(
|
||||
(<Canvas>
|
||||
<Suspense fallback={null}>
|
||||
<Scene />
|
||||
</Suspense>
|
||||
</Canvas>),
|
||||
document.getElementsByClassName('gtoria-maintenance-background')[0]
|
||||
);
|
||||
|
||||
$('#gt_mt_buttons').on('click', 'button', function() {
|
||||
let ButtonId = parseInt(this.getAttribute('name').substr(8)); //gt_mtbtnX
|
||||
|
||||
ButtonHistory.push(ButtonId);
|
||||
attemptBypass();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
const urlObject = new URL(document.location.href);
|
||||
|
||||
export function getCurrentDomain() {
|
||||
return urlObject.hostname.replace(/^[^.]+\./g, '');
|
||||
};
|
||||
|
||||
export function getProtocol() {
|
||||
return urlObject.protocol;
|
||||
};
|
||||
|
||||
export function buildGenericApiUrl(subdomain, path) {
|
||||
return `${getProtocol()}//${subdomain}.${getCurrentDomain()}/${path}`;
|
||||
};
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
@php
|
||||
$noFooter = true;
|
||||
|
||||
$buttons = str_split('Graphictoria')
|
||||
@endphp
|
||||
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('page-specific')
|
||||
<script src="{{ asset('js/pages/maintenance.js') }}"></script>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="gtoria-maintenance-background"></div>
|
||||
<div class="text-center m-auto container gtoria-maintenance-form">
|
||||
<h1>Graphictoria is currently under maintenance.</h1>
|
||||
<h4>Our cyborg team of highly trained code-monkes are working to make Graphictoria better. We'll be back soon!</h4>
|
||||
<div class="input-group mt-5 d-none d-md-flex" id="gt_mt_buttons">
|
||||
<input type="password" class="form-control" placeholder="Password" autoComplete="off" />
|
||||
@foreach($buttons as $index => $button)
|
||||
<button class="btn btn-secondary" type="button" name="gt_mtbtn{{ $index }}">{{ $button }}</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -2,12 +2,6 @@
|
|||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\AuthController;
|
||||
use App\Http\Controllers\BannerController;
|
||||
use App\Http\Controllers\GamesController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use App\Http\Controllers\Auth\RegisterController;
|
||||
use App\Http\Controllers\Controller; // remove this and clean up the code lol
|
||||
use App\Models\User;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -17,4 +17,8 @@ use Illuminate\Support\Facades\Route;
|
|||
Route::view('/', 'home');
|
||||
|
||||
// misc
|
||||
Route::view('/javascript', 'javascript');
|
||||
Route::any('/maintenance', 'MaintenanceController@showPage');
|
||||
Route::view('/javascript', 'javascript');
|
||||
|
||||
// client
|
||||
Route::get('/asset', 'ContentController@fetchAsset');
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ require('laravel-mix-banner');
|
|||
*/
|
||||
|
||||
mix.js('resources/js/app.js', 'public/js')
|
||||
.js('resources/js/pages/maintenance.js', 'public/js/pages')
|
||||
.react()
|
||||
.sass('resources/sass/graphictoria.scss', 'public/css')
|
||||
.banner({
|
||||
|
|
|
|||
Loading…
Reference in New Issue