'boolean', 'last_used_at' => 'datetime', 'expires_at' => 'datetime', 'metadata' => 'array', ]; protected $hidden = [ 'api_secret', ]; /** * Encrypt the API secret before saving * * @param string $value */ public function setApiSecretAttribute($value) { $this->attributes['api_secret'] = Crypt::encryptString($value); } /** * Decrypt the API secret when retrieving * * @param string $value * @return string */ public function getApiSecretAttribute($value) { try { return Crypt::decryptString($value); } catch (\Exception $e) { \Log::error('Failed to decrypt PBX API secret', [ 'credential_id' => $this->id, 'error' => $e->getMessage() ]); return null; } } /** * Get the decrypted API secret for runtime use * * @return string|null */ public function getDecryptedSecret(): ?string { return $this->api_secret; } /** * Mark this credential as used * * @return void */ public function markAsUsed(): void { $this->update(['last_used_at' => now()]); } /** * Check if credential is valid * * @return bool */ public function isValid(): bool { if (!$this->is_active) { return false; } if ($this->expires_at && $this->expires_at->isPast()) { return false; } return true; } /** * Scope: Get active credentials * * @param \Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopeActive($query) { return $query->where('is_active', true) ->where(function ($q) { $q->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }); } /** * Get the primary active credential * * @return static|null */ public static function getPrimary(): ?self { return static::active()->orderBy('created_at', 'asc')->first(); } }