Skip to content

Commit

Permalink
add own action class for "rotate database password"
Browse files Browse the repository at this point in the history
  • Loading branch information
Boy132 committed Dec 12, 2024
1 parent d6f814b commit 12a4813
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@

namespace App\Filament\Admin\Resources\DatabaseHostResource\RelationManagers;

use App\Filament\Components\Forms\Actions\RotateDatabasePasswordAction;
use App\Models\Database;
use App\Services\Databases\DatabasePasswordService;
use App\Tables\Columns\DateTimeColumn;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Forms\Set;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\ViewAction;
Expand All @@ -30,25 +27,19 @@ public function form(Form $form): Form
TextInput::make('password')
->password()
->revealable()
->hintAction(
Action::make('rotate')
->icon('tabler-refresh')
->requiresConfirmation()
->action(fn (DatabasePasswordService $service, Database $database, $set, $get) => $this->rotatePassword($service, $database, $set, $get))
->authorize(fn (Database $database) => auth()->user()->can('update database', $database))
)
->hintAction(RotateDatabasePasswordAction::make())
->formatStateUsing(fn (Database $database) => $database->password),
TextInput::make('remote')
->label('Connections From')
->formatStateUsing(fn ($record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote),
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote),
TextInput::make('max_connections')
->formatStateUsing(fn ($record) => $record->max_connections === 0 ? 'Unlimited' : $record->max_connections),
TextInput::make('JDBC')
->formatStateUsing(fn (Database $record) => $record->max_connections === 0 ? 'Unlimited' : $record->max_connections),
TextInput::make('jdbc')
->label('JDBC Connection String')
->columnSpanFull()
->password()
->revealable()
->formatStateUsing(fn (Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')),
->formatStateUsing(fn (Database $database) => $database->jdbc),
]);
}

Expand All @@ -62,7 +53,7 @@ public function table(Table $table): Table
TextColumn::make('username')
->icon('tabler-user'),
TextColumn::make('remote')
->formatStateUsing(fn ($record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote),
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote),
TextColumn::make('server.name')
->icon('tabler-brand-docker')
->url(fn (Database $database) => route('filament.admin.resources.servers.edit', ['record' => $database->server_id])),
Expand All @@ -78,13 +69,4 @@ public function table(Table $table): Table
->hidden(fn () => !auth()->user()->can('viewList database')),
]);
}

protected function rotatePassword(DatabasePasswordService $service, Database $database, Set $set, Get $get): void
{
$newPassword = $service->handle($database);
$jdbcString = 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database');

$set('password', $newPassword);
$set('JDBC', $jdbcString);
}
}
28 changes: 6 additions & 22 deletions app/Filament/Admin/Resources/ServerResource/Pages/EditServer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Enums\ServerState;
use App\Filament\Admin\Resources\ServerResource;
use App\Filament\Admin\Resources\ServerResource\RelationManagers\AllocationsRelationManager;
use App\Filament\Components\Forms\Actions\RotateDatabasePasswordAction;
use App\Filament\Server\Pages\Console;
use App\Models\Database;
use App\Models\DatabaseHost;
Expand All @@ -14,7 +15,6 @@
use App\Models\Server;
use App\Models\ServerVariable;
use App\Services\Databases\DatabaseManagementService;
use App\Services\Databases\DatabasePasswordService;
use App\Services\Eggs\EggChangerService;
use App\Services\Servers\RandomWordService;
use App\Services\Servers\ReinstallServerService;
Expand Down Expand Up @@ -667,31 +667,24 @@ public function form(Form $form): Form
->password()
->revealable()
->columnSpan(1)
->hintAction(
Action::make('rotate')
->authorize(fn (Database $database) => auth()->user()->can('update database', $database))
->icon('tabler-refresh')
->modalHeading('Change Database Password?')
->action(fn (DatabasePasswordService $service, $record, $set, $get) => $this->rotatePassword($service, $record, $set, $get))
->requiresConfirmation()
)
->hintAction(RotateDatabasePasswordAction::make())
->formatStateUsing(fn (Database $database) => $database->password),
TextInput::make('remote')
->disabled()
->formatStateUsing(fn ($record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote)
->formatStateUsing(fn (Database $record) => $record->remote === '%' ? 'Anywhere ( % )' : $record->remote)
->columnSpan(1)
->label('Connections From'),
TextInput::make('max_connections')
->disabled()
->formatStateUsing(fn ($record) => $record->max_connections === 0 ? 'Unlimited' : $record->max_connections)
->formatStateUsing(fn (Database $record) => $record->max_connections === 0 ? 'Unlimited' : $record->max_connections)
->columnSpan(1),
TextInput::make('JDBC')
TextInput::make('jdbc')
->disabled()
->password()
->revealable()
->label('JDBC Connection String')
->columnSpan(2)
->formatStateUsing(fn (Get $get, $record) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($record->password) . '@' . $record->host->host . ':' . $record->host->port . '/' . $get('database')),
->formatStateUsing(fn (Database $record) => $record->jdbc),
])
->relationship('databases')
->deletable(false)
Expand Down Expand Up @@ -950,13 +943,4 @@ private function getSelectOptionsFromRules(ServerVariable $serverVariable): arra
->mapWithKeys(fn ($value) => [$value => $value])
->all();
}

protected function rotatePassword(DatabasePasswordService $service, Database $record, Set $set, Get $get): void
{
$newPassword = $service->handle($record);
$jdbcString = 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $record->host->host . ':' . $record->host->port . '/' . $get('database');

$set('password', $newPassword);
$set('JDBC', $jdbcString);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace App\Filament\Components\Forms\Actions;

use App\Models\Database;
use App\Services\Databases\DatabasePasswordService;
use Exception;
use Filament\Actions\StaticAction;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Set;
use Filament\Notifications\Notification;

class RotateDatabasePasswordAction extends Action
{
public static function getDefaultName(): ?string
{
return 'rotate';
}

protected function setUp(): void
{
parent::setUp();

$this->label('Rotate');

$this->icon('tabler-refresh');

$this->authorize(fn (Database $database) => auth()->user()->can('update database', $database));

$this->modalHeading('Rotate Password');

$this->modalIconColor('warning');

$this->modalSubmitAction(fn (StaticAction $action) => $action->color('warning'));

$this->requiresConfirmation();

$this->action(function (DatabasePasswordService $service, Database $database, Set $set) {
try {
$service->handle($database);

$database->refresh();

$set('password', $database->password);
$set('jdbc', $database->jdbc);

Notification::make()
->title('Password rotated')
->success()
->send();
} catch (Exception $exception) {
Notification::make()
->title('Password rotation failed')
->body($exception->getMessage())
->danger()
->send();

report($exception);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,20 @@

namespace App\Filament\Server\Resources\DatabaseResource\Pages;

use App\Filament\Components\Forms\Actions\RotateDatabasePasswordAction;
use App\Filament\Server\Resources\DatabaseResource;
use App\Models\Database;
use App\Models\DatabaseHost;
use App\Models\Permission;
use App\Models\Server;
use App\Services\Databases\DatabaseManagementService;
use App\Services\Databases\DatabasePasswordService;
use App\Tables\Columns\DateTimeColumn;
use Filament\Actions\CreateAction;
use Filament\Facades\Filament;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Grid;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Pages\ListRecords;
use Filament\Tables\Actions\DeleteAction;
use Filament\Tables\Actions\ViewAction;
Expand Down Expand Up @@ -45,30 +43,22 @@ public function form(Form $form): Form
->password()->revealable()
->hidden(fn () => !auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
->hintAction(
Action::make('rotate')
RotateDatabasePasswordAction::make()
->authorize(fn () => auth()->user()->can(Permission::ACTION_DATABASE_UPDATE, $server))
->icon('tabler-refresh')
->requiresConfirmation()
->action(function (DatabasePasswordService $service, Database $database, $set, $get) {
$newPassword = $service->handle($database);

$set('password', $newPassword);
$set('JDBC', 'jdbc:mysql://' . $get('username') . ':' . urlencode($newPassword) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database'));
})
)
->suffixAction(CopyAction::make())
->formatStateUsing(fn (Database $database) => $database->password),
TextInput::make('remote')
->label('Connections From'),
TextInput::make('max_connections')
->formatStateUsing(fn (Database $database) => $database->max_connections === 0 ? $database->max_connections : 'Unlimited'),
TextInput::make('JDBC')
TextInput::make('jdbc')
->label('JDBC Connection String')
->password()->revealable()
->hidden(!auth()->user()->can(Permission::ACTION_DATABASE_VIEW_PASSWORD, $server))
->suffixAction(CopyAction::make())
->columnSpanFull()
->formatStateUsing(fn (Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')),
->formatStateUsing(fn (Database $database) => $database->jdbc),
]);
}

Expand Down
9 changes: 9 additions & 0 deletions app/Models/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace App\Models;

use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\DB;

Expand All @@ -14,6 +15,7 @@
* @property string $remote
* @property string $password
* @property int $max_connections
* @property string $jdbc
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $updated_at
* @property \App\Models\Server $server
Expand Down Expand Up @@ -87,6 +89,13 @@ public function server(): BelongsTo
return $this->belongsTo(Server::class);
}

protected function jdbc(): Attribute
{
return Attribute::make(
get: fn () => 'jdbc:mysql://' . $this->username . ':' . urlencode($this->password) . '@' . $this->host->host . ':' . $this->host->port . '/' . $this->database,
);
}

/**
* Run the provided statement against the database on a given connection.
*/
Expand Down
4 changes: 1 addition & 3 deletions app/Services/Databases/DatabasePasswordService.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function __construct(
/**
* Updates a password for a given database.
*/
public function handle(Database|int $database): string
public function handle(Database|int $database): void
{
if (is_int($database)) {
$database = Database::query()->findOrFail($database);
Expand All @@ -40,7 +40,5 @@ public function handle(Database|int $database): string
$database->assignUserToDatabase($database->database, $database->username, $database->remote);
$database->flush();
});

return $password;
}
}

0 comments on commit 12a4813

Please sign in to comment.