*/ use HasApiTokens, HasFactory, Notifiable, SoftDeletes; protected $guarded = ['id']; protected static function booted(): void { static::creating(function (self $user) { if (empty($user->ulid)) { $user->ulid = Str::ulid(); } }); } /** * The attributes that should be hidden for serialization. * * @var list */ protected $hidden = [ 'password', 'remember_token', ]; /** * Get the attributes that should be cast. * * @return array */ protected function casts(): array { return [ 'email_verified_at' => 'datetime', 'two_factor_confirmed_at' => 'datetime', 'password' => 'hashed', ]; } /** @return HasMany */ public function workspaces(): HasMany { return $this->hasMany(Workspace::class, 'owner_id'); } /** @return BelongsTo */ public function defaultWorkspace(): BelongsTo { return $this->belongsTo(Workspace::class, 'default_workspace_id'); } /** @return HasMany */ public function workspaceMemberships(): HasMany { return $this->hasMany(WorkspaceMember::class); } /** @return array */ public function enableTwoFactor(string $secret): array { $recoveryCodes = collect(range(1, 8))->map(fn () => implode('-', [ strtoupper(substr(bin2hex(random_bytes(5)), 0, 5)), strtoupper(substr(bin2hex(random_bytes(5)), 0, 5)), ]))->all(); $this->update([ 'two_factor_secret' => encrypt($secret), 'two_factor_recovery' => encrypt(json_encode($recoveryCodes)), ]); return $recoveryCodes; } public function disableTwoFactor(): void { $this->update([ 'two_factor_secret' => null, 'two_factor_recovery' => null, 'two_factor_confirmed_at' => null, ]); } public function hasTwoFactorEnabled(): bool { return $this->two_factor_confirmed_at !== null; } public function verifyTwoFactor(string $code): bool { if (! $this->two_factor_secret) { return false; } $secret = decrypt($this->two_factor_secret); $google2fa = new Google2FA; return $google2fa->verifyKey($secret, $code) !== false; } }