Merge pull request #3 from biondizzle/codex/add-login-to-console-management-page

Add console login with env credentials
This commit is contained in:
biondizzle
2025-06-05 09:56:38 -04:00
committed by GitHub
5 changed files with 121 additions and 1 deletions

4
.env
View File

@@ -29,3 +29,7 @@ APP_SECRET=6aa2ea989e29de27bc42a77db9849b87
# DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" # DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8"
DATABASE_URL="mysql://vultradmin:AVNS_jn444_0nHCHAvnZkTFN@vultr-prod-a6de266e-e9c6-477c-abf3-7ec2e7a7bfc8-vultr-prod-3195.vultrdb.com:18140/defaultdb?serverVersion=8.0.32&charset=utf8mb4" DATABASE_URL="mysql://vultradmin:AVNS_jn444_0nHCHAvnZkTFN@vultr-prod-a6de266e-e9c6-477c-abf3-7ec2e7a7bfc8-vultr-prod-3195.vultrdb.com:18140/defaultdb?serverVersion=8.0.32&charset=utf8mb4"
###< doctrine/doctrine-bundle ### ###< doctrine/doctrine-bundle ###
# Console login credentials
CONSOLE_USER=admin
CONSOLE_PASS=changeMe

View File

@@ -55,6 +55,17 @@ console_api_stats:
controller: App\Controller\ConsoleApiController::stats controller: App\Controller\ConsoleApiController::stats
methods: [GET] methods: [GET]
# Console Authentication Routes
console_login:
path: /console/login
controller: App\Controller\ConsoleController::login
methods: [GET, POST]
console_logout:
path: /console/logout
controller: App\Controller\ConsoleController::logout
methods: [GET]
# Console Frontend Route # Console Frontend Route
console_frontend: console_frontend:
path: /console/{route} path: /console/{route}

View File

@@ -19,9 +19,20 @@ class ConsoleApiController extends AbstractController
private EntityManagerInterface $entityManager private EntityManagerInterface $entityManager
) {} ) {}
private function checkAuth(Request $request): ?JsonResponse
{
if (!$request->getSession()->get('console_logged_in')) {
return new JsonResponse(['error' => 'Unauthorized'], Response::HTTP_UNAUTHORIZED);
}
return null;
}
// Credentials Management // Credentials Management
public function credentials(Request $request): JsonResponse public function credentials(Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
if ($request->getMethod() === 'GET') { if ($request->getMethod() === 'GET') {
$credentials = $this->entityManager->getRepository(S3Credential::class)->findAll(); $credentials = $this->entityManager->getRepository(S3Credential::class)->findAll();
@@ -63,6 +74,9 @@ class ConsoleApiController extends AbstractController
public function credentialDetail(int $id, Request $request): JsonResponse public function credentialDetail(int $id, Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
$credential = $this->entityManager->getRepository(S3Credential::class)->find($id); $credential = $this->entityManager->getRepository(S3Credential::class)->find($id);
if (!$credential) { if (!$credential) {
@@ -115,6 +129,9 @@ class ConsoleApiController extends AbstractController
// Buckets Management // Buckets Management
public function buckets(Request $request): JsonResponse public function buckets(Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
if ($request->getMethod() === 'GET') { if ($request->getMethod() === 'GET') {
$buckets = $this->entityManager->getRepository(S3Bucket::class)->findAll(); $buckets = $this->entityManager->getRepository(S3Bucket::class)->findAll();
@@ -177,6 +194,9 @@ class ConsoleApiController extends AbstractController
public function bucketDetail(string $name, Request $request): JsonResponse public function bucketDetail(string $name, Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
$bucket = $this->s3Service->findBucketByName($name); $bucket = $this->s3Service->findBucketByName($name);
if (!$bucket) { if (!$bucket) {
@@ -224,6 +244,9 @@ class ConsoleApiController extends AbstractController
// Objects Management // Objects Management
public function objects(string $bucketName, Request $request): JsonResponse public function objects(string $bucketName, Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
$bucket = $this->s3Service->findBucketByName($bucketName); $bucket = $this->s3Service->findBucketByName($bucketName);
if (!$bucket) { if (!$bucket) {
@@ -270,6 +293,9 @@ class ConsoleApiController extends AbstractController
public function objectDetail(string $bucketName, string $objectKey, Request $request): JsonResponse public function objectDetail(string $bucketName, string $objectKey, Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
$bucket = $this->s3Service->findBucketByName($bucketName); $bucket = $this->s3Service->findBucketByName($bucketName);
if (!$bucket) { if (!$bucket) {
@@ -309,6 +335,9 @@ class ConsoleApiController extends AbstractController
// Multipart Uploads // Multipart Uploads
public function multipartUploads(string $bucketName, Request $request): JsonResponse public function multipartUploads(string $bucketName, Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
$bucket = $this->s3Service->findBucketByName($bucketName); $bucket = $this->s3Service->findBucketByName($bucketName);
if (!$bucket) { if (!$bucket) {
@@ -339,6 +368,9 @@ class ConsoleApiController extends AbstractController
// Presigned URLs // Presigned URLs
public function presignedUrls(Request $request): JsonResponse public function presignedUrls(Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
if ($request->getMethod() === 'GET') { if ($request->getMethod() === 'GET') {
$urls = $this->entityManager->getRepository(\App\Entity\S3PresignedUrl::class) $urls = $this->entityManager->getRepository(\App\Entity\S3PresignedUrl::class)
->createQueryBuilder('p') ->createQueryBuilder('p')
@@ -392,6 +424,9 @@ class ConsoleApiController extends AbstractController
// Statistics // Statistics
public function stats(Request $request): JsonResponse public function stats(Request $request): JsonResponse
{ {
if ($resp = $this->checkAuth($request)) {
return $resp;
}
$credentialCount = $this->entityManager->getRepository(S3Credential::class)->count([]); $credentialCount = $this->entityManager->getRepository(S3Credential::class)->count([]);
$bucketCount = $this->entityManager->getRepository(S3Bucket::class)->count([]); $bucketCount = $this->entityManager->getRepository(S3Bucket::class)->count([]);
$objectCount = $this->entityManager->getRepository(S3Object::class)->count([]); $objectCount = $this->entityManager->getRepository(S3Object::class)->count([]);

View File

@@ -4,11 +4,47 @@ namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
class ConsoleController extends AbstractController class ConsoleController extends AbstractController
{ {
public function index(string $route = ''): Response public function index(Request $request, string $route = ''): Response
{ {
if (!$request->getSession()->get('console_logged_in')) {
return new RedirectResponse('/console/login');
}
return $this->render('console/index.html.twig'); return $this->render('console/index.html.twig');
} }
public function login(Request $request): Response
{
if ($request->getSession()->get('console_logged_in')) {
return new RedirectResponse('/console');
}
$error = null;
if ($request->isMethod('POST')) {
$user = $request->request->get('username');
$pass = $request->request->get('password');
$envUser = $_ENV['CONSOLE_USER'] ?? 'admin';
$envPass = $_ENV['CONSOLE_PASS'] ?? 'password';
if ($user === $envUser && $pass === $envPass) {
$request->getSession()->set('console_logged_in', true);
return new RedirectResponse('/console');
}
$error = 'Invalid credentials';
}
return $this->render('console/login.html.twig', ['error' => $error]);
}
public function logout(Request $request): Response
{
$request->getSession()->remove('console_logged_in');
return new RedirectResponse('/console/login');
}
} }

View File

@@ -0,0 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>vStash Console Login</title>
<style>
body { font-family: Arial, sans-serif; background: #f7fafc; display:flex; align-items:center; justify-content:center; height:100vh; }
.login-box { background:white; padding:2rem; border-radius:0.5rem; box-shadow:0 1px 3px rgba(0,0,0,0.1); width:300px; }
.form-group { margin-bottom:1rem; }
label { display:block; margin-bottom:0.5rem; }
input { width:100%; padding:0.5rem; border:1px solid #d2d6dc; border-radius:0.375rem; }
button { width:100%; padding:0.5rem; background:#3182ce; color:white; border:none; border-radius:0.375rem; cursor:pointer; }
.error { color:#c53030; margin-bottom:1rem; text-align:center; }
</style>
</head>
<body>
<div class="login-box">
<h2 style="text-align:center;margin-bottom:1rem;">Console Login</h2>
{% if error %}<div class="error">{{ error }}</div>{% endif %}
<form method="post">
<div class="form-group">
<label>Username</label>
<input type="text" name="username" required>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" name="password" required>
</div>
<button type="submit">Login</button>
</form>
</div>
</body>
</html>