diff --git a/readme.md b/readme.md
index f97b1d1..7445484 100644
--- a/readme.md
+++ b/readme.md
@@ -205,6 +205,16 @@ All view templates are in `resources/views/` and can be customized:
- `blog/show.php` - Individual post
- `admin/*` - Admin panel templates
+### Scheduling Jobs
+
+Start the scheduler:
+
+```bash
+php neuron jobs:schedule
+```
+
+This will process scheduled jobs.
+
### Running Background Jobs
Start the queue worker:
diff --git a/resources/app/Initializers/AuthInitializer.php b/resources/app/Initializers/AuthInitializer.php
index 3382f0e..a2085d5 100644
--- a/resources/app/Initializers/AuthInitializer.php
+++ b/resources/app/Initializers/AuthInitializer.php
@@ -20,58 +20,39 @@ class AuthInitializer implements IRunnable
{
/**
* Run the initializer
+ * @param array $argv
+ * @return mixed
+ * @throws \Exception
*/
- public function run( array $Argv = [] ): mixed
+ public function run( array $argv = [] ): mixed
{
// Get Settings from Registry
- $Settings = Registry::getInstance()->get( 'Settings' );
+ $settings = Registry::getInstance()->get( 'Settings' );
- if( !$Settings || !$Settings instanceof \Neuron\Data\Setting\SettingManager )
+ if( !$settings || !$settings instanceof \Neuron\Data\Setting\SettingManager )
{
Log::error( "Settings not found in Registry, skipping auth initialization" );
return null;
}
// Get Application from Registry
- $App = Registry::getInstance()->get( 'App' );
+ $app = Registry::getInstance()->get( 'App' );
- if( !$App || !$App instanceof \Neuron\Mvc\Application )
+ if( !$app || !$app instanceof \Neuron\Mvc\Application )
{
Log::error( "Application not found in Registry, skipping auth initialization" );
return null;
}
- // Get database configuration
- $dbConfig = [];
+ // Check if database is configured
try
{
- $settingNames = $Settings->getSectionSettingNames( 'database' );
+ $settingNames = $settings->getSectionSettingNames( 'database' );
if( !empty( $settingNames ) )
- {
- foreach( $settingNames as $name )
- {
- $value = $Settings->get( 'database', $name );
- if( $value !== null )
- {
- // Convert string values to appropriate types
- $dbConfig[$name] = ( $name === 'port' ) ? (int)$value : $value;
- }
- }
- }
- }
- catch( \Exception $e )
- {
- Log::error( "Failed to load database config: " . $e->getMessage() );
- }
-
- // Only register auth filter if database is configured
- if( !empty( $dbConfig ) )
- {
- try
{
// Initialize authentication components
- $userRepository = new DatabaseUserRepository( $dbConfig );
+ $userRepository = new DatabaseUserRepository( $settings );
$sessionManager = new SessionManager();
$passwordHasher = new PasswordHasher();
$authManager = new AuthManager( $userRepository, $sessionManager, $passwordHasher );
@@ -80,15 +61,15 @@ public function run( array $Argv = [] ): mixed
$authFilter = new AuthenticationFilter( $authManager, '/login' );
// Register the auth filter with the Router
- $App->getRouter()->registerFilter( 'auth', $authFilter );
+ $app->getRouter()->registerFilter( 'auth', $authFilter );
// Store AuthManager in Registry for easy access
Registry::getInstance()->set( 'AuthManager', $authManager );
}
- catch( \Exception $e )
- {
- Log::error( "Failed to register auth filter: " . $e->getMessage() );
- }
+ }
+ catch( \Exception $e )
+ {
+ Log::error( "Failed to register auth filter: " . $e->getMessage() );
}
return null;
diff --git a/resources/app/Initializers/MaintenanceInitializer.php b/resources/app/Initializers/MaintenanceInitializer.php
index c0bf599..fc44426 100644
--- a/resources/app/Initializers/MaintenanceInitializer.php
+++ b/resources/app/Initializers/MaintenanceInitializer.php
@@ -19,34 +19,37 @@ class MaintenanceInitializer implements IRunnable
{
/**
* Run the initializer
+ * @param array $argv
+ * @return mixed
+ * @throws \Exception
*/
- public function run( array $Argv = [] ): mixed
+ public function run( array $argv = [] ): mixed
{
// Get Application from Registry
- $App = Registry::getInstance()->get( 'App' );
+ $app = Registry::getInstance()->get( 'App' );
- if( !$App || !$App instanceof \Neuron\Mvc\Application )
+ if( !$app || !$app instanceof \Neuron\Mvc\Application )
{
Log::error( "Application not found in Registry, skipping maintenance initialization" );
return null;
}
// Get base path for maintenance file (use application base path, not cwd)
- $basePath = $App->getBasePath();
+ $basePath = $app->getBasePath();
// Create maintenance manager
$manager = new MaintenanceManager( $basePath );
// Get configuration (if available)
$config = null;
- $Settings = Registry::getInstance()->get( 'Settings' );
+ $settings = Registry::getInstance()->get( 'Settings' );
- if( $Settings && $Settings instanceof \Neuron\Data\Setting\SettingManager )
+ if( $settings && $settings instanceof \Neuron\Data\Setting\SettingManager )
{
try
{
// Get the source from the SettingManager
- $source = $Settings->getSource();
+ $source = $settings->getSource();
$config = MaintenanceConfig::fromSettings( $source );
}
catch( \Exception $e )
@@ -62,8 +65,8 @@ public function run( array $Argv = [] ): mixed
);
// Register and apply filter globally to all routes
- $App->getRouter()->registerFilter( 'maintenance', $filter );
- $App->getRouter()->addFilter( 'maintenance' );
+ $app->getRouter()->registerFilter( 'maintenance', $filter );
+ $app->getRouter()->addFilter( 'maintenance' );
// Store manager in registry for CLI commands
Registry::getInstance()->set( 'maintenance.manager', $manager );
diff --git a/resources/app/Initializers/PasswordResetInitializer.php b/resources/app/Initializers/PasswordResetInitializer.php
index ca8dfca..88a2245 100644
--- a/resources/app/Initializers/PasswordResetInitializer.php
+++ b/resources/app/Initializers/PasswordResetInitializer.php
@@ -20,61 +20,42 @@ class PasswordResetInitializer implements IRunnable
{
/**
* Run the initializer
+ * @param array $argv
+ * @return mixed
+ * @throws \Exception
*/
- public function run( array $Argv = [] ): mixed
+ public function run( array $argv = [] ): mixed
{
// Get Settings from Registry
- $Settings = Registry::getInstance()->get( 'Settings' );
+ $settings = Registry::getInstance()->get( 'Settings' );
- if( !$Settings || !$Settings instanceof SettingManager )
+ if( !$settings || !$settings instanceof SettingManager )
{
Log::error( "Settings not found in Registry, skipping password reset initialization" );
return null;
}
- // Get database configuration
- $dbConfig = [];
+ // Check if database is configured
try
{
- $settingNames = $Settings->getSectionSettingNames( 'database' );
+ $settingNames = $settings->getSectionSettingNames( 'database' );
if( !empty( $settingNames ) )
- {
- foreach( $settingNames as $name )
- {
- $value = $Settings->get( 'database', $name );
- if( $value !== null )
- {
- // Convert string values to appropriate types
- $dbConfig[$name] = ( $name === 'port' ) ? (int)$value : $value;
- }
- }
- }
- }
- catch( \Exception $e )
- {
- Log::error( "Failed to load database config: " . $e->getMessage() );
- }
-
- // Only initialize if database is configured
- if( !empty( $dbConfig ) )
- {
- try
{
// Get site configuration
- $siteUrl = $Settings->get( 'site', 'url' ) ?? 'http://localhost:8000';
- $siteName = $Settings->get( 'site', 'name' ) ?? 'Neuron CMS';
+ $siteUrl = $settings->get( 'site', 'url' ) ?? 'http://localhost:8000';
+ $siteName = $settings->get( 'site', 'name' ) ?? 'Neuron CMS';
// Get email configuration (with fallbacks)
- $fromEmail = $Settings->get( 'mail', 'from_email' ) ?? 'noreply@localhost';
- $fromName = $Settings->get( 'mail', 'from_name' ) ?? $siteName;
+ $fromEmail = $settings->get( 'mail', 'from_email' ) ?? 'noreply@localhost';
+ $fromName = $settings->get( 'mail', 'from_name' ) ?? $siteName;
// Get token expiration (default 60 minutes)
- $tokenExpiration = $Settings->get( 'auth', 'password_reset_expiration' ) ?? 60;
+ $tokenExpiration = $settings->get( 'auth', 'password_reset_expiration' ) ?? 60;
// Initialize components
- $tokenRepository = new DatabasePasswordResetTokenRepository( $dbConfig );
- $userRepository = new DatabaseUserRepository( $dbConfig );
+ $tokenRepository = new DatabasePasswordResetTokenRepository( $settings );
+ $userRepository = new DatabaseUserRepository( $settings );
$passwordHasher = new PasswordHasher();
// Create password reset URL
@@ -95,14 +76,12 @@ public function run( array $Argv = [] ): mixed
// Store PasswordResetManager in Registry for easy access
Registry::getInstance()->set( 'PasswordResetManager', $resetManager );
-
- Log::debug( "Password reset system initialized" );
- }
- catch( \Exception $e )
- {
- Log::error( "Failed to initialize password reset: " . $e->getMessage() );
}
}
+ catch( \Exception $e )
+ {
+ Log::error( "Failed to initialize password reset: " . $e->getMessage() );
+ }
return null;
}
diff --git a/resources/public/index.php b/resources/public/index.php
index cff61ef..446f0d5 100644
--- a/resources/public/index.php
+++ b/resources/public/index.php
@@ -11,6 +11,6 @@
error_reporting( E_ALL );
-$App = boot( '../config' );
+$app = boot( '../config' );
-dispatch( $App );
+dispatch( $app );
diff --git a/resources/views/admin/posts/edit.php b/resources/views/admin/posts/edit.php
index eef90ac..5cb011a 100644
--- a/resources/views/admin/posts/edit.php
+++ b/resources/views/admin/posts/edit.php
@@ -23,7 +23,7 @@
| = $post->getId() ?> |
= htmlspecialchars( $post->getTitle() ) ?> |
- = htmlspecialchars( $post->getAuthor() ) ?> |
+ = $post->getAuthor() ? htmlspecialchars( $post->getAuthor()->getUsername() ) : 'Unknown' ?> |
= htmlspecialchars( $post->getStatus() ) ?> |
- = $post->getViews() ?> |
+ = $post->getViewCount() ?> |
= $post->getCreatedAt() ? $post->getCreatedAt()->format( 'Y-m-d H:i' ) : 'N/A' ?> |
View
diff --git a/resources/views/blog/category.php b/resources/views/blog/category.php
index c9a4415..a46cfc5 100644
--- a/resources/views/blog/category.php
+++ b/resources/views/blog/category.php
@@ -23,7 +23,7 @@
- By = htmlspecialchars( $post->getAuthor() ) ?>
+ By = $post->getAuthor() ? htmlspecialchars( $post->getAuthor()->getUsername() ) : 'Unknown' ?>
on = $post->getCreatedAt() ? $post->getCreatedAt()->format( 'F j, Y' ) : '' ?>
diff --git a/resources/views/blog/tag.php b/resources/views/blog/tag.php
index 1fea0e7..63b2321 100644
--- a/resources/views/blog/tag.php
+++ b/resources/views/blog/tag.php
@@ -20,7 +20,7 @@
- By = htmlspecialchars( $post->getAuthor() ) ?>
+ By = $post->getAuthor() ? htmlspecialchars( $post->getAuthor()->getUsername() ) : 'Unknown' ?>
on = $post->getCreatedAt() ? $post->getCreatedAt()->format( 'F j, Y' ) : '' ?>
diff --git a/src/Bootstrap.php b/src/Bootstrap.php
index fc87151..eaf5a6e 100644
--- a/src/Bootstrap.php
+++ b/src/Bootstrap.php
@@ -21,18 +21,18 @@
/**
* Bootstrap and initialize a Neuron CMS application.
- *
+ *
* This function initializes a complete CMS application with all necessary
* components including routing, content management, blog functionality,
* and site configuration. It delegates to the MVC boot function but
* provides CMS-specific context and naming.
*
- * @param string $ConfigPath Path to the CMS configuration directory
+ * @param string $configPath Path to the CMS configuration directory
* @return Application Fully configured CMS application instance
* @throws \Exception If configuration loading or application initialization fails
*/
-function boot( string $ConfigPath ) : Application
+function boot( string $configPath ) : Application
{
- return \Neuron\Mvc\boot( $ConfigPath );
+ return \Neuron\Mvc\boot( $configPath );
}
diff --git a/src/Cms/Auth/AuthManager.php b/src/Cms/Auth/AuthManager.php
index 1dda54d..e51b647 100644
--- a/src/Cms/Auth/AuthManager.php
+++ b/src/Cms/Auth/AuthManager.php
@@ -16,80 +16,80 @@
*/
class AuthManager
{
- private IUserRepository $_UserRepository;
- private SessionManager $_SessionManager;
- private PasswordHasher $_PasswordHasher;
- private int $_MaxLoginAttempts = 5;
- private int $_LockoutDuration = 15; // minutes
+ private IUserRepository $_userRepository;
+ private SessionManager $_sessionManager;
+ private PasswordHasher $_passwordHasher;
+ private int $_maxLoginAttempts = 5;
+ private int $_lockoutDuration = 15; // minutes
public function __construct(
- IUserRepository $UserRepository,
- SessionManager $SessionManager,
- PasswordHasher $PasswordHasher
+ IUserRepository $userRepository,
+ SessionManager $sessionManager,
+ PasswordHasher $passwordHasher
)
{
- $this->_UserRepository = $UserRepository;
- $this->_SessionManager = $SessionManager;
- $this->_PasswordHasher = $PasswordHasher;
+ $this->_userRepository = $userRepository;
+ $this->_sessionManager = $sessionManager;
+ $this->_passwordHasher = $passwordHasher;
}
/**
* Attempt to authenticate a user
*/
- public function attempt( string $Username, string $Password, bool $Remember = false ): bool
+ public function attempt( string $username, string $password, bool $remember = false ): bool
{
- $User = $this->_UserRepository->findByUsername( $Username );
+ $user = $this->_userRepository->findByUsername( $username );
- if( !$User )
+ if( !$user )
{
// Perform dummy hash to normalize timing
- $this->_PasswordHasher->verify( $Password, '$2y$10$dummyhashtopreventtimingattack1234567890' );
+ $this->_passwordHasher->verify( $password, '$2y$10$dummyhashtopreventtimingattack1234567890' );
return false;
}
// Check if account is locked
- if( $User->isLockedOut() )
+ if( $user->isLockedOut() )
{
return false;
}
// Check if account is active
- if( !$User->isActive() )
+ if( !$user->isActive() )
{
return false;
}
// Verify password
- if( !$this->validateCredentials( $User, $Password ) )
+ if( !$this->validateCredentials( $user, $password ) )
{
// Increment failed login attempts
- $User->incrementFailedLoginAttempts();
+ $user->incrementFailedLoginAttempts();
// Lock account if too many failed attempts
- if( $User->getFailedLoginAttempts() >= $this->_MaxLoginAttempts )
+ if( $user->getFailedLoginAttempts() >= $this->_maxLoginAttempts )
{
- $LockedUntil = (new DateTimeImmutable())->add( new DateInterval( "PT{$this->_LockoutDuration}M" ) );
- $User->setLockedUntil( $LockedUntil );
+ $lockedUntil = (new DateTimeImmutable())->add( new DateInterval( "PT{$this->_lockoutDuration}M" ) );
+ $user->setLockedUntil( $lockedUntil );
}
- $this->_UserRepository->update( $User );
+ $this->_userRepository->update( $user );
return false;
}
// Successful login - reset failed attempts
- $User->resetFailedLoginAttempts();
- $User->setLastLoginAt( new DateTimeImmutable() );
+ $user->resetFailedLoginAttempts();
+ $user->setLastLoginAt( new DateTimeImmutable() );
// Check if password needs rehashing
- if( $this->_PasswordHasher->needsRehash( $User->getPasswordHash() ) )
+ if( $this->_passwordHasher->needsRehash( $user->getPasswordHash() ) )
{
- $User->setPasswordHash( $this->_PasswordHasher->hash( $Password ) );
+ $user->setPasswordHash( $this->_passwordHasher->hash( $password ) );
}
- $this->_UserRepository->update( $User );
+ $this->_userRepository->update( $user );
// Log the user in
- $this->login( $User, $Remember );
+ $this->login( $user, $remember );
return true;
}
@@ -97,19 +97,19 @@ public function attempt( string $Username, string $Password, bool $Remember = fa
/**
* Log a user in
*/
- public function login( User $User, bool $Remember = false ): void
+ public function login( User $user, bool $remember = false ): void
{
// Regenerate session ID to prevent session fixation
- $this->_SessionManager->regenerate();
+ $this->_sessionManager->regenerate();
// Store user ID in session
- $this->_SessionManager->set( 'user_id', $User->getId() );
- $this->_SessionManager->set( 'user_role', $User->getRole() );
+ $this->_sessionManager->set( 'user_id', $user->getId() );
+ $this->_sessionManager->set( 'user_role', $user->getRole() );
// Handle remember me
- if( $Remember )
+ if( $remember )
{
- $this->setRememberToken( $User );
+ $this->setRememberToken( $user );
}
}
@@ -121,16 +121,16 @@ public function logout(): void
// Clear remember token if exists
if( $this->check() )
{
- $User = $this->user();
- if( $User )
+ $user = $this->user();
+ if( $user )
{
- $User->setRememberToken( null );
- $this->_UserRepository->update( $User );
+ $user->setRememberToken( null );
+ $this->_userRepository->update( $user );
}
}
// Destroy session
- $this->_SessionManager->destroy();
+ $this->_sessionManager->destroy();
// Delete remember me cookie if exists
if( isset( $_COOKIE['remember_token'] ) )
@@ -145,7 +145,7 @@ public function logout(): void
public function check(): bool
{
// Check session first
- if( $this->_SessionManager->has( 'user_id' ) )
+ if( $this->_sessionManager->has( 'user_id' ) )
{
return true;
}
@@ -169,22 +169,22 @@ public function user(): ?User
return null;
}
- $UserId = $this->_SessionManager->get( 'user_id' );
+ $userId = $this->_sessionManager->get( 'user_id' );
- if( !$UserId )
+ if( !$userId )
{
return null;
}
- $User = $this->_UserRepository->findById( $UserId );
-
- if( !$User )
+ $user = $this->_userRepository->findById( $userId );
+
+ if( !$user )
{
// Clear stale session if user no longer exists
$this->logout();
}
-
- return $User;
+
+ return $user;
}
/**
@@ -196,37 +196,37 @@ public function id(): ?int
{
return null;
}
-
- return $this->_SessionManager->get( 'user_id' );
+
+ return $this->_sessionManager->get( 'user_id' );
}
/**
* Validate user credentials
*/
- public function validateCredentials( User $User, string $Password ): bool
+ public function validateCredentials( User $user, string $password ): bool
{
- return $this->_PasswordHasher->verify( $Password, $User->getPasswordHash() );
+ return $this->_passwordHasher->verify( $password, $user->getPasswordHash() );
}
/**
* Set remember me token for user
*/
- private function setRememberToken( User $User ): void
+ private function setRememberToken( User $user ): void
{
// Generate secure random token
- $Token = bin2hex( random_bytes( 32 ) );
+ $token = bin2hex( random_bytes( 32 ) );
// Hash the token before storing
- $HashedToken = hash( 'sha256', $Token );
+ $hashedToken = hash( 'sha256', $token );
// Store hashed token in user record
- $User->setRememberToken( $HashedToken );
- $this->_UserRepository->update( $User );
+ $user->setRememberToken( $hashedToken );
+ $this->_userRepository->update( $user );
// Set cookie with plain token (30 days)
setcookie(
'remember_token',
- $Token,
+ $token,
time() + (30 * 24 * 60 * 60),
'/',
'',
@@ -238,20 +238,20 @@ private function setRememberToken( User $User ): void
/**
* Attempt to log in using remember token
*/
- public function loginUsingRememberToken( string $Token ): bool
+ public function loginUsingRememberToken( string $token ): bool
{
// Hash the token to compare with stored hash
- $HashedToken = hash( 'sha256', $Token );
+ $hashedToken = hash( 'sha256', $token );
- $User = $this->_UserRepository->findByRememberToken( $HashedToken );
+ $user = $this->_userRepository->findByRememberToken( $hashedToken );
- if( !$User || !$User->isActive() )
+ if( !$user || !$user->isActive() )
{
return false;
}
// Log the user in
- $this->login( $User, true );
+ $this->login( $user, true );
return true;
}
@@ -259,28 +259,28 @@ public function loginUsingRememberToken( string $Token ): bool
/**
* Set maximum login attempts before lockout
*/
- public function setMaxLoginAttempts( int $MaxLoginAttempts ): self
+ public function setMaxLoginAttempts( int $maxLoginAttempts ): self
{
- $this->_MaxLoginAttempts = $MaxLoginAttempts;
+ $this->_maxLoginAttempts = $maxLoginAttempts;
return $this;
}
/**
* Set lockout duration in minutes
*/
- public function setLockoutDuration( int $LockoutDuration ): self
+ public function setLockoutDuration( int $lockoutDuration ): self
{
- $this->_LockoutDuration = $LockoutDuration;
+ $this->_lockoutDuration = $lockoutDuration;
return $this;
}
/**
* Check if user has a specific role
*/
- public function hasRole( string $Role ): bool
+ public function hasRole( string $role ): bool
{
- $User = $this->user();
- return $User && $User->getRole() === $Role;
+ $user = $this->user();
+ return $user && $user->getRole() === $role;
}
/**
@@ -296,13 +296,13 @@ public function isAdmin(): bool
*/
public function isEditorOrHigher(): bool
{
- $User = $this->user();
- if( !$User )
+ $user = $this->user();
+ if( !$user )
{
return false;
}
- return in_array( $User->getRole(), [User::ROLE_ADMIN, User::ROLE_EDITOR] );
+ return in_array( $user->getRole(), [User::ROLE_ADMIN, User::ROLE_EDITOR] );
}
/**
@@ -310,12 +310,12 @@ public function isEditorOrHigher(): bool
*/
public function isAuthorOrHigher(): bool
{
- $User = $this->user();
- if( !$User )
+ $user = $this->user();
+ if( !$user )
{
return false;
}
- return in_array( $User->getRole(), [User::ROLE_ADMIN, User::ROLE_EDITOR, User::ROLE_AUTHOR] );
+ return in_array( $user->getRole(), [User::ROLE_ADMIN, User::ROLE_EDITOR, User::ROLE_AUTHOR] );
}
}
diff --git a/src/Cms/Auth/CsrfTokenManager.php b/src/Cms/Auth/CsrfTokenManager.php
index a525ae7..d16db0b 100644
--- a/src/Cms/Auth/CsrfTokenManager.php
+++ b/src/Cms/Auth/CsrfTokenManager.php
@@ -12,12 +12,12 @@
*/
class CsrfTokenManager
{
- private SessionManager $_SessionManager;
- private string $_TokenKey = 'csrf_token';
+ private SessionManager $_sessionManager;
+ private string $_tokenKey = 'csrf_token';
- public function __construct( SessionManager $SessionManager )
+ public function __construct( SessionManager $sessionManager )
{
- $this->_SessionManager = $SessionManager;
+ $this->_sessionManager = $sessionManager;
}
/**
@@ -25,9 +25,9 @@ public function __construct( SessionManager $SessionManager )
*/
public function generate(): string
{
- $Token = bin2hex( random_bytes( 32 ) );
- $this->_SessionManager->set( $this->_TokenKey, $Token );
- return $Token;
+ $token = bin2hex( random_bytes( 32 ) );
+ $this->_sessionManager->set( $this->_tokenKey, $token );
+ return $token;
}
/**
@@ -35,28 +35,28 @@ public function generate(): string
*/
public function getToken(): string
{
- if( !$this->_SessionManager->has( $this->_TokenKey ) )
+ if( !$this->_sessionManager->has( $this->_tokenKey ) )
{
return $this->generate();
}
- return $this->_SessionManager->get( $this->_TokenKey );
+ return $this->_sessionManager->get( $this->_tokenKey );
}
/**
* Validate a CSRF token
*/
- public function validate( string $Token ): bool
+ public function validate( string $token ): bool
{
- $StoredToken = $this->_SessionManager->get( $this->_TokenKey );
+ $storedToken = $this->_sessionManager->get( $this->_tokenKey );
- if( !$StoredToken )
+ if( !$storedToken )
{
return false;
}
// Use hash_equals to prevent timing attacks
- return hash_equals( $StoredToken, $Token );
+ return hash_equals( $storedToken, $token );
}
/**
diff --git a/src/Cms/Auth/Filters/AuthenticationFilter.php b/src/Cms/Auth/Filters/AuthenticationFilter.php
index 76a7025..e4accc4 100644
--- a/src/Cms/Auth/Filters/AuthenticationFilter.php
+++ b/src/Cms/Auth/Filters/AuthenticationFilter.php
@@ -17,17 +17,17 @@
*/
class AuthenticationFilter extends Filter
{
- private AuthManager $_AuthManager;
- private string $_LoginUrl = '/login';
- private string $_RedirectParam = 'redirect';
+ private AuthManager $_authManager;
+ private string $_loginUrl = '/login';
+ private string $_redirectParam = 'redirect';
- public function __construct( AuthManager $AuthManager, string $LoginUrl = '/login' )
+ public function __construct( AuthManager $authManager, string $loginUrl = '/login' )
{
- $this->_AuthManager = $AuthManager;
- $this->_LoginUrl = $LoginUrl;
+ $this->_authManager = $authManager;
+ $this->_loginUrl = $loginUrl;
parent::__construct(
- function( RouteMap $Route ) { $this->checkAuthentication( $Route ); },
+ function( RouteMap $route ) { $this->checkAuthentication( $route ); },
null
);
}
@@ -35,38 +35,34 @@ function( RouteMap $Route ) { $this->checkAuthentication( $Route ); },
/**
* Check if user is authenticated
*/
- protected function checkAuthentication( RouteMap $Route ): void
+ protected function checkAuthentication( RouteMap $route ): void
{
- if( !$this->_AuthManager->check() )
+ $user = $this->_authManager->user();
+ if( !$user )
{
// Store intended URL for post-login redirect
- $IntendedUrl = $_SERVER['REQUEST_URI'] ?? $Route->getPath();
+ $intendedUrl = $_SERVER['REQUEST_URI'] ?? $route->getPath();
// Redirect to login page
- $separator = ( strpos( $this->_LoginUrl, '?' ) === false ) ? '?' : '&';
- $query = http_build_query( [ $this->_RedirectParam => $IntendedUrl ] );
- $RedirectUrl = $this->_LoginUrl . $separator . $query;
+ $separator = ( strpos( $this->_loginUrl, '?' ) === false ) ? '?' : '&';
+ $query = http_build_query( [ $this->_redirectParam => $intendedUrl ] );
+ $redirectUrl = $this->_loginUrl . $separator . $query;
- header( 'Location: ' . $RedirectUrl );
+ header( 'Location: ' . $redirectUrl );
exit;
}
- // Store authenticated user in Registry for easy access
- $User = $this->_AuthManager->user();
- if( $User )
- {
- Registry::getInstance()->set( 'Auth.User', $User );
- Registry::getInstance()->set( 'Auth.UserId', $User->getId() );
- Registry::getInstance()->set( 'Auth.UserRole', $User->getRole() );
- }
+ Registry::getInstance()->set( 'Auth.User', $user );
+ Registry::getInstance()->set( 'Auth.UserId', $user->getId() );
+ Registry::getInstance()->set( 'Auth.UserRole', $user->getRole() );
}
/**
* Set login URL
*/
- public function setLoginUrl( string $LoginUrl ): self
+ public function setLoginUrl( string $loginUrl ): self
{
- $this->_LoginUrl = $LoginUrl;
+ $this->_loginUrl = $loginUrl;
return $this;
}
}
diff --git a/src/Cms/Auth/Filters/CsrfFilter.php b/src/Cms/Auth/Filters/CsrfFilter.php
index 39fea9c..5052ce9 100644
--- a/src/Cms/Auth/Filters/CsrfFilter.php
+++ b/src/Cms/Auth/Filters/CsrfFilter.php
@@ -17,15 +17,15 @@
*/
class CsrfFilter extends Filter
{
- private CsrfTokenManager $_CsrfManager;
- private array $_ExemptMethods = ['GET', 'HEAD', 'OPTIONS'];
+ private CsrfTokenManager $_csrfManager;
+ private array $_exemptMethods = ['GET', 'HEAD', 'OPTIONS'];
- public function __construct( CsrfTokenManager $CsrfManager )
+ public function __construct( CsrfTokenManager $csrfManager )
{
- $this->_CsrfManager = $CsrfManager;
+ $this->_csrfManager = $csrfManager;
parent::__construct(
- function( RouteMap $Route ) { $this->validateCsrfToken( $Route ); },
+ function( RouteMap $route ) { $this->validateCsrfToken( $route ); },
null
);
}
@@ -33,27 +33,27 @@ function( RouteMap $Route ) { $this->validateCsrfToken( $Route ); },
/**
* Validate CSRF token
*/
- protected function validateCsrfToken( RouteMap $Route ): void
+ protected function validateCsrfToken( RouteMap $route ): void
{
- $Method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
+ $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
// Skip validation for safe methods
- if( in_array( strtoupper( $Method ), $this->_ExemptMethods ) )
+ if( in_array( strtoupper( $method ), $this->_exemptMethods ) )
{
return;
}
// Get token from request
- $Token = $this->getTokenFromRequest();
+ $token = $this->getTokenFromRequest();
- if( !$Token )
+ if( !$token )
{
Log::warning( 'CSRF token missing from request' );
$this->respondForbidden( 'CSRF token missing' );
}
// Validate token
- if( !$this->_CsrfManager->validate( $Token ) )
+ if( !$this->_csrfManager->validate( $token ) )
{
Log::warning( 'Invalid CSRF token' );
$this->respondForbidden( 'Invalid CSRF token' );
@@ -83,11 +83,11 @@ private function getTokenFromRequest(): ?string
/**
* Respond with 403 Forbidden
*/
- private function respondForbidden( string $Message ): void
+ private function respondForbidden( string $message ): void
{
http_response_code( 403 );
echo '403 Forbidden';
- echo '' . htmlspecialchars( $Message ) . ' ';
+ echo '' . htmlspecialchars( $message ) . ' ';
exit;
}
}
diff --git a/src/Cms/Auth/PasswordHasher.php b/src/Cms/Auth/PasswordHasher.php
index b48baa8..1b0b17f 100644
--- a/src/Cms/Auth/PasswordHasher.php
+++ b/src/Cms/Auth/PasswordHasher.php
@@ -12,72 +12,72 @@
*/
class PasswordHasher
{
- private int $_MinLength = 8;
- private bool $_RequireUppercase = true;
- private bool $_RequireLowercase = true;
- private bool $_RequireNumbers = true;
- private bool $_RequireSpecialChars = false;
+ private int $_minLength = 8;
+ private bool $_requireUppercase = true;
+ private bool $_requireLowercase = true;
+ private bool $_requireNumbers = true;
+ private bool $_requireSpecialChars = false;
/**
* Hash a password using Argon2id or Bcrypt
*/
- public function hash( string $Password ): string
+ public function hash( string $password ): string
{
// Use Argon2id if available, otherwise fall back to Bcrypt
$algorithm = defined( 'PASSWORD_ARGON2ID' ) ? PASSWORD_ARGON2ID : PASSWORD_BCRYPT;
- return password_hash( $Password, $algorithm );
+ return password_hash( $password, $algorithm );
}
/**
* Verify a password against a hash
*/
- public function verify( string $Password, string $Hash ): bool
+ public function verify( string $password, string $hash ): bool
{
- return password_verify( $Password, $Hash );
+ return password_verify( $password, $hash );
}
/**
* Check if a hash needs to be rehashed (algorithm upgrade)
*/
- public function needsRehash( string $Hash ): bool
+ public function needsRehash( string $hash ): bool
{
$algorithm = defined( 'PASSWORD_ARGON2ID' ) ? PASSWORD_ARGON2ID : PASSWORD_BCRYPT;
- return password_needs_rehash( $Hash, $algorithm );
+ return password_needs_rehash( $hash, $algorithm );
}
/**
* Check if password meets strength requirements
*/
- public function meetsRequirements( string $Password ): bool
+ public function meetsRequirements( string $password ): bool
{
// Check minimum length
- if( strlen( $Password ) < $this->_MinLength )
+ if( strlen( $password ) < $this->_minLength )
{
return false;
}
// Check for uppercase letters
- if( $this->_RequireUppercase && !preg_match( '/[A-Z]/', $Password ) )
+ if( $this->_requireUppercase && !preg_match( '/[A-Z]/', $password ) )
{
return false;
}
// Check for lowercase letters
- if( $this->_RequireLowercase && !preg_match( '/[a-z]/', $Password ) )
+ if( $this->_requireLowercase && !preg_match( '/[a-z]/', $password ) )
{
return false;
}
// Check for numbers
- if( $this->_RequireNumbers && !preg_match( '/[0-9]/', $Password ) )
+ if( $this->_requireNumbers && !preg_match( '/[0-9]/', $password ) )
{
return false;
}
// Check for special characters
- if( $this->_RequireSpecialChars && !preg_match( '/[^A-Za-z0-9]/', $Password ) )
+ if( $this->_requireSpecialChars && !preg_match( '/[^A-Za-z0-9]/', $password ) )
{
return false;
}
@@ -88,111 +88,111 @@ public function meetsRequirements( string $Password ): bool
/**
* Get password validation error messages
*/
- public function getValidationErrors( string $Password ): array
+ public function getValidationErrors( string $password ): array
{
- $Errors = [];
+ $errors = [];
- if( strlen( $Password ) < $this->_MinLength )
+ if( strlen( $password ) < $this->_minLength )
{
- $Errors[] = "Password must be at least {$this->_MinLength} characters long";
+ $errors[] = "Password must be at least {$this->_minLength} characters long";
}
- if( $this->_RequireUppercase && !preg_match( '/[A-Z]/', $Password ) )
+ if( $this->_requireUppercase && !preg_match( '/[A-Z]/', $password ) )
{
- $Errors[] = 'Password must contain at least one uppercase letter';
+ $errors[] = 'Password must contain at least one uppercase letter';
}
- if( $this->_RequireLowercase && !preg_match( '/[a-z]/', $Password ) )
+ if( $this->_requireLowercase && !preg_match( '/[a-z]/', $password ) )
{
- $Errors[] = 'Password must contain at least one lowercase letter';
+ $errors[] = 'Password must contain at least one lowercase letter';
}
- if( $this->_RequireNumbers && !preg_match( '/[0-9]/', $Password ) )
+ if( $this->_requireNumbers && !preg_match( '/[0-9]/', $password ) )
{
- $Errors[] = 'Password must contain at least one number';
+ $errors[] = 'Password must contain at least one number';
}
- if( $this->_RequireSpecialChars && !preg_match( '/[^A-Za-z0-9]/', $Password ) )
+ if( $this->_requireSpecialChars && !preg_match( '/[^A-Za-z0-9]/', $password ) )
{
- $Errors[] = 'Password must contain at least one special character';
+ $errors[] = 'Password must contain at least one special character';
}
- return $Errors;
+ return $errors;
}
/**
* Set minimum password length
*/
- public function setMinLength( int $MinLength ): self
+ public function setMinLength( int $minLength ): self
{
- $this->_MinLength = $MinLength;
+ $this->_minLength = $minLength;
return $this;
}
/**
* Set whether uppercase letters are required
*/
- public function setRequireUppercase( bool $RequireUppercase ): self
+ public function setRequireUppercase( bool $requireUppercase ): self
{
- $this->_RequireUppercase = $RequireUppercase;
+ $this->_requireUppercase = $requireUppercase;
return $this;
}
/**
* Set whether lowercase letters are required
*/
- public function setRequireLowercase( bool $RequireLowercase ): self
+ public function setRequireLowercase( bool $requireLowercase ): self
{
- $this->_RequireLowercase = $RequireLowercase;
+ $this->_requireLowercase = $requireLowercase;
return $this;
}
/**
* Set whether numbers are required
*/
- public function setRequireNumbers( bool $RequireNumbers ): self
+ public function setRequireNumbers( bool $requireNumbers ): self
{
- $this->_RequireNumbers = $RequireNumbers;
+ $this->_requireNumbers = $requireNumbers;
return $this;
}
/**
* Set whether special characters are required
*/
- public function setRequireSpecialChars( bool $RequireSpecialChars ): self
+ public function setRequireSpecialChars( bool $requireSpecialChars ): self
{
- $this->_RequireSpecialChars = $RequireSpecialChars;
+ $this->_requireSpecialChars = $requireSpecialChars;
return $this;
}
/**
* Configure password requirements from settings
*/
- public function configure( array $Settings ): self
+ public function configure( array $settings ): self
{
- if( isset( $Settings['min_length'] ) )
+ if( isset( $settings['min_length'] ) )
{
- $this->setMinLength( $Settings['min_length'] );
+ $this->setMinLength( $settings['min_length'] );
}
- if( isset( $Settings['require_uppercase'] ) )
+ if( isset( $settings['require_uppercase'] ) )
{
- $this->setRequireUppercase( $Settings['require_uppercase'] );
+ $this->setRequireUppercase( $settings['require_uppercase'] );
}
- if( isset( $Settings['require_lowercase'] ) )
+ if( isset( $settings['require_lowercase'] ) )
{
- $this->setRequireLowercase( $Settings['require_lowercase'] );
+ $this->setRequireLowercase( $settings['require_lowercase'] );
}
- if( isset( $Settings['require_numbers'] ) )
+ if( isset( $settings['require_numbers'] ) )
{
- $this->setRequireNumbers( $Settings['require_numbers'] );
+ $this->setRequireNumbers( $settings['require_numbers'] );
}
- if( isset( $Settings['require_special_chars'] ) )
+ if( isset( $settings['require_special_chars'] ) )
{
- $this->setRequireSpecialChars( $Settings['require_special_chars'] );
+ $this->setRequireSpecialChars( $settings['require_special_chars'] );
}
return $this;
diff --git a/src/Cms/Auth/PasswordResetManager.php b/src/Cms/Auth/PasswordResetManager.php
index 1b37ca9..113dc80 100644
--- a/src/Cms/Auth/PasswordResetManager.php
+++ b/src/Cms/Auth/PasswordResetManager.php
@@ -17,47 +17,47 @@
*/
class PasswordResetManager
{
- private IPasswordResetTokenRepository $_TokenRepository;
- private IUserRepository $_UserRepository;
- private PasswordHasher $_PasswordHasher;
- private string $_ResetUrl;
- private string $_FromEmail;
- private string $_FromName;
- private int $_TokenExpirationMinutes = 60;
+ private IPasswordResetTokenRepository $_tokenRepository;
+ private IUserRepository $_userRepository;
+ private PasswordHasher $_passwordHasher;
+ private string $_resetUrl;
+ private string $_fromEmail;
+ private string $_fromName;
+ private int $_tokenExpirationMinutes = 60;
/**
* Constructor
*
- * @param IPasswordResetTokenRepository $TokenRepository Token repository
- * @param IUserRepository $UserRepository User repository
- * @param PasswordHasher $PasswordHasher Password hasher
- * @param string $ResetUrl Base URL for password reset (token will be appended)
- * @param string $FromEmail Email address to send from
- * @param string $FromName Name to send from
+ * @param IPasswordResetTokenRepository $tokenRepository Token repository
+ * @param IUserRepository $userRepository User repository
+ * @param PasswordHasher $passwordHasher Password hasher
+ * @param string $resetUrl Base URL for password reset (token will be appended)
+ * @param string $fromEmail Email address to send from
+ * @param string $fromName Name to send from
*/
public function __construct(
- IPasswordResetTokenRepository $TokenRepository,
- IUserRepository $UserRepository,
- PasswordHasher $PasswordHasher,
- string $ResetUrl,
- string $FromEmail,
- string $FromName = 'System'
+ IPasswordResetTokenRepository $tokenRepository,
+ IUserRepository $userRepository,
+ PasswordHasher $passwordHasher,
+ string $resetUrl,
+ string $fromEmail,
+ string $fromName = 'System'
)
{
- $this->_TokenRepository = $TokenRepository;
- $this->_UserRepository = $UserRepository;
- $this->_PasswordHasher = $PasswordHasher;
- $this->_ResetUrl = $ResetUrl;
- $this->_FromEmail = $FromEmail;
- $this->_FromName = $FromName;
+ $this->_tokenRepository = $tokenRepository;
+ $this->_userRepository = $userRepository;
+ $this->_passwordHasher = $passwordHasher;
+ $this->_resetUrl = $resetUrl;
+ $this->_fromEmail = $fromEmail;
+ $this->_fromName = $fromName;
}
/**
* Set token expiration time in minutes
*/
- public function setTokenExpirationMinutes( int $Minutes ): self
+ public function setTokenExpirationMinutes( int $minutes ): self
{
- $this->_TokenExpirationMinutes = $Minutes;
+ $this->_tokenExpirationMinutes = $minutes;
return $this;
}
@@ -66,39 +66,39 @@ public function setTokenExpirationMinutes( int $Minutes ): self
*
* Generates a secure token, stores it, and sends an email to the user.
*
- * @param string $Email User's email address
+ * @param string $email User's email address
* @return bool True if reset email was sent, false if user not found
* @throws Exception if email sending fails
*/
- public function requestReset( string $Email ): bool
+ public function requestReset( string $email ): bool
{
// Check if user exists
- $User = $this->_UserRepository->findByEmail( $Email );
+ $user = $this->_userRepository->findByEmail( $email );
- if( !$User )
+ if( !$user )
{
// Don't reveal whether email exists in system
return true;
}
// Delete any existing tokens for this email
- $this->_TokenRepository->deleteByEmail( $Email );
+ $this->_tokenRepository->deleteByEmail( $email );
// Generate secure random token
- $PlainToken = bin2hex( random_bytes( 32 ) );
- $HashedToken = hash( 'sha256', $PlainToken );
+ $plainToken = bin2hex( random_bytes( 32 ) );
+ $hashedToken = hash( 'sha256', $plainToken );
// Create and store token
- $Token = new PasswordResetToken(
- $Email,
- $HashedToken,
- $this->_TokenExpirationMinutes
+ $token = new PasswordResetToken(
+ $email,
+ $hashedToken,
+ $this->_tokenExpirationMinutes
);
- $this->_TokenRepository->create( $Token );
+ $this->_tokenRepository->create( $token );
// Send reset email
- $this->sendResetEmail( $Email, $PlainToken );
+ $this->sendResetEmail( $email, $plainToken );
return true;
}
@@ -106,62 +106,62 @@ public function requestReset( string $Email ): bool
/**
* Validate a reset token
*
- * @param string $PlainToken Plain text token from URL
+ * @param string $plainToken Plain text token from URL
* @return PasswordResetToken|null Token if valid and not expired, null otherwise
*/
- public function validateToken( string $PlainToken ): ?PasswordResetToken
+ public function validateToken( string $plainToken ): ?PasswordResetToken
{
- $HashedToken = hash( 'sha256', $PlainToken );
+ $hashedToken = hash( 'sha256', $plainToken );
- $Token = $this->_TokenRepository->findByToken( $HashedToken );
+ $token = $this->_tokenRepository->findByToken( $hashedToken );
- if( !$Token || $Token->isExpired() )
+ if( !$token || $token->isExpired() )
{
return null;
}
- return $Token;
+ return $token;
}
/**
* Reset password using a valid token
*
- * @param string $PlainToken Plain text token from URL
- * @param string $NewPassword New password to set
+ * @param string $plainToken Plain text token from URL
+ * @param string $newPassword New password to set
* @return bool True if password was reset, false if token invalid or expired
* @throws Exception if password doesn't meet requirements or update fails
*/
- public function resetPassword( string $PlainToken, string $NewPassword ): bool
+ public function resetPassword( string $plainToken, string $newPassword ): bool
{
// Validate token
- $Token = $this->validateToken( $PlainToken );
+ $token = $this->validateToken( $plainToken );
- if( !$Token )
+ if( !$token )
{
return false;
}
// Validate new password
- if( !$this->_PasswordHasher->meetsRequirements( $NewPassword ) )
+ if( !$this->_passwordHasher->meetsRequirements( $newPassword ) )
{
- $Errors = $this->_PasswordHasher->getValidationErrors( $NewPassword );
- throw new Exception( implode( ', ', $Errors ) );
+ $errors = $this->_passwordHasher->getValidationErrors( $newPassword );
+ throw new Exception( implode( ', ', $errors ) );
}
// Find user
- $User = $this->_UserRepository->findByEmail( $Token->getEmail() );
+ $user = $this->_userRepository->findByEmail( $token->getEmail() );
- if( !$User )
+ if( !$user )
{
return false;
}
// Update password
- $User->setPasswordHash( $this->_PasswordHasher->hash( $NewPassword ) );
- $this->_UserRepository->update( $User );
+ $user->setPasswordHash( $this->_passwordHasher->hash( $newPassword ) );
+ $this->_userRepository->update( $user );
// Delete the token
- $this->_TokenRepository->deleteByToken( hash( 'sha256', $PlainToken ) );
+ $this->_tokenRepository->deleteByToken( hash( 'sha256', $plainToken ) );
return true;
}
@@ -173,23 +173,23 @@ public function resetPassword( string $PlainToken, string $NewPassword ): bool
*/
public function cleanupExpiredTokens(): int
{
- return $this->_TokenRepository->deleteExpired();
+ return $this->_tokenRepository->deleteExpired();
}
/**
* Send password reset email
*
- * @param string $Email Recipient email
- * @param string $PlainToken Plain text token to include in URL
+ * @param string $email Recipient email
+ * @param string $plainToken Plain text token to include in URL
* @throws Exception if email sending fails
*/
- private function sendResetEmail( string $Email, string $PlainToken ): void
+ private function sendResetEmail( string $email, string $plainToken ): void
{
- $ResetLink = $this->_ResetUrl . '?token=' . urlencode( $PlainToken );
+ $resetLink = $this->_resetUrl . '?token=' . urlencode( $plainToken );
- $Subject = 'Password Reset Request';
+ $subject = 'Password Reset Request';
- $Body = <<
@@ -210,10 +210,10 @@ private function sendResetEmail( string $Email, string $PlainToken ): void
You have requested to reset your password. Click the button below to proceed:
- Reset Password
+ Reset Password
Or copy and paste this link into your browser:
- {$ResetLink}
- This link will expire in {$this->_TokenExpirationMinutes} minutes.
+ {$resetLink}
+ This link will expire in {$this->_tokenExpirationMinutes} minutes.
If you did not request a password reset, please ignore this email.
|