diff --git a/app/Console/Commands/ResetAdmin.php b/app/Console/Commands/ResetAdmin.php new file mode 100644 index 0000000..d3b4739 --- /dev/null +++ b/app/Console/Commands/ResetAdmin.php @@ -0,0 +1,60 @@ +option('email'); + $user = $email !== '' + ? User::where('email', $email)->first() + : (User::count() === 1 ? User::first() : null); + + if (! $user) { + $this->error($email !== '' ? "Kein Benutzer mit E-Mail {$email}." : 'Kein eindeutiger Benutzer — bitte --email angeben.'); + + return self::FAILURE; + } + + $password = (string) ($this->option('password') ?: Str::password(20)); + $user->forceFill(['password' => Hash::make($password), 'must_change_password' => false]); + + if ($this->option('disable-2fa')) { + $user->forceFill([ + 'two_factor_secret' => null, + 'two_factor_confirmed_at' => null, + 'two_factor_recovery_codes' => null, + ]); + } + + $user->save(); + + $this->info("Passwort für {$user->email} zurückgesetzt."); + if (! $this->option('password')) { + $this->warn("Einmal-Passwort (jetzt notieren): {$password}"); + } + if ($this->option('disable-2fa')) { + $this->info('2FA + Backup-Codes entfernt — beim nächsten Login neu einrichten.'); + } + + return self::SUCCESS; + } +} diff --git a/tests/Feature/ResetAdminCommandTest.php b/tests/Feature/ResetAdminCommandTest.php new file mode 100644 index 0000000..8264a8f --- /dev/null +++ b/tests/Feature/ResetAdminCommandTest.php @@ -0,0 +1,36 @@ +create([ + 'email' => 'admin@clusev.local', + 'two_factor_secret' => 'x', 'two_factor_confirmed_at' => now(), + ]); + $user->replaceRecoveryCodes(); + + $this->artisan('clusev:reset-admin', ['--email' => 'admin@clusev.local', '--password' => 'BrandNew1234', '--disable-2fa' => true]) + ->assertExitCode(0); + + $user->refresh(); + $this->assertTrue(Hash::check('BrandNew1234', $user->password)); + $this->assertNull($user->two_factor_secret); + $this->assertNull($user->two_factor_confirmed_at); + $this->assertFalse($user->hasRecoveryCodes()); + } + + public function test_unknown_email_fails(): void + { + $this->artisan('clusev:reset-admin', ['--email' => 'nope@x.test'])->assertExitCode(1); + } +}