This commit is contained in:
parent
3320857c12
commit
2c25af9efc
Binary file not shown.
|
|
@ -37,8 +37,6 @@ class BannerController extends Controller
|
|||
}
|
||||
|
||||
return response($content)
|
||||
->header('Access-Control-Allow-Origin', env('APP_URL'))
|
||||
->header('Vary', 'origin')
|
||||
->header('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@ class GamesController extends Controller
|
|||
->first();
|
||||
|
||||
return response()->json(['available' => $status->operational])
|
||||
->header('Access-Control-Allow-Origin', env('APP_URL'))
|
||||
->header('Vary', 'origin')
|
||||
->header('Content-Type', 'application/json');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,5 +63,6 @@ class Kernel extends HttpKernel
|
|||
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
|
||||
'cors' => \App\Http\Middleware\Cors::class,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Cors
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
$nextClosure = $next($request);
|
||||
|
||||
if($passCheck)
|
||||
{
|
||||
$nextClosure
|
||||
->header('Access-Control-Allow-Origin', 'http' . ($request->secure() ? 's' : null) . '://' . $origin)
|
||||
->header('Vary', 'origin');
|
||||
}
|
||||
|
||||
return $nextClosure;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,10 +38,10 @@ class RouteServiceProvider extends ServiceProvider
|
|||
$this->configureRateLimiting();
|
||||
|
||||
$this->routes(function () {
|
||||
Route::domain('api.' . env('APP_URL'))
|
||||
Route::domain('apis.' . env('APP_URL'))
|
||||
->middleware('api')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/api.php'));
|
||||
->group(base_path('routes/apis.php'));
|
||||
|
||||
Route::domain('www.' . env('APP_URL'))
|
||||
->middleware('web')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
function CreateAccount(loginForm)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
export { CreateAccount };
|
||||
|
|
@ -37,7 +37,7 @@ class App extends React.Component {
|
|||
|
||||
function updateBanners()
|
||||
{
|
||||
axios.get(protocol + 'api.' + url + '/banners/data').then((response) => {
|
||||
axios.get(protocol + 'apis.' + url + '/banners/data').then((response) => {
|
||||
var result = [];
|
||||
response.data.map(function(banner){
|
||||
result.push(<Banner type={banner.type} description={banner.text} dismissible={banner.dismissable} />);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import React from 'react';
|
||||
|
||||
const Card = (props) => {
|
||||
return (
|
||||
<div className="container graphictoria-center-vh">
|
||||
<div className="card graphictoria-small-card shadow-sm">
|
||||
<div className="card-body text-center">
|
||||
{ props.children }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const CardTitle = (props) => {
|
||||
return (
|
||||
<>
|
||||
<h5 className="card-title fw-bold">{ props.children }</h5>
|
||||
<hr className="mx-5"/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
Card,
|
||||
CardTitle
|
||||
};
|
||||
|
|
@ -1,12 +1,19 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from "react-google-recaptcha";
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
|
||||
import SetTitle from "../Helpers/Title.js";
|
||||
import SetTitle from '../Helpers/Title.js';
|
||||
import { CreateAccount } from '../Helpers/Auth.js';
|
||||
|
||||
import { Card, CardTitle } from '../Layouts/Card.js';
|
||||
|
||||
import LoginForm from './Auth/Login.js';
|
||||
import ForgotPasswordForm from './Auth/ForgotPassword.js';
|
||||
import RegisterForm from './Auth/Register.js';
|
||||
|
||||
class Auth extends React.Component {
|
||||
componentDidMount()
|
||||
|
|
@ -28,90 +35,29 @@ class Auth extends React.Component {
|
|||
{
|
||||
case '/login':
|
||||
pageLabel = (<><i className="fas fa-user-circle"></i> SIGN IN</>);
|
||||
pageContent = (
|
||||
<>
|
||||
<div className="col-md-8 mb-2">
|
||||
<input type="username" className="form-control mb-4" placeholder="Username"/>
|
||||
<input type="password" className="form-control mb-3" placeholder="Password"/>
|
||||
<div className="d-flex mb-3">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
className="mx-auto"
|
||||
/>
|
||||
</div>
|
||||
<button className="btn btn-primary px-5">SIGN IN</button><br/>
|
||||
<Link to="/passwordreset" className="text-decoration-none fw-normal center">Forgot your password?</Link>
|
||||
</div>
|
||||
<div className="col">
|
||||
<h5>New to Graphictoria?</h5>
|
||||
<p>Creating an account takes less than a minute, and you can join a community of 6k+ users for <b>completely free</b>.<br/><Link to="/register" className="text-decoration-none fw-normal">Sign Up</Link></p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
pageContent = (<LoginForm />);
|
||||
break;
|
||||
case '/register':
|
||||
pageLabel = (<><i className="fas fa-user-plus"></i> REGISTER</>);
|
||||
pageContent = (
|
||||
<>
|
||||
<div className="px-5 mb-4">
|
||||
<div className="alert alert-warning graphictoria-alert" style={{ "borderRadius": "10px" }}>
|
||||
<p className="mb-0">Make sure your password is unique!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-sm-5">
|
||||
<input type="username" className="form-control" placeholder="Username" id="uname"/>
|
||||
<p id="unameLabel" className="text-muted form-text mb-1"><br/></p>
|
||||
<input type="email" className="form-control" placeholder="Email" id="email"/>
|
||||
<p id="emailLabel" className="text-muted form-text mb-1">Make sure your email is valid, you'll need to confirm it.</p>
|
||||
<input type="password" className="form-control" placeholder="Password" id="passwd"/>
|
||||
<p id="passwdLabel" className="text-muted form-text mb-1"><br/></p>
|
||||
<input type="password" className="form-control" placeholder="Confirm password" id="passwdconf"/>
|
||||
<p id="passwdconfLabel" className="text-muted form-text pb-0 mb-0"><br/></p>
|
||||
<div className="d-flex mb-3">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
className="mx-auto"
|
||||
/>
|
||||
</div>
|
||||
<button className="btn btn-success px-5">SIGN UP</button><br/>
|
||||
<Link to="/login" className="text-decoration-none fw-normal center">Already have an account?</Link>
|
||||
<p className="text-muted my-2">By creating an account, you agree to our <a href="/legal/terms-of-service" className="text-decoration-none fw-normal" target="_blank">Terms of Service</a> and our <a href="/legal/privacy-policy" className="text-decoration-none fw-normal" target="_blank">Privacy Policy</a>.</p>
|
||||
</div>
|
||||
</>
|
||||
<RegisterForm />
|
||||
);
|
||||
break;
|
||||
case '/passwordreset':
|
||||
pageLabel = (<><i className="fas fa-question-circle"></i> RESET PASSWORD</>);
|
||||
pageContent = (
|
||||
<div className="col-md-11 mx-auto">
|
||||
<input type="username" className="form-control mb-3" placeholder="Username"/>
|
||||
<div className="d-flex mb-3">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
className="mx-auto"
|
||||
/>
|
||||
</div>
|
||||
<button className="btn btn-primary px-5">RESET PASSWORD</button><br/>
|
||||
<Link to="/login" className="text-decoration-none fw-normal center">Login?</Link>
|
||||
</div>
|
||||
);
|
||||
pageContent = (<ForgotPasswordForm />);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container graphictoria-center-vh">
|
||||
<div className="card graphictoria-small-card shadow-sm">
|
||||
<div className="card-body text-center">
|
||||
<h5 className="card-title fw-bold">{ pageLabel }</h5>
|
||||
<hr className="mx-5"/>
|
||||
<div className="p-2 row">
|
||||
{ pageContent }
|
||||
</div>
|
||||
</div>
|
||||
<Card>
|
||||
<CardTitle>{ pageLabel }</CardTitle>
|
||||
<div className="p-2 row">
|
||||
{ pageContent }
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
|
||||
const ForgotPasswordForm = (props) => {
|
||||
return (
|
||||
<div className="col-md-11 mx-auto">
|
||||
<input type="username" className="form-control mb-3" placeholder="Username"/>
|
||||
<div className="d-flex mb-3">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
className="mx-auto"
|
||||
/>
|
||||
</div>
|
||||
<button className="btn btn-primary px-5">RESET PASSWORD</button><br/>
|
||||
<Link to="/login" className="text-decoration-none fw-normal center">Login?</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ForgotPasswordForm;
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
|
||||
const LoginForm = (props) => {
|
||||
return (
|
||||
<>
|
||||
<div className="col-md-8 mb-2">
|
||||
<input type="username" className="form-control mb-4" placeholder="Username"/>
|
||||
<input type="password" className="form-control mb-3" placeholder="Password"/>
|
||||
<div className="d-flex mb-3">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
className="mx-auto"
|
||||
/>
|
||||
</div>
|
||||
<button className="btn btn-primary px-5">SIGN IN</button><br/>
|
||||
<Link to="/passwordreset" className="text-decoration-none fw-normal center">Forgot your password?</Link>
|
||||
</div>
|
||||
<div className="col">
|
||||
<h5>New to Graphictoria?</h5>
|
||||
<p>Creating an account takes less than a minute, and you can join a community of 6k+ users for <b>completely free</b>.<br/><Link to="/register" className="text-decoration-none fw-normal">Sign Up</Link></p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginForm;
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// © XlXi 2021
|
||||
// Graphictoria 5
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import ReCAPTCHA from 'react-google-recaptcha';
|
||||
|
||||
import Loader from '../../Components/Loader.js';
|
||||
|
||||
const RegisterForm = (props) => {
|
||||
const RegistrationAreas = [
|
||||
{
|
||||
text: 'Username',
|
||||
type: 'username',
|
||||
id: 'username'
|
||||
},
|
||||
{
|
||||
text: 'Email',
|
||||
type: 'email',
|
||||
id: 'email'
|
||||
},
|
||||
{
|
||||
text: 'Password',
|
||||
type: 'password',
|
||||
id: 'password'
|
||||
},
|
||||
{
|
||||
text: 'Confirm password',
|
||||
type: 'password',
|
||||
id: 'confirmation'
|
||||
}
|
||||
];
|
||||
|
||||
const [waitingForSubmission, setWaitingForSubmission] = useState(false);
|
||||
|
||||
const [values, setValues] = useState({
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
confirmation: ''
|
||||
});
|
||||
|
||||
const [validity, setValidity] = useState({
|
||||
username: false,
|
||||
email: false,
|
||||
password: false,
|
||||
confirmation: false
|
||||
});
|
||||
|
||||
const [validityMessages, setValidityMessages] = useState({
|
||||
username: 'test',
|
||||
email: '',
|
||||
password: '',
|
||||
confirmation: ''
|
||||
});
|
||||
|
||||
const handleChange = (e) => {
|
||||
const {id, value} = e.target;
|
||||
|
||||
setValues(prevState => ({
|
||||
...prevState,
|
||||
[id] : value
|
||||
}));
|
||||
}
|
||||
|
||||
function SubmitRegistration()
|
||||
{
|
||||
setWaitingForSubmission(true);
|
||||
}
|
||||
|
||||
return (
|
||||
waitingForSubmission
|
||||
?
|
||||
<Loader />
|
||||
:
|
||||
(
|
||||
<>
|
||||
<div className="px-5 mb-2">
|
||||
<div className="alert alert-warning graphictoria-alert" style={{ "borderRadius": "10px" }}>
|
||||
<p className="mb-0">Make sure your password is unique!</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="px-sm-5">
|
||||
{
|
||||
RegistrationAreas.map(({ text, type, id }, index) =>
|
||||
<input key={ index } onChange={ handleChange } type={ type } className={ `form-control mb-2${ validityMessages[id] !== '' ? (validity[id] === true ? ' is-valid' : ' is-invalid') : ''}` } placeholder={ text } id={ id } />
|
||||
)
|
||||
}
|
||||
<div className="mt-3">
|
||||
<div className="d-flex mb-2">
|
||||
<ReCAPTCHA
|
||||
sitekey="6LeyHsUbAAAAAJ9smf-als-hXqrg7a-lHZ950-fL"
|
||||
className="mx-auto"
|
||||
/>
|
||||
</div>
|
||||
<button className="btn btn-success px-5" onClick={ SubmitRegistration }>SIGN UP</button>
|
||||
</div>
|
||||
<Link to="/login" className="text-decoration-none fw-normal center">Already have an account?</Link>
|
||||
<p className="text-muted my-2">By creating an account, you agree to our <a href="/legal/terms-of-service" className="text-decoration-none fw-normal" target="_blank">Terms of Service</a> and our <a href="/legal/privacy-policy" className="text-decoration-none fw-normal" target="_blank">Privacy Policy</a>.</p>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default RegisterForm;
|
||||
|
|
@ -6,37 +6,34 @@ import { Link, useHistory } from "react-router-dom";
|
|||
|
||||
import SetTitle from "../Helpers/Title.js";
|
||||
|
||||
import { Card, CardTitle } from '../Layouts/Card.js';
|
||||
|
||||
function GenericErrorModal(props)
|
||||
{
|
||||
const history = useHistory();
|
||||
|
||||
return (
|
||||
<div className="container graphictoria-center-vh">
|
||||
<div className="card graphictoria-small-card shadow-sm">
|
||||
<div className="card-body text-center">
|
||||
<h5 className="card-title fw-bold">{ props.title }</h5>
|
||||
<hr className="mx-5"/>
|
||||
<p className="card-text">{ props.children }</p>
|
||||
{
|
||||
props.stack !== undefined && process.env.NODE_ENV === 'development'
|
||||
?
|
||||
<div className="border border-primary bg-dark p-3 m-4">
|
||||
{/* this code is a jumbled mess */}
|
||||
<code>
|
||||
STACK TRACE<br/>{("-").repeat(15)}<br/>{ props.stack }
|
||||
</code>
|
||||
</div>
|
||||
:
|
||||
null
|
||||
}
|
||||
<div className="mt-2">
|
||||
<Link className="btn btn-primary px-4 me-2" to="/home">Home</Link>
|
||||
{/* eslint-disable-next-line */}
|
||||
<a className="btn btn-secondary px-4" onClick={ () => history.goBack() }>Back</a>
|
||||
<Card>
|
||||
<CardTitle>{ props.title }</CardTitle>
|
||||
<p className="card-text">{ props.children }</p>
|
||||
{
|
||||
props.stack !== undefined && process.env.NODE_ENV === 'development'
|
||||
?
|
||||
<div className="border border-primary bg-dark p-3 m-4">
|
||||
{/* this code is a jumbled mess */}
|
||||
<code>
|
||||
STACK TRACE<br/>{("-").repeat(15)}<br/>{ props.stack }
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
null
|
||||
}
|
||||
<div className="mt-2">
|
||||
<Link className="btn btn-primary px-4 me-2" to="/home">Home</Link>
|
||||
{/* eslint-disable-next-line */}
|
||||
<a className="btn btn-secondary px-4" onClick={ () => history.goBack() }>Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class Games extends React.Component {
|
|||
|
||||
SetTitle('Games');
|
||||
|
||||
axios.get(protocol + 'api.' + url + '/games/metadata').then((response) => {
|
||||
axios.get(protocol + 'apis.' + url + '/games/metadata').then((response) => {
|
||||
app.setState({loading: !(response.data.available == false), offline: !response.data.available});
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,16 +16,20 @@ use App\Http\Controllers\GamesController;
|
|||
|
|
||||
*/
|
||||
|
||||
Route::get('/', function () {
|
||||
return 'API OK';
|
||||
});
|
||||
Route::middleware(['cors'])->group(function() {
|
||||
|
||||
Route::get('/banners/data', [BannerController::class, 'getBanners']);
|
||||
Route::get('/', function () {
|
||||
return 'API OK';
|
||||
});
|
||||
|
||||
Route::get('/games/metadata', [GamesController::class, 'isAvailable']);
|
||||
Route::get('/banners/data', [BannerController::class, 'getBanners']);
|
||||
|
||||
Route::get('/games/metadata', [GamesController::class, 'isAvailable']);
|
||||
|
||||
Route::fallback(function () {
|
||||
return response('{"errors":[{"code":404,"message":"NotFound"}]}', 404)
|
||||
->header('Cache-Control', 'private')
|
||||
->header('Content-Type', 'application/json; charset=utf-8');
|
||||
});
|
||||
|
||||
Route::fallback(function () {
|
||||
return response('{"errors":[{"code":404,"message":"NotFound"}]}', 404)
|
||||
->header('Cache-Control', 'private')
|
||||
->header('Content-Type', 'application/json; charset=utf-8');
|
||||
});
|
||||
Loading…
Reference in New Issue