feat: site admin (#8)

This commit is contained in:
floppydiskette 2023-07-16 21:02:51 +01:00 committed by GitHub
parent 691d0d933d
commit 7c16dc53b5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 1378 additions and 52 deletions

1
.gitignore vendored
View file

@ -17,3 +17,4 @@ yarn-error.log
/.fleet /.fleet
/.idea /.idea
/.vscode /.vscode
.auth0.*.json

View file

@ -6,6 +6,7 @@
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^8.1", "php": "^8.1",
"auth0/login": "^7.8",
"guzzlehttp/guzzle": "^7.2", "guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^10.10", "laravel/framework": "^10.10",
"laravel/sanctum": "^3.2", "laravel/sanctum": "^3.2",

1171
composer.lock generated

File diff suppressed because it is too large Load diff

56
config/auth0.php Normal file
View file

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
use Auth0\Laravel\Configuration;
use Auth0\SDK\Configuration\SdkConfiguration;
return Configuration::VERSION_2 + [
'registerGuards' => true,
'registerMiddleware' => true,
'registerAuthenticationRoutes' => true,
'configurationPath' => null,
'guards' => [
'default' => [
Configuration::CONFIG_STRATEGY => Configuration::get(Configuration::CONFIG_STRATEGY, SdkConfiguration::STRATEGY_NONE),
Configuration::CONFIG_DOMAIN => Configuration::get(Configuration::CONFIG_DOMAIN),
Configuration::CONFIG_CUSTOM_DOMAIN => Configuration::get(Configuration::CONFIG_CUSTOM_DOMAIN),
Configuration::CONFIG_CLIENT_ID => Configuration::get(Configuration::CONFIG_CLIENT_ID),
Configuration::CONFIG_CLIENT_SECRET => Configuration::get(Configuration::CONFIG_CLIENT_SECRET),
Configuration::CONFIG_AUDIENCE => Configuration::get(Configuration::CONFIG_AUDIENCE),
Configuration::CONFIG_ORGANIZATION => Configuration::get(Configuration::CONFIG_ORGANIZATION),
Configuration::CONFIG_USE_PKCE => Configuration::get(Configuration::CONFIG_USE_PKCE),
Configuration::CONFIG_SCOPE => Configuration::get(Configuration::CONFIG_SCOPE),
Configuration::CONFIG_RESPONSE_MODE => Configuration::get(Configuration::CONFIG_RESPONSE_MODE),
Configuration::CONFIG_RESPONSE_TYPE => Configuration::get(Configuration::CONFIG_RESPONSE_TYPE),
Configuration::CONFIG_TOKEN_ALGORITHM => Configuration::get(Configuration::CONFIG_TOKEN_ALGORITHM),
Configuration::CONFIG_TOKEN_JWKS_URI => Configuration::get(Configuration::CONFIG_TOKEN_JWKS_URI),
Configuration::CONFIG_TOKEN_MAX_AGE => Configuration::get(Configuration::CONFIG_TOKEN_MAX_AGE),
Configuration::CONFIG_TOKEN_LEEWAY => Configuration::get(Configuration::CONFIG_TOKEN_LEEWAY),
Configuration::CONFIG_TOKEN_CACHE => Configuration::get(Configuration::CONFIG_TOKEN_CACHE),
Configuration::CONFIG_TOKEN_CACHE_TTL => Configuration::get(Configuration::CONFIG_TOKEN_CACHE_TTL),
Configuration::CONFIG_HTTP_MAX_RETRIES => Configuration::get(Configuration::CONFIG_HTTP_MAX_RETRIES),
Configuration::CONFIG_HTTP_TELEMETRY => Configuration::get(Configuration::CONFIG_HTTP_TELEMETRY),
Configuration::CONFIG_MANAGEMENT_TOKEN => Configuration::get(Configuration::CONFIG_MANAGEMENT_TOKEN),
Configuration::CONFIG_MANAGEMENT_TOKEN_CACHE => Configuration::get(Configuration::CONFIG_MANAGEMENT_TOKEN_CACHE),
Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY),
Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM),
Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST => Configuration::get(Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST),
],
'api' => [
Configuration::CONFIG_STRATEGY => SdkConfiguration::STRATEGY_API,
],
'web' => [
Configuration::CONFIG_STRATEGY => SdkConfiguration::STRATEGY_REGULAR,
Configuration::CONFIG_COOKIE_SECRET => Configuration::get(Configuration::CONFIG_COOKIE_SECRET, env('APP_KEY')),
Configuration::CONFIG_REDIRECT_URI => Configuration::get(Configuration::CONFIG_REDIRECT_URI, env('APP_URL') . '/callback'),
Configuration::CONFIG_SESSION_STORAGE => Configuration::get(Configuration::CONFIG_SESSION_STORAGE),
Configuration::CONFIG_SESSION_STORAGE_ID => Configuration::get(Configuration::CONFIG_SESSION_STORAGE_ID),
Configuration::CONFIG_TRANSIENT_STORAGE => Configuration::get(Configuration::CONFIG_TRANSIENT_STORAGE),
Configuration::CONFIG_TRANSIENT_STORAGE_ID => Configuration::get(Configuration::CONFIG_TRANSIENT_STORAGE_ID),
],
],
];

View file

@ -350,3 +350,29 @@ table.gb_entry tr td {
table.gb_entry { table.gb_entry {
margin-bottom: 5px; margin-bottom: 5px;
} }
table.gb_admin {
margin-bottom: 5px;
width: 500px;
border: #FFFFFF solid;
}
table.gb_admin tr td {
border-right: none;
border-bottom: none;
vertical-align: top;
padding: 5px;
}
table.gb_admin tr td.gb_del {
border-left: none;
vertical-align: top;
padding: 5px;
width: 32px;
}
table.gb_admin tr td.gb_message {
border-top: none;
vertical-align: top;
padding: 5px;
}

View file

@ -9,3 +9,7 @@ body {
color: #ddd; color: #ddd;
background-color: #333; background-color: #333;
} }
table.gb_entry_details tr td {
padding-right: 5px;
}

View file

@ -0,0 +1,9 @@
@extends('layouts.minimal')
@section('title', 'Error 401: Unauthorized User!')
@section('content')
<h1>{{ $error }}</h1>
<hr/>
@if(isset($description))
<p>{{ $description }}</p>
@endif
@stop

View file

@ -0,0 +1,8 @@
@extends('layouts.minimal')
@section('title', 'Error 401: Unauthorized User!')
@section('content')
<h1>Error 401: Unauthorized User!</h1>
<hr/>
<p>Woah there! Only authorized users can access this page. Please <a href="/login">log in</a> to proceed.</p>
<p>Ended up here on accident? Click <a href="/">here</a> to return to the homepage</u>!</p>
@stop

View file

@ -0,0 +1,12 @@
<nav>
<div>
<a href="/">public home</a> |
<a href="/admin">admin home</a> |
<a href="/admin/guestbook">guestbook</a>
@if (auth()->check())
| ({{ auth()->user()->name }}) <a href="/logout">logout</a>
@else
| <a href="/login">login</a>
@endif
</div>
</nav>

View file

@ -8,5 +8,11 @@
<a href="/computers/">computers</a> | <a href="/computers/">computers</a> |
<a href="/bookmarks/">bookmarks</a> | <a href="/bookmarks/">bookmarks</a> |
<a href="/guestbook/">guestbook</a> <a href="/guestbook/">guestbook</a>
@if (auth()->check())
| <a href="/admin/">admin</a>
| ({{ auth()->user()->name }}) <a href="/logout">logout</a>
@else
| <a href="/login">login</a>
@endif
</div> </div>
</nav> </nav>

View file

@ -0,0 +1,23 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
@include('includes.head')
</head>
<body>
<div class="page">
<div class="header">
@include('includes.admin.header')
</div> <!-- header -->
<div id="pagebody">
<div id="content">
@yield('content')
</div> <!-- content -->
<div id="footer" class="pagefooter">
@include('includes.footer')
</div> <!-- footer -->
</div> <!-- pagebody -->
</div> <!-- page -->
</body>
</html>

View file

@ -0,0 +1,33 @@
@extends('layouts.minimal')
@section('title', 'Delete confirm')
@section('content')
<h1>Delete Confirmation</h1>
<hr/>
<p>Are you sure you want to delete this entry?</p>
<h3>Entry Details:</h3>
<table class="gb_entry_details">
<tr>
<td><b>ID:</b></td>
<td>{{ $entry->id }}</td>
</tr>
<tr>
<td><b>Name:</b></td>
<td>{{ $entry->name }}</td>
</tr>
<tr>
<td><b>Date:</b></td>
<td>{{ gmdate("H:i:s - Y-m-d", $entry->timestamp) }}</td>
</tr>
<tr>
<td><b>Message:</b></td>
<td>{{ $entry->message }}</td>
</tr>
</table>
<form action="/admin/guestbook/delete" method="POST">
@csrf
<input type="hidden" name="id" value="{{ $entry->id }}">
<button type="submit">Confirm Delete</button>
</form>
@stop

View file

@ -0,0 +1,27 @@
@extends('layouts.default-admin')
@section('title', 'guestbook')
@section('content')
@php
$entries = DB::select('SELECT id, name, timestamp, message FROM guestbook_entries ORDER BY id DESC');
@endphp
<h1>Entries <small>({{ count($entries) }} total)</small></h1>
@foreach ($entries as $entry)
<table class="gb_admin">
<tr>
<td>
Name:&nbsp;{{ $entry->name }}<br/>
Date:&nbsp;{{ gmdate("H:i:s - Y-m-d", $entry->timestamp) }}
</td>
<td class="gb_del">
<a href="/admin/guestbook/delete?id={{ $entry->id }}">del</a>
</td>
</tr>
<tr>
<td colspan="2" class="gb_message">
<br/>
{{ htmlspecialchars($entry->message) }}
</td>
</tr></table>
@endforeach
@stop

View file

@ -0,0 +1,9 @@
@extends('layouts.default-admin')
@section('title', 'Page Title')
@section('description', 'Page description goes here')
@php
$user = auth()->user();
@endphp
@section('content')
<p>You are logged in as {{ $user->name }} ({{ $user->email }})</p>
@stop

View file

@ -40,4 +40,46 @@
->name('guestbookPost') ->name('guestbookPost')
->middleware('rate_limit'); ->middleware('rate_limit');
Route::get('/admin', function () {
if (!auth()->check()) {
return view('errors.no-auth');
}
return view('pages.admin.index');
});
Route::get('/admin/guestbook', function () {
if (!auth()->check()) {
return view('errors.no-auth');
}
return view('pages.admin.guestbook');
});
Route::get('/admin/guestbook/delete', function () {
if (!auth()->check()) {
return view('errors.no-auth');
}
$id = request()->input('id');
$entry = DB::table('guestbook_entries')->find($id);
if ($entry) {
// Render a confirmation view
return View::make('pages.admin.guestbook-del-confirm', compact('entry'));
} else {
return view('errors.generic-error')
->with('error', "Entry not found")
->with('description', "The specified entry does not exist!");
}
});
Route::post('/admin/guestbook/delete', function () {
if (!auth()->check()) {
return view('errors.no-auth');
}
$id = request()->input('id');
DB::table('guestbook_entries')->where('id', $id)->delete();
return back()->with('success', 'Entry deleted successfully!');
});