diff --git a/web/.env.example b/web/.env.example index 44853cd..17430bf 100644 --- a/web/.env.example +++ b/web/.env.example @@ -1,19 +1,24 @@ -APP_NAME=Laravel +TRUSTED_HOSTS=localhost,gtoria.local + +APP_NAME=Graphictoria APP_ENV=local APP_KEY= APP_DEBUG=true -APP_URL=http://localhost +APP_URL=http://gtoria.local LOG_CHANNEL=stack LOG_LEVEL=debug -DB_CONNECTION=mysql +DB_CONNECTION=mysql-primary DB_HOST=127.0.0.1 DB_PORT=3306 -DB_DATABASE=laravel -DB_USERNAME=root +DB_USERNAME=service-laravel DB_PASSWORD= +DB_PRIMARY_DATABASE=gtoriadev_primary +DB_MEMBERSHIP_DATABASE=gtoriadev_membership +DB_FFLAG_DATABASE=gtoriadev_fflag + BROADCAST_DRIVER=log CACHE_DRIVER=file FILESYSTEM_DRIVER=local @@ -21,7 +26,7 @@ QUEUE_CONNECTION=sync SESSION_DRIVER=file SESSION_LIFETIME=120 -MEMCACHED_HOST=127.0.0.1 +MEMCACHED_HOST=memcached REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null @@ -48,4 +53,4 @@ PUSHER_APP_SECRET= PUSHER_APP_CLUSTER=mt1 MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" -MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" +MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" \ No newline at end of file diff --git a/web/app/Helpers/AuthHelper.php b/web/app/Helpers/AuthHelper.php new file mode 100644 index 0000000..205e1f7 --- /dev/null +++ b/web/app/Helpers/AuthHelper.php @@ -0,0 +1,65 @@ +session()->exists('authentication')) { + $session = UserSession::where('token', $request->session()->get('authentication'))->first(); + + if($session) + return User::where('id', $session->user)->first(); + + return; + } + + return; + } + + /** + * Grants a session. + * + * @return UserSession + */ + public static function GrantSession($request, $id) { + $session = new UserSession(); + $session->user = $id; + // formerly cookies + $session->token = 'DO_NOT_SHARE_OR_YOUR_ITEMS_WILL_BE_STOLEN_|' . Random::Str(64); + $session->ip = $request->ip(); + $session->last_seen = Carbon::now(); + $session->save(); + + return $session; + } +} diff --git a/web/app/Helpers/Random.php b/web/app/Helpers/Random.php new file mode 100644 index 0000000..3955173 --- /dev/null +++ b/web/app/Helpers/Random.php @@ -0,0 +1,28 @@ +middleware('auth'); - } -} diff --git a/web/app/Http/Controllers/Auth/ForgotPasswordController.php b/web/app/Http/Controllers/Auth/ForgotPasswordController.php deleted file mode 100644 index 465c39c..0000000 --- a/web/app/Http/Controllers/Auth/ForgotPasswordController.php +++ /dev/null @@ -1,22 +0,0 @@ -middleware('guest')->except('logout'); - } -} diff --git a/web/app/Http/Controllers/Auth/RegisterController.php b/web/app/Http/Controllers/Auth/RegisterController.php deleted file mode 100644 index bb4546a..0000000 --- a/web/app/Http/Controllers/Auth/RegisterController.php +++ /dev/null @@ -1,105 +0,0 @@ - ['required', 'string', 'max:16', 'unique:users'], - 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], - 'password' => ['required', 'string', 'min:8', 'confirmed'], - ]); - } - - /** - * Create a new user instance after a valid registration. - * - * @param array $data - * @return \App\Models\User - */ - protected function create(Request $request) - { - - $data = Request::all(); - - if (Request::input('password') != Request::input('confirmation')) { - return Response()->json(['message'=>"Those passwords don't match!", 'badInputs'=>['password','confirmation']]); - } - - $valid = Validator::make($data, [ - 'username' => ['required', 'string', 'max:16', 'unique:users'], - 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], - 'password' => ['required', 'string', 'min:8'], - ]); - - if ($valid->stopOnFirstFailure()->fails()) { - $error = $valid->errors()->first(); - $messages = $valid->messages()->get('*'); - return Response()->json(['message'=>$error, 'badInputs'=>[array_keys($messages)]]); - } - - $prws = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 8)); - shuffle($prws); - $sc = substr(implode($prws), 0, 56); - - $user = new User; - $user->username = $data['username']; - $user->email = $data['email']; - $user->password = Hash::make($data['password']); - $user->token = $sc; - $user->save(); - - Request::session()->regenerate(); - - Auth::login($user); - - setcookie('gtok', $sc, time()+(345600*30), "/", $_POST['host']); - - return Response()->json(['message'=>'Success!', 'badInputs'=>[]]); - - } -} diff --git a/web/app/Http/Controllers/Auth/ResetPasswordController.php b/web/app/Http/Controllers/Auth/ResetPasswordController.php deleted file mode 100644 index b1726a3..0000000 --- a/web/app/Http/Controllers/Auth/ResetPasswordController.php +++ /dev/null @@ -1,30 +0,0 @@ -middleware('auth'); - $this->middleware('signed')->only('verify'); - $this->middleware('throttle:6,1')->only('verify', 'resend'); - } -} diff --git a/web/app/Http/Controllers/AuthController.php b/web/app/Http/Controllers/AuthController.php new file mode 100644 index 0000000..3c25b1a --- /dev/null +++ b/web/app/Http/Controllers/AuthController.php @@ -0,0 +1,121 @@ +all(); + + if ($request->input('password') != $request->input('confirmation')) + return Response()->json(['message'=>'The passwords you supplied don\'t match!', 'badInputs'=>['password','confirmation']]); + + $valid = Validator::make( + $data, + [ + 'username' => ['required', 'string', 'regex:/[a-zA-Z0-9._]+/', 'max:20'], + 'email' => ['required', 'string', 'email', 'max:255'], + 'password' => ['required', 'string', 'min:8'], + ] + ); + + if ($valid->stopOnFirstFailure()->fails()) { + $error = $valid->errors()->first(); + $messages = $valid->messages()->get('*'); + return Response()->json(['message'=>$error, 'badInputs'=>[array_keys($messages)]]); + } + + if(User::where('username', $data['username'])->first()) + return Response()->json(['message'=>'This user already exists.', 'badInputs'=>['username']]); + + if(User::where('email', $data['email'])->first()) + return Response()->json(['message'=>'This email is already in use!', 'badInputs'=>['email']]); + + $user = new User(); + $user->username = $data['username']; + $user->email = $data['email']; + $user->password = Hash::make($data['password']); + $user->about = 'I\'m new to Graphictoria!'; + $user->save(); + + $request->session()->regenerate(); + + $newSession = AuthHelper::GrantSession($request, $user->id); + $request->session()->put('authentication', $newSession->token); + + return Response()->json(['message'=>'Success!', 'badInputs'=>[]]); + } + + /** + * Logs the user in. + * + * @return Response + */ + public function Login(Request $request) { + if(AuthHelper::Guard($request)) + return Response(null, 400); + + /* */ + + $data = $request->all(); + + $valid = Validator::make( + $data, + [ + 'username' => ['required', 'string'], + 'password' => ['required', 'string'], + ] + ); + + if ($valid->stopOnFirstFailure()->fails()) { + $error = $valid->errors()->first(); + $messages = $valid->messages()->get('*'); + + return Response()->json(['message'=>$error, 'badInputs'=>[array_keys($messages)]]); + } + + /* */ + + $user = User::where('username', $request->input('username'))->first(); + if (!$user) + return Response()->json(['message'=>'That user doesn\'t exist.', 'badInputs'=>['username']]); + + if (!$user->password != Hash::make($data['password'])) + return Response()->json(['message'=>'The password you tried is incorrect.', 'badInputs'=>['password']]); + + $request->session()->regenerate(); + + $newSession = AuthHelper::GrantSession($request, $user->id); + $request->session()->put('authentication', $newSession); + + return Response()->json(['message'=>'Success!', 'badInputs'=>[]]); + } + + /** + * Logs the user out and kills the session. + * + * @return Response + */ + public function Logout(Request $request) { + $request->session()->invalidate(); + $request->session()->regenerateToken(); + return redirect('/'); + } +} diff --git a/web/app/Http/Controllers/Controller.php b/web/app/Http/Controllers/Controller.php index 0b881b8..ab5f720 100644 --- a/web/app/Http/Controllers/Controller.php +++ b/web/app/Http/Controllers/Controller.php @@ -28,44 +28,6 @@ class Controller extends BaseController { use AuthorizesRequests, DispatchesJobs, ValidatesRequests; - public function fetchUser() { - $POST; - - if (!isset($_POST['decision'])) {return Response()->json(false);} - - $decision = $_POST['decision']; - - switch($decision) { - case "metaUser": - if (!isset($_POST['token'])) {return Response()->json(false);} - $POST = $_POST['token']; - $user = User::where('token', $POST)->first(); - if (!$user) {return Response()->json(false);} - $array = $user->toArray(); - $staff = Staff::where('user_id', $user->id)->first(); - if ($staff) {$array['power'] = $staff->power_level;} - $array['bank'] = $user->bank; - $array['email'] = $user->email; - return Response()->json(["data"=>$array]); - break; - case "fetchedUser": - if (!isset($_POST['userId'])) {return Response()->json(false);} - $POST = $_POST['userId']; - $user = User::where('id', $POST)->first(); - if (!$user) {return Response()->json(false);} - $array = $user->toArray(); - $staff = Staff::where('user_id', $user->id)->first(); - if ($staff) {$array['power'] = $staff->power_level;} - return Response()->json(["data"=>$array]); - break; - default: - return Response()->json(false); - break; - } - - return Response()->json(["data"=>$array]); - } - public function fetchCategoriesFP() { if (!isset($_POST['token'])) {return Response()->json(["error"=>"No user."]);} @@ -153,66 +115,4 @@ class Controller extends BaseController return Response()->json(["post"=>$postA,"replies"=>$replies]); } - - - public function logout(Request $request) { - - $POST; - - if (!isset($_COOKIE['gtok'])) {return Redirect('/login');} - - $POST = $_COOKIE['gtok']; - - $user = User::where('token', $POST)->first(); - - if (!$user) {return Redirect('/login');} - - setcookie('gtok', null, time()+(345600*30), "/", $_SERVER['HTTP_HOST']); - - return Redirect('/'); - - } - - public function login(Request $request) { - - $data = Request::all(); - - $valid = Validator::make($data, [ - 'username' => ['required', 'string'], - 'password' => ['required', 'string'], - ]); - - if ($valid->stopOnFirstFailure()->fails()) { - $error = $valid->errors()->first(); - $messages = $valid->messages()->get('*'); - return Response()->json(['message'=>$error, 'badInputs'=>[array_keys($messages)]]); - } - - if (!User::where('username', Request::input('username'))->first()) { - return Response()->json(['message'=>"Sorry, that user wasn't found!", 'badInputs'=>['username']]); - } - - $user = User::where('username', Request::input('username'))->first(); - - if (!Auth::attempt(Request::only('username', 'password'))) { - return Response()->json(['message'=>'Sorry, thats the wrong password!', 'badInputs'=>['password']]); - } - - Request::session()->regenerate(); - - $prws = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 8)); - shuffle($prws); - $sc = substr(implode($prws), 0, 56); - - $user->token = $sc; - $user->save(); - - setcookie('gtok', $user->token, time()+(345600*30), "/", $_POST['host']); - - Auth::login($user); - - return Response()->json(['message'=>'Success!', 'badInputs'=>[]]); - - } - } diff --git a/web/app/Http/Controllers/UserController.php b/web/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..727fbd1 --- /dev/null +++ b/web/app/Http/Controllers/UserController.php @@ -0,0 +1,33 @@ +json([ + 'data' => [] + ]); + } else { + return Response()->json([ + 'error' => 'Unauthorized', + 'userFacingMessage' => 'You are not authorized to perform this request.' + ]); + } + + // Not sure how we'd get here, but just in case + return Response(null, 400); + } +} diff --git a/web/app/Http/Middleware/RedirectIfAuthenticated.php b/web/app/Http/Middleware/RedirectIfAuthenticated.php index 362b48b..e665aa3 100644 --- a/web/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/web/app/Http/Middleware/RedirectIfAuthenticated.php @@ -5,7 +5,8 @@ namespace App\Http\Middleware; use App\Providers\RouteServiceProvider; use Closure; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; + +use App\Helpers\AuthHelper; class RedirectIfAuthenticated { @@ -22,7 +23,7 @@ class RedirectIfAuthenticated $guards = empty($guards) ? [null] : $guards; foreach ($guards as $guard) { - if (Auth::guard($guard)->check()) { + if (AuthHelper::GetCurrentUser($request)) { return redirect(RouteServiceProvider::HOME); } } diff --git a/web/app/Models/Fbucket.php b/web/app/Models/Fbucket.php index 4ef77bf..b790e56 100644 --- a/web/app/Models/Fbucket.php +++ b/web/app/Models/Fbucket.php @@ -8,12 +8,12 @@ use Illuminate\Database\Eloquent\Model; /* FFlag bucket */ class Fbucket extends Model { + use HasFactory; + /** * The database connection that should be used by the migration. * * @var string */ protected $connection = 'mysql-fflag'; - - use HasFactory; } diff --git a/web/app/Models/User.php b/web/app/Models/User.php index f0257bd..8e4b210 100644 --- a/web/app/Models/User.php +++ b/web/app/Models/User.php @@ -2,58 +2,17 @@ namespace App\Models; -use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Foundation\Auth\User as Authenticatable; -use Illuminate\Notifications\Notifiable; -use Laravel\Sanctum\HasApiTokens; -use App\Models\Staff; +use Illuminate\Database\Eloquent\Model; -class User extends Authenticatable +class User extends Model { - use HasApiTokens, HasFactory, Notifiable; - - /** - * The attributes that are mass assignable. - * - * @var string[] - */ - protected $fillable = [ - 'name', - 'email', - 'password', - ]; - - /** - * The attributes that should be hidden for serialization. - * - * @var array - */ - protected $hidden = [ - 'password', - 'remember_token', - 'token', - 'email', - 'email_verified_at', - 'bank' - ]; - - /** - * The attributes that should be cast. - * - * @var array - */ - protected $casts = [ - 'email_verified_at' => 'datetime', - ]; - - public function Staff() { - $staff = Staff::where('user_id', $this->id)->first(); - return $staff; - } - - public function inventory() { - return $this->morphMany('App\Models\Inventory', 'owner'); - } - + use HasFactory; + + /** + * The database connection that should be used by the migration. + * + * @var string + */ + protected $connection = 'mysql-membership'; } diff --git a/web/app/Models/User/UserSession.php b/web/app/Models/User/UserSession.php new file mode 100644 index 0000000..105de3d --- /dev/null +++ b/web/app/Models/User/UserSession.php @@ -0,0 +1,18 @@ + env('MYSQL_ATTR_SSL_CA'), ]) : [], ], + + 'mysql-membership' => [ + 'driver' => 'mysql', + 'url' => env('DATABASE_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_MEMBERSHIP_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + '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', diff --git a/web/database/migrations/2021_12_16_011849_create_users_table.php b/web/database/migrations/2021_12_16_011849_create_users_table.php index 3dd6eb8..ac4985a 100644 --- a/web/database/migrations/2021_12_16_011849_create_users_table.php +++ b/web/database/migrations/2021_12_16_011849_create_users_table.php @@ -6,6 +6,13 @@ use Illuminate\Support\Facades\Schema; class CreateUsersTable extends Migration { + /** + * The database connection that should be used by the migration. + * + * @var string + */ + protected $connection = 'mysql-membership'; + /** * Run the migrations. * @@ -17,11 +24,10 @@ class CreateUsersTable extends Migration $table->id(); $table->string('username'); $table->string('email'); - $table->timestamp('email_verified_at')->default(null); + $table->timestamp('email_verified_at')->nullable(); $table->string('password'); - $table->string('token'); - $table->integer('bank')->default(150); - $table->string('about')->default(null); + $table->integer('bank')->default(15); + $table->string('about')->nullable(); $table->timestamps(); }); } diff --git a/web/database/migrations/2022_03_26_040843_create_user_sessions_table.php b/web/database/migrations/2022_03_26_040843_create_user_sessions_table.php new file mode 100644 index 0000000..6f5115b --- /dev/null +++ b/web/database/migrations/2022_03_26_040843_create_user_sessions_table.php @@ -0,0 +1,42 @@ +id(); + $table->unsignedBigInteger('user'); + $table->string('token'); + $table->ipAddress('ip'); + $table->timestamp('last_seen'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_sessions'); + } +} diff --git a/web/resources/js/layouts/Card.js b/web/resources/js/components/Card.js similarity index 56% rename from web/resources/js/layouts/Card.js rename to web/resources/js/components/Card.js index 5219e83..016f644 100644 --- a/web/resources/js/layouts/Card.js +++ b/web/resources/js/components/Card.js @@ -3,6 +3,7 @@ import React from 'react'; +/* regular card */ export const Card = (props) => { return (
@@ -23,3 +24,23 @@ export const CardTitle = (props) => { ); }; + +/* mini card */ +export const MiniCardTitle = (props) => { + return ( + <> +
{ props.children }
+
+ + ); +}; + +export const MiniCard = (props) => { + return ( +
+
+ { props.children } +
+
+ ); +}; diff --git a/web/resources/js/components/Navbar.js b/web/resources/js/components/Navbar.js index aba49c0..464b5f5 100644 --- a/web/resources/js/components/Navbar.js +++ b/web/resources/js/components/Navbar.js @@ -9,7 +9,7 @@ const Navbar = (props) => { return ( <>