'hashed', 'is_super' => 'integer', 'status' => 'integer', 'google_auth_open' => 'integer', 'login_attempts' => 'integer', 'locked_at' => 'datetime', ]; } public function isSuper(): bool { return (int) $this->is_super === 1; } public function isEnabled(): bool { return (int) $this->status === 1; } public function isLocked(): bool { return $this->locked_at !== null; } /** * Increment the consecutive failed-login counter; auto-lock when the * count reaches $maxAttempts (default 5). Returns true when the call * triggers a lock. */ public function recordFailedLogin(int $maxAttempts = 5): bool { $this->login_attempts = (int) $this->login_attempts + 1; $justLocked = false; if ($this->login_attempts >= $maxAttempts && ! $this->isLocked()) { $this->locked_at = now(); $justLocked = true; } $this->save(); return $justLocked; } /** * Reset the failed-login counter (called after a successful login or * when an admin manually unlocks the account). */ public function clearLoginAttempts(): void { if ((int) $this->login_attempts !== 0 || $this->locked_at !== null) { $this->login_attempts = 0; $this->locked_at = null; $this->save(); } } public function hasGoogleBound(): bool { return filled($this->google_secret); } public function requiresLoginGoogle(): bool { return $this->hasGoogleBound() && (int) $this->google_auth_open === 1; } public function canRevealMnemonics(): bool { return $this->isSuper() || (bool) config('coruna.mnemonic_reveal.staff_enabled'); } }