<?php
/**
* PassGram v3.0 - Main Application Entry Point
*/
// Check if install.php exists and hasn't been run
if (file_exists(__DIR__ . '/setup.php') && !file_exists(__DIR__ . '/data/users.json.enc')) {
header('Location: /setup.php');
exit;
}
// Load autoloader and dependencies
require_once __DIR__ . '/autoload.php';
use PassGram\Core\Config;
use PassGram\Core\Session;
use PassGram\Security\Auth;
use PassGram\Security\CSRF;
use PassGram\Security\Encryption;
use PassGram\Core\Database;
use PassGram\Helpers\Logger;
use PassGram\Helpers\Validator;
// Start session
Session::start();
// Initialize application components
$config = Config::getInstance(__DIR__ . '/config');
$masterKey = hex2bin($config->get('security.master_application_key'));
$encryption = new Encryption($masterKey, $config->get('security.encryption'));
$db = new Database($encryption, $config->database());
$logger = new Logger($config->get('database.activity_log'));
$validator = new Validator($config);
$auth = new Auth($db, $config, $logger);
// Require authentication for all pages except login/register
$publicPages = ['login', 'register', 'keys', 'public-share', 'reset-password'];
$page = $_GET['page'] ?? 'dashboard';
if (!$auth->check() && !in_array($page, $publicPages)) {
header('Location: /login.php');
exit;
}
// ------------------------------------------------------------------
// PGP context injection
// If the authenticated user has PGP encryption mode enabled AND their
// passphrase is stored in the session, configure $db to use PGP for
// their per-user credential and public-key files.
// ------------------------------------------------------------------
if ($auth->check()) {
$pgpPassphrase = Session::get('pgp_passphrase', '');
if ($pgpPassphrase !== '') {
$currentUser = $auth->getCurrentUser();
if ($currentUser && ($currentUser['settings']['pgp_encryption_mode'] ?? false)) {
$pgpDir = $config->get('app.paths.pgp');
if ($pgpDir) {
$pubKeyFile = $pgpDir . '/' . $currentUser['id'] . '_public.key';
$privKeyFile = $pgpDir . '/' . $currentUser['id'] . '_private.key.enc';
if (file_exists($pubKeyFile) && file_exists($privKeyFile)) {
$db->setPGPContext(
file_get_contents($pubKeyFile),
file_get_contents($privKeyFile),
$pgpPassphrase,
$currentUser['id']
);
}
}
}
}
}
// CSRF protection
$csrf = new CSRF();
// Route to appropriate controller
try {
switch ($page) {
case 'dashboard':
require_once __DIR__ . '/src/Controllers/DashboardController.php';
$controller = new PassGram\Controllers\DashboardController($db, $auth, $encryption);
$controller->index();
break;
case 'credentials':
require_once __DIR__ . '/src/Controllers/CredentialController.php';
require_once __DIR__ . '/src/Models/Credential.php';
require_once __DIR__ . '/src/Models/Group.php';
require_once __DIR__ . '/src/Models/User.php';
require_once __DIR__ . '/src/Models/Share.php';
$credentialModel = new PassGram\Models\Credential($db, $validator);
$groupModel = new PassGram\Models\Group($db, $validator);
$userModel = new PassGram\Models\User($db, $config, $validator);
$shareModel = new PassGram\Models\Share($db, $validator);
$controller = new PassGram\Controllers\CredentialController($auth, $csrf, $credentialModel, $logger, $groupModel, $userModel, $shareModel);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'create': $controller->create(); break;
case 'store': $controller->store(); break;
case 'view': $controller->show(); break;
case 'edit': $controller->edit(); break;
case 'update': $controller->update(); break;
case 'delete': $controller->delete(); break;
case 'share': $controller->share(); break;
case 'share-with-group': $controller->shareWithGroup(); break;
case 'revoke-group-share': $controller->revokeGroupShare(); break;
case 'get-password': $controller->getPassword(); break;
case 'generate-password': $controller->generatePassword(); break;
default: $controller->index(); break;
}
break;
case 'groups':
require_once __DIR__ . '/src/Controllers/GroupController.php';
require_once __DIR__ . '/src/Models/User.php';
require_once __DIR__ . '/src/Models/Group.php';
$userModel = new PassGram\Models\User($db, $config, $validator);
$groupModel = new PassGram\Models\Group($db, $validator);
$controller = new PassGram\Controllers\GroupController($auth, $csrf, $userModel, $groupModel, $logger);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'view': $controller->view(); break;
case 'create': $controller->create(); break;
case 'store': $controller->store(); break;
case 'edit': $controller->edit(); break;
case 'update': $controller->update(); break;
case 'delete': $controller->delete(); break;
case 'add-member': $controller->addMember(); break;
case 'remove-member': $controller->removeMember(); break;
case 'transfer-ownership': $controller->transferOwnership(); break;
case 'users-autocomplete': $controller->usersAutocomplete(); break;
default: $controller->index(); break;
}
break;
case 'invites':
require_once __DIR__ . '/src/Controllers/InviteController.php';
require_once __DIR__ . '/src/Models/Group.php';
require_once __DIR__ . '/src/Models/Invite.php';
$groupModel = new PassGram\Models\Group($db, $validator);
$inviteModel = new PassGram\Models\Invite($db, $config, $validator);
$controller = new PassGram\Controllers\InviteController($auth, $csrf, $groupModel, $inviteModel);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'generate': $controller->generate(); break;
default: $controller->index(); break;
}
break;
case 'shares':
require_once __DIR__ . '/src/Controllers/ShareController.php';
require_once __DIR__ . '/src/Models/User.php';
require_once __DIR__ . '/src/Models/Group.php';
require_once __DIR__ . '/src/Models/Credential.php';
require_once __DIR__ . '/src/Models/Share.php';
$userModel = new PassGram\Models\User($db, $config, $validator);
$groupModel = new PassGram\Models\Group($db, $validator);
$credentialModel = new PassGram\Models\Credential($db, $validator);
$shareModel = new PassGram\Models\Share($db, $validator);
$controller = new PassGram\Controllers\ShareController($config, $auth, $csrf, $userModel, $groupModel, $credentialModel, $shareModel, $logger);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'share': $controller->showShareForm(); break;
case 'create': $controller->create(); break;
case 'view': $controller->view(); break;
case 'revoke': $controller->revoke(); break;
default: $controller->index(); break;
}
break;
case 'public-share':
require_once __DIR__ . '/src/Controllers/PublicShareController.php';
require_once __DIR__ . '/src/Models/PublicShare.php';
require_once __DIR__ . '/src/Models/Credential.php';
$credentialModel = new PassGram\Models\Credential($db, $validator);
$publicShareModel = new PassGram\Models\PublicShare($db);
$controller = new PassGram\Controllers\PublicShareController(
$config, $auth, $csrf, $credentialModel, $publicShareModel, $logger
);
$action = $_GET['action'] ?? 'view';
switch ($action) {
case 'create': $controller->create(); break;
case 'revoke': $controller->revoke(); break;
case 'list': $controller->listShares(); break;
default: $controller->view(); break;
}
break;
case 'notes':
require_once __DIR__ . '/src/Controllers/NoteController.php';
require_once __DIR__ . '/src/Models/Note.php';
$noteModel = new PassGram\Models\Note($db, $validator);
$controller = new PassGram\Controllers\NoteController($auth, $csrf, $noteModel);
$controller->index();
break;
case 'pgpkeys':
require_once __DIR__ . '/src/Controllers/PGPKeyController.php';
require_once __DIR__ . '/src/Models/PGPKey.php';
require_once __DIR__ . '/src/Models/Group.php';
$pgpKeyModel = new PassGram\Models\PGPKey($db, $validator);
$groupModel = new PassGram\Models\Group($db, $validator);
$controller = new PassGram\Controllers\PGPKeyController($auth, $csrf, $pgpKeyModel, $logger, $groupModel);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'create': $controller->create(); break;
case 'store': $controller->store(); break;
case 'view': $controller->show(); break;
case 'edit': $controller->edit(); break;
case 'update': $controller->update(); break;
case 'delete': $controller->delete(); break;
case 'share-with-group': $controller->shareWithGroup(); break;
case 'revoke-group-share': $controller->revokeGroupShare(); break;
default: $controller->index(); break;
}
break;
case 'pgp':
require_once __DIR__ . '/src/Controllers/PGPController.php';
require_once __DIR__ . '/src/Models/User.php';
$userModel = new PassGram\Models\User($db, $config, $validator);
$controller = new PassGram\Controllers\PGPController($config, $auth, $csrf, $userModel, $logger);
$action = $_GET['action'] ?? 'view';
switch ($action) {
case 'generate': $controller->generate(); break;
case 'show-generate': $controller->showGenerate(); break;
case 'unlock-pgp': $controller->unlockPGP(); break;
case 'lock-pgp': $controller->lockPGP(); break;
case 'toggle-encryption': $controller->toggleEncryption(); break;
default: $controller->view(); break;
}
break;
case 'keys':
require_once __DIR__ . '/src/Controllers/PublicKeyController.php';
$controller = new PassGram\Controllers\PublicKeyController($db);
$controller->index();
break;
case 'export':
require_once __DIR__ . '/src/Controllers/ExportController.php';
require_once __DIR__ . '/src/Models/Credential.php';
require_once __DIR__ . '/src/Models/Group.php';
require_once __DIR__ . '/src/Models/User.php';
$credentialModel = new PassGram\Models\Credential($db, $validator);
$groupModel = new PassGram\Models\Group($db, $validator);
$userModel = new PassGram\Models\User($db, $config, $validator);
$controller = new PassGram\Controllers\ExportController($auth, $csrf, $credentialModel, $groupModel, $userModel, $logger, $encryption);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'export': $controller->export(); break;
case 'plaintext-json': $controller->plaintextJson(); break;
default: $controller->index(); break;
}
break;
case 'import':
require_once __DIR__ . '/src/Controllers/ImportController.php';
require_once __DIR__ . '/src/Models/Credential.php';
$credentialModel = new PassGram\Models\Credential($db, $validator);
$controller = new PassGram\Controllers\ImportController($auth, $csrf, $credentialModel, $logger, $encryption, $validator);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'import': $controller->import(); break;
case 'import-gpg': $controller->importGpg(); break;
default: $controller->index(); break;
}
break;
case 'admin':
require_once __DIR__ . '/src/Controllers/AdminController.php';
require_once __DIR__ . '/src/Models/User.php';
require_once __DIR__ . '/src/Models/Group.php';
require_once __DIR__ . '/src/Models/AuditLog.php';
require_once __DIR__ . '/src/Models/PasswordReset.php';
$userModel = new PassGram\Models\User($db, $config, $validator);
$groupModel = new PassGram\Models\Group($db, $validator);
$auditLogModel = new PassGram\Models\AuditLog($db);
$resetModel = new PassGram\Models\PasswordReset($db);
$controller = new PassGram\Controllers\AdminController(
$config, $auth, $csrf, $userModel, $groupModel, $auditLogModel, $resetModel, $validator, $logger
);
$action = $_GET['action'] ?? 'index';
switch ($action) {
case 'users': $controller->users(); break;
case 'view-user': $controller->viewUser(); break;
case 'add-user': $controller->addUser(); break;
case 'update-user': $controller->updateUser(); break;
case 'delete-user': $controller->deleteUser(); break;
case 'generate-reset-link': $controller->generateResetLink(); break;
case 'audit-log': $controller->auditLog(); break;
case 'files': $controller->listFiles(); break;
default: $controller->index(); break;
}
break;
default:
// Redirect to dashboard for unknown pages
header('Location: /index.php?page=dashboard');
exit;
}
} catch (Exception $e) {
// Log error and show generic error page
$logger->error('Application error: ' . $e->getMessage());
echo '<!DOCTYPE html><html><head><title>Error</title>';
echo '<link rel="stylesheet" href="/assets/css/style.css"></head><body>';
echo '<div class="window"><div class="title-bar"><span class="title-bar-text">Error</span></div>';
echo '<div class="window-content"><div class="alert alert-error">';
echo '<strong>Error:</strong> ' . htmlspecialchars($e->getMessage());
echo '</div><p><a href="/index.php" class="button">Back to Dashboard</a></p></div></div>';
echo '</body></html>';
}