0001
This commit is contained in:
parent
a096f91b5c
commit
b5c30c0773
@ -1,29 +0,0 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const loginForm = document.getElementById('loginForm');
|
||||
|
||||
if (loginForm) {
|
||||
loginForm.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
const email = document.getElementById('email').value;
|
||||
const password = document.getElementById('password').value;
|
||||
|
||||
// Basic client-side validation
|
||||
if (!email || !password) {
|
||||
alert('Please enter both email and password.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Simple email format check
|
||||
const emailRegex = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
alert('Please enter a valid email address.');
|
||||
return;
|
||||
}
|
||||
|
||||
// On success, simulate login
|
||||
console.log('Login validation passed. Redirecting...');
|
||||
window.location.href = 'dashboard.php';
|
||||
});
|
||||
}
|
||||
});
|
||||
143
dashboard.php
143
dashboard.php
@ -1,21 +1,146 @@
|
||||
|
||||
<?php
|
||||
// A simple placeholder for the dashboard page after successful login.
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// If user is not logged in, redirect to login page
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$displayName = $_SESSION['user_display_name'] ?? 'User';
|
||||
$pdo = db();
|
||||
|
||||
$viewingClient = null;
|
||||
$clients = [];
|
||||
|
||||
if (isset($_GET['client_id'])) {
|
||||
$stmt = $pdo->prepare("SELECT * FROM clients WHERE client_id = ?");
|
||||
$stmt->execute([$_GET['client_id']]);
|
||||
$viewingClient = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
// TODO: Fetch credentials and notes for the client
|
||||
} else {
|
||||
$stmt = $pdo->query("SELECT * FROM clients ORDER BY name ASC");
|
||||
$clients = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Dashboard - FlexPass</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container text-center mt-5">
|
||||
<h1>Welcome to FlexPass</h1>
|
||||
<p class="lead">You have successfully logged in.</p>
|
||||
<a href="index.php" class="btn btn-secondary mt-3">Logout</a>
|
||||
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="dashboard.php">
|
||||
<i class="bi bi-shield-lock"></i> FlexPass
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="dashboard.php">Clients</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="d-flex">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="bi bi-person-circle"></i> <?php echo htmlspecialchars($displayName); ?>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="logout.php">Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<?php if ($viewingClient): ?>
|
||||
<!-- Client Detail View -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<a href="dashboard.php" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> Back to Client List</a>
|
||||
<button class="btn btn-sm btn-primary"><i class="bi bi-plus-circle"></i> Add Credential</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="mb-0">
|
||||
<?php echo htmlspecialchars($viewingClient['name']); ?>
|
||||
<span class="badge bg-secondary ms-2"><?php echo htmlspecialchars($viewingClient['client_id']); ?></span>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Status:</strong> <span class="badge bg-<?php echo $viewingClient['status'] === 'active' ? 'success' : 'danger'; ?>"><?php echo htmlspecialchars($viewingClient['status']); ?></span></p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h4>Credentials</h4>
|
||||
<p class="text-muted">Credentials management coming soon.</p>
|
||||
<!-- Placeholder for credentials list -->
|
||||
|
||||
<hr>
|
||||
|
||||
<h4>Notes</h4>
|
||||
<p class="text-muted">Notes timeline coming soon.</p>
|
||||
<!-- Placeholder for notes timeline -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
<!-- Client List View -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h1 class="mb-0">Clients</h1>
|
||||
<button class="btn btn-primary"><i class="bi bi-plus-circle"></i> Add New Client</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Client ID</th>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($clients as $client): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($client['client_id']); ?></td>
|
||||
<td><?php echo htmlspecialchars($client['name']); ?></td>
|
||||
<td><span class="badge bg-<?php echo $client['status'] === 'active' ? 'success' : 'danger'; ?>"><?php echo htmlspecialchars($client['status']); ?></span></td>
|
||||
<td>
|
||||
<a href="?client_id=<?php echo htmlspecialchars($client['client_id']); ?>" class="btn btn-sm btn-outline-primary">View</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php if (empty($clients)): ?>
|
||||
<tr>
|
||||
<td colspan="4" class="text-center text-muted">No clients found.</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
33
db/migrate.php
Normal file
33
db/migrate.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
function run_migrations() {
|
||||
$pdo = db();
|
||||
$migrationsDir = __DIR__ . '/migrations';
|
||||
$files = glob($migrationsDir . '/*.sql');
|
||||
sort($files);
|
||||
|
||||
foreach ($files as $file) {
|
||||
echo "Running migration: " . basename($file) . "...\n";
|
||||
$sql = file_get_contents($file);
|
||||
if ($sql === false) {
|
||||
echo "Error: Could not read file " . basename($file) . ".\n";
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$pdo->exec($sql);
|
||||
echo "Success.\n";
|
||||
} catch (PDOException $e) {
|
||||
echo "Error executing migration " . basename($file) . ": " . $e->getMessage() . "\n";
|
||||
// Exit on first error
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (php_sapi_name() === 'cli') {
|
||||
run_migrations();
|
||||
}
|
||||
|
||||
?>
|
||||
69
db/migrations/001_initial_schema.sql
Normal file
69
db/migrations/001_initial_schema.sql
Normal file
@ -0,0 +1,69 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
`id` char(36) NOT NULL DEFAULT (uuid()),
|
||||
`email` varchar(255) NOT NULL,
|
||||
`display_name` varchar(255) DEFAULT NULL,
|
||||
`role` enum('Admin','TechTeam') NOT NULL,
|
||||
`status` enum('active','disabled') NOT NULL DEFAULT 'active',
|
||||
`password_enc` varchar(255) NOT NULL,
|
||||
`mfa_enabled` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`last_login_at` datetime DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `email` (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `clients` (
|
||||
`client_id` varchar(4) NOT NULL,
|
||||
`name` varchar(255) DEFAULT NULL,
|
||||
`status` enum('active','inactive') NOT NULL DEFAULT 'active',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`client_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `credentials` (
|
||||
`id` char(36) NOT NULL DEFAULT (uuid()),
|
||||
`client_id` varchar(4) NOT NULL,
|
||||
`system_name` varchar(255) NOT NULL,
|
||||
`username` varchar(255) NOT NULL,
|
||||
`password_enc` text NOT NULL,
|
||||
`additional_fields` json DEFAULT NULL,
|
||||
`tags` json DEFAULT NULL,
|
||||
`rotation_due_at` datetime DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `client_id` (`client_id`),
|
||||
CONSTRAINT `credentials_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`client_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `notes` (
|
||||
`id` char(36) NOT NULL DEFAULT (uuid()),
|
||||
`client_id` varchar(4) NOT NULL,
|
||||
`user_id` char(36) NOT NULL,
|
||||
`text` text NOT NULL,
|
||||
`pinned` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `client_id` (`client_id`),
|
||||
KEY `user_id` (`user_id`),
|
||||
CONSTRAINT `notes_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`client_id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `notes_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `audit_events` (
|
||||
`id` char(36) NOT NULL DEFAULT (uuid()),
|
||||
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`actor_user_id` char(36) DEFAULT NULL,
|
||||
`action` varchar(255) NOT NULL,
|
||||
`entity_type` varchar(255) DEFAULT NULL,
|
||||
`entity_id` varchar(255) DEFAULT NULL,
|
||||
`client_id` varchar(4) DEFAULT NULL,
|
||||
`metadata` json DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `actor_user_id` (`actor_user_id`),
|
||||
KEY `client_id_idx` (`client_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
59
db/seed.php
Normal file
59
db/seed.php
Normal file
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
function seed_database() {
|
||||
$pdo = db();
|
||||
|
||||
// Seed admin user
|
||||
$email = 'admin@flexpass.local';
|
||||
$password = 'password';
|
||||
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
try {
|
||||
// Check if user already exists
|
||||
$stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
|
||||
$stmt->execute([$email]);
|
||||
if ($stmt->fetch()) {
|
||||
echo "Admin user already exists.\n";
|
||||
} else {
|
||||
$stmt = $pdo->prepare("INSERT INTO users (email, password_enc, role, display_name) VALUES (?, ?, 'Admin', 'Admin User')");
|
||||
$stmt->execute([$email, $hashedPassword]);
|
||||
echo "Admin user created successfully.\n";
|
||||
echo "Email: " . $email . "\n";
|
||||
echo "Password: " . $password . "\n";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo "Error seeding database: " . $e->getMessage() . "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Seed clients
|
||||
try {
|
||||
$stmt = $pdo->query("SELECT count(*) FROM clients");
|
||||
if ($stmt->fetchColumn() > 0) {
|
||||
echo "Clients table already seeded.\n";
|
||||
} else {
|
||||
$clients = [
|
||||
['1001', 'Stark Industries', 'active'],
|
||||
['1002', 'Wayne Enterprises', 'active'],
|
||||
['1003', 'Cyberdyne Systems', 'inactive'],
|
||||
];
|
||||
$stmt = $pdo->prepare("INSERT INTO clients (client_id, name, status) VALUES (?, ?, ?)");
|
||||
foreach ($clients as $client) {
|
||||
$stmt->execute($client);
|
||||
}
|
||||
echo "Seeded " . count($clients) . " clients.\n";
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo "Error seeding clients: " . $e->getMessage() . "\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (php_sapi_name() === 'cli') {
|
||||
seed_database();
|
||||
}
|
||||
?>
|
||||
66
index.php
66
index.php
@ -1,3 +1,57 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// If user is already logged in, redirect to dashboard
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error_message = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$email = $_POST['email'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
if (empty($email) || empty($password)) {
|
||||
$error_message = 'Please enter both email and password.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = ?");
|
||||
$stmt->execute([$email]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password_enc'])) {
|
||||
if ($user['status'] === 'active') {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['user_email'] = $user['email'];
|
||||
$_SESSION['user_role'] = $user['role'];
|
||||
$_SESSION['user_display_name'] = $user['display_name'];
|
||||
|
||||
// Regenerate session ID to prevent session fixation
|
||||
session_regenerate_id(true);
|
||||
|
||||
// Update last login timestamp
|
||||
$updateStmt = $pdo->prepare("UPDATE users SET last_login_at = CURRENT_TIMESTAMP WHERE id = ?");
|
||||
$updateStmt->execute([$user['id']]);
|
||||
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
} else {
|
||||
$error_message = 'Your account is disabled. Please contact an administrator.';
|
||||
}
|
||||
} else {
|
||||
$error_message = 'Invalid email or password.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// In a real app, you would log this error.
|
||||
$error_message = 'A database error occurred. Please try again later.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@ -30,14 +84,20 @@
|
||||
<h1>FlexPass</h1>
|
||||
<p class="tagline">HIPAA-Ready Credential Vault</p>
|
||||
|
||||
<form id="loginForm" novalidate>
|
||||
<?php if (!empty($error_message)): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo htmlspecialchars($error_message); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form id="loginForm" method="POST">
|
||||
<div class="mb-3 text-start">
|
||||
<label for="email" class="form-label">Email Address</label>
|
||||
<input type="email" class="form-control" id="email" required>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="mb-4 text-start">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" required>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100">Sign In</button>
|
||||
</form>
|
||||
|
||||
23
logout.php
Normal file
23
logout.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Unset all of the session variables
|
||||
$_SESSION = [];
|
||||
|
||||
// If it's desired to kill the session, also delete the session cookie.
|
||||
// Note: This will destroy the session, and not just the session data!
|
||||
if (ini_get("session.use_cookies")) {
|
||||
$params = session_get_cookie_params();
|
||||
setcookie(session_name(), '', time() - 42000,
|
||||
$params["path"], $params["domain"],
|
||||
$params["secure"], $params["httponly"]
|
||||
);
|
||||
}
|
||||
|
||||
// Finally, destroy the session.
|
||||
session_destroy();
|
||||
|
||||
// Redirect to login page
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
?>
|
||||
Loading…
x
Reference in New Issue
Block a user