Domain Model
The Domain model represents websites or services where you have accounts:
class Domain extends Model
{
use HasFactory;
use UserTrait;
protected $fillable = ['name', 'user_id'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function records(): HasMany
{
return $this->hasMany(Record::class)->with('domain');
}
protected function casts(): array
{
return [
'created_at' => 'date',
'updated_at' => 'date',
];
}
}
Record Model
The Record model stores the actual password entries with password expiry tracking:
class Record extends Model
{
use HasFactory;
protected $fillable = [
'record_type_id',
'url',
'username',
'password',
'domain_id',
'password_last_changed',
'password_expiry_days',
];
public function recordType(): BelongsTo
{
return $this->belongsTo(RecordType::class);
}
public function domain(): BelongsTo
{
return $this->belongsTo(Domain::class);
}
public function auditLogs(): HasMany
{
return $this->hasMany(AuditLog::class);
}
/**
* Check if password is expired
*/
public function isPasswordExpired(): bool
{
if (!$this->password_last_changed) {
return false;
}
$expiryDate = $this->password_last_changed->addDays($this->password_expiry_days);
return $expiryDate->isPast();
}
/**
* Get days until password expires
*/
public function daysUntilExpiry(): ?int
{
if (!$this->password_last_changed || !$this->password_expiry_days) {
return null;
}
$expiryDate = $this->password_last_changed->addDays($this->password_expiry_days);
return (int) max(0, Carbon::now()->diffInDays($expiryDate, false));
}
/**
* Check if password is nearing expiry (within 14 days)
*/
public function isPasswordNearingExpiry(): bool
{
$days = $this->daysUntilExpiry();
return $days !== null && $days <= 14 && $days > 0;
}
protected function casts(): array
{
return [
'created_at' => 'date',
'updated_at' => 'date',
'password_last_changed' => 'datetime',
];
}
}
RecordType Model
The RecordType model allows for categorization of password records:
class RecordType extends Model
{
use HasFactory;
use UserTrait;
protected $fillable = ['name', 'user_id'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
protected function casts(): array
{
return [
'created_at' => 'date',
'updated_at' => 'date',
];
}
}
AuditLog Model
The AuditLog model tracks all password-related activities for security monitoring:
class AuditLog extends Model
{
protected $fillable = ['user_id', 'record_id', 'action', 'details', 'ip_address', 'user_agent'];
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function record(): BelongsTo
{
return $this->belongsTo(Record::class);
}
protected function casts(): array
{
return [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
}
}
Security Considerations
Password Encryption
All passwords are encrypted in the database using Laravel's Crypt facade:
// When displaying a password
TextColumn::make('password')
->copyable()
->icon('heroicon-s-document-duplicate')
->formatStateUsing(fn (string $state): string => Crypt::decryptString($state)),
// When saving a password
TextInput::make('password')
->required()
->formatStateUsing(function ($state) {
if ($state) {
return Crypt::decryptString($state);
}
return null;
})
->dehydrateStateUsing(fn ($state) => Crypt::encryptString($state))
->dehydrated(fn ($state) => filled($state)),
User Scope
The application implements a user scope to ensure that users can only access their own data:
#[ScopedBy(UserScope::class)]
class Domain extends Model
{
use UserTrait;
// ...
}
Audit Logging
The application includes comprehensive audit logging to enhance security:
// Example of how audit logging is implemented
AuditLogService::log('view_password', $record);
All sensitive actions are logged, including:
- Viewing passwords
- Creating new records
- Editing existing records
- Deleting records
Each log entry contains:
- User ID
- Record ID
- Action type
- IP address
- User agent (browser information)
- Timestamp
Best Practices
- Use HTTPS: Always configure your server to use HTTPS to encrypt data in transit
- Regular Backups: Implement regular database backups to prevent data loss
- Update Regularly: Keep the application and its dependencies up to date
- Strong Master Password: Use a strong password for your application account
- Limited Access: Restrict server access to authorized personnel only
- Review Audit Logs: Regularly review audit logs for suspicious activities
- Rotate Passwords: Use the password expiry feature to enforce regular password rotation
Disclaimer
This software and its code are provided AS IS. Do not use it if you don't know what you are doing. The author(s) assumes no responsibility or liability for any errors or omissions. It is NOT recommended to use it on a publicly accessible server!
ALL CONTENT IS "AS IS" AND "AS AVAILABLE" BASIS WITHOUT ANY REPRESENTATIONS OR WARRANTIES OF ANY KIND INCLUDING THE WARRANTIES OF MERCHANTABILITY, EXPRESS OR IMPLIED TO THE FULL EXTENT PERMISSIBLE BY LAW. THE AUTHORS MAKE NO WARRANTIES THAT THE SOFTWARE WILL PERFORM OR OPERATE TO MEET YOUR REQUIREMENTS OR THAT THE FEATURES PRESENTED WILL BE COMPLETE, CURRENT OR ERROR-FREE.
License
This software is released under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version (GPL-3+).