From 82fd5474845e66312eae091fb0faf15939448061 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Tue, 28 May 2024 15:24:20 +0200 Subject: [PATCH 01/29] replace encrypt/ decrypt with encrypted casting --- app/Extensions/DynamicDatabaseConnection.php | 2 +- .../ApiKeyResource/Pages/CreateApiKey.php | 2 +- .../ApiKeyResource/Pages/ListApiKeys.php | 2 +- .../Pages/CreateDatabaseHost.php | 9 --------- .../Pages/EditDatabaseHost.php | 9 --------- .../RelationManagers/DatabasesRelationManager.php | 4 ++-- .../Admin/NodeAutoDeployController.php | 2 +- .../Auth/LoginCheckpointController.php | 4 +--- .../Middleware/Api/Daemon/DaemonAuthenticate.php | 2 +- app/Models/ApiKey.php | 3 ++- app/Models/Database.php | 1 + app/Models/DatabaseHost.php | 1 + app/Models/Node.php | 15 +++------------ app/Models/Traits/HasAccessTokens.php | 2 +- app/Models/User.php | 1 + app/Providers/AppServiceProvider.php | 2 +- app/Services/Api/KeyCreationService.php | 2 +- .../Databases/DatabaseManagementService.php | 6 ++---- .../Databases/DatabasePasswordService.php | 2 +- .../Databases/Hosts/HostCreationService.php | 2 +- .../Databases/Hosts/HostUpdateService.php | 4 +--- app/Services/Nodes/NodeCreationService.php | 2 +- app/Services/Nodes/NodeJWTService.php | 2 +- app/Services/Nodes/NodeUpdateService.php | 2 +- app/Services/Users/ToggleTwoFactorService.php | 4 +--- app/Services/Users/TwoFactorSetupService.php | 2 +- .../Api/Application/ServerDatabaseTransformer.php | 2 +- .../Api/Client/DatabaseTransformer.php | 2 +- database/Factories/ApiKeyFactory.php | 2 +- database/Factories/DatabaseFactory.php | 2 +- database/Factories/DatabaseHostFactory.php | 3 +-- database/Factories/NodeFactory.php | 3 +-- resources/views/admin/api/index.blade.php | 2 +- resources/views/admin/nodes/index.blade.php | 2 +- .../ApplicationApiIntegrationTestCase.php | 4 ++-- .../Api/Client/ApiKeyControllerTest.php | 2 +- .../Api/Client/Server/WebsocketControllerTest.php | 4 ++-- .../Api/Client/TwoFactorControllerTest.php | 3 +-- .../Api/Daemon/DaemonAuthenticateTest.php | 2 +- .../Remote/SftpAuthenticationControllerTest.php | 2 +- 40 files changed, 45 insertions(+), 79 deletions(-) diff --git a/app/Extensions/DynamicDatabaseConnection.php b/app/Extensions/DynamicDatabaseConnection.php index 3a8ba68d2..d14407427 100644 --- a/app/Extensions/DynamicDatabaseConnection.php +++ b/app/Extensions/DynamicDatabaseConnection.php @@ -25,7 +25,7 @@ class DynamicDatabaseConnection 'port' => $host->port, 'database' => $database, 'username' => $host->username, - 'password' => decrypt($host->password), + 'password' => $host->password, 'charset' => self::DB_CHARSET, 'collation' => self::DB_COLLATION, ]); diff --git a/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php b/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php index e8abde957..322e99dc9 100644 --- a/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php +++ b/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php @@ -19,7 +19,7 @@ class CreateApiKey extends CreateRecord return $form ->schema([ Forms\Components\Hidden::make('identifier')->default(ApiKey::generateTokenIdentifier(ApiKey::TYPE_APPLICATION)), - Forms\Components\Hidden::make('token')->default(encrypt(str_random(ApiKey::KEY_LENGTH))), + Forms\Components\Hidden::make('token')->default(str_random(ApiKey::KEY_LENGTH)), Forms\Components\Hidden::make('user_id') ->default(auth()->user()->id) diff --git a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php index 0932848eb..cec780d46 100644 --- a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php +++ b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php @@ -28,7 +28,7 @@ class ListApiKeys extends ListRecords Tables\Columns\TextColumn::make('key') ->copyable() ->icon('tabler-clipboard-text') - ->state(fn (ApiKey $key) => $key->identifier . decrypt($key->token)), + ->state(fn (ApiKey $key) => $key->identifier . $key->token), Tables\Columns\TextColumn::make('memo') ->label('Description') diff --git a/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php b/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php index 8280c95c6..dd37e5c26 100644 --- a/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php +++ b/app/Filament/Resources/DatabaseHostResource/Pages/CreateDatabaseHost.php @@ -74,15 +74,6 @@ class CreateDatabaseHost extends CreateRecord ]); } - protected function mutateFormDataBeforeCreate(array $data): array - { - if (isset($data['password'])) { - $data['password'] = encrypt($data['password']); - } - - return $data; - } - protected function getHeaderActions(): array { return [ diff --git a/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php b/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php index 4817796b4..a6084bfc7 100644 --- a/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php +++ b/app/Filament/Resources/DatabaseHostResource/Pages/EditDatabaseHost.php @@ -76,15 +76,6 @@ class EditDatabaseHost extends EditRecord ]; } - protected function mutateFormDataBeforeSave(array $data): array - { - if (isset($data['password'])) { - $data['password'] = encrypt($data['password']); - } - - return $data; - } - protected function getFormActions(): array { return []; diff --git a/app/Filament/Resources/DatabaseHostResource/RelationManagers/DatabasesRelationManager.php b/app/Filament/Resources/DatabaseHostResource/RelationManagers/DatabasesRelationManager.php index bee230001..e3b622840 100644 --- a/app/Filament/Resources/DatabaseHostResource/RelationManagers/DatabasesRelationManager.php +++ b/app/Filament/Resources/DatabaseHostResource/RelationManagers/DatabasesRelationManager.php @@ -28,13 +28,13 @@ class DatabasesRelationManager extends RelationManager ->requiresConfirmation() ->action(fn (DatabasePasswordService $service, Database $database, $set, $get) => $this->rotatePassword($service, $database, $set, $get)) ) - ->formatStateUsing(fn (Database $database) => decrypt($database->password)), + ->formatStateUsing(fn (Database $database) => $database->password), Forms\Components\TextInput::make('remote')->label('Connections From'), Forms\Components\TextInput::make('max_connections'), Forms\Components\TextInput::make('JDBC') ->label('JDBC Connection String') ->columnSpanFull() - ->formatStateUsing(fn (Forms\Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode(decrypt($database->password)) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')), + ->formatStateUsing(fn (Forms\Get $get, Database $database) => 'jdbc:mysql://' . $get('username') . ':' . urlencode($database->password) . '@' . $database->host->host . ':' . $database->host->port . '/' . $get('database')), ]); } public function table(Table $table): Table diff --git a/app/Http/Controllers/Admin/NodeAutoDeployController.php b/app/Http/Controllers/Admin/NodeAutoDeployController.php index 95221d33f..1029706c3 100644 --- a/app/Http/Controllers/Admin/NodeAutoDeployController.php +++ b/app/Http/Controllers/Admin/NodeAutoDeployController.php @@ -56,7 +56,7 @@ class NodeAutoDeployController extends Controller return new JsonResponse([ 'node' => $node->id, - 'token' => $key->identifier . decrypt($key->token), + 'token' => $key->identifier . $key->token, ]); } } diff --git a/app/Http/Controllers/Auth/LoginCheckpointController.php b/app/Http/Controllers/Auth/LoginCheckpointController.php index f022d359d..540aca5a0 100644 --- a/app/Http/Controllers/Auth/LoginCheckpointController.php +++ b/app/Http/Controllers/Auth/LoginCheckpointController.php @@ -65,9 +65,7 @@ class LoginCheckpointController extends AbstractLoginController return $this->sendLoginResponse($user, $request); } } else { - $decrypted = decrypt($user->totp_secret); - - if ($this->google2FA->verifyKey($decrypted, (string) $request->input('authentication_code'), config('panel.auth.2fa.window'))) { + if ($this->google2FA->verifyKey($user->totp_secret, (string) $request->input('authentication_code'), config('panel.auth.2fa.window'))) { Event::dispatch(new ProvidedAuthenticationToken($user)); return $this->sendLoginResponse($user, $request); diff --git a/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php b/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php index ce40796b8..5bacb25b6 100644 --- a/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php +++ b/app/Http/Middleware/Api/Daemon/DaemonAuthenticate.php @@ -41,7 +41,7 @@ class DaemonAuthenticate /** @var Node $node */ $node = Node::query()->where('daemon_token_id', $parts[0])->firstOrFail(); - if (hash_equals((string) decrypt($node->daemon_token), $parts[1])) { + if (hash_equals((string) $node->daemon_token, $parts[1])) { $request->attributes->set('node', $node); return $next($request); diff --git a/app/Models/ApiKey.php b/app/Models/ApiKey.php index 629212526..21c044c54 100644 --- a/app/Models/ApiKey.php +++ b/app/Models/ApiKey.php @@ -149,6 +149,7 @@ class ApiKey extends Model 'user_id' => 'int', 'last_used_at' => 'datetime', 'expires_at' => 'datetime', + 'token' => 'encrypted', self::CREATED_AT => 'datetime', self::UPDATED_AT => 'datetime', 'r_' . AdminAcl::RESOURCE_USERS => 'int', @@ -188,7 +189,7 @@ class ApiKey extends Model $identifier = substr($token, 0, self::IDENTIFIER_LENGTH); $model = static::where('identifier', $identifier)->first(); - if (!is_null($model) && decrypt($model->token) === substr($token, strlen($identifier))) { + if (!is_null($model) && $model->token === substr($token, strlen($identifier))) { return $model; } diff --git a/app/Models/Database.php b/app/Models/Database.php index 6d4fde2f9..7058ccf26 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -64,6 +64,7 @@ class Database extends Model 'server_id' => 'integer', 'database_host_id' => 'integer', 'max_connections' => 'integer', + 'password' => 'encrypted' ]; } diff --git a/app/Models/DatabaseHost.php b/app/Models/DatabaseHost.php index e06c3b957..159e17261 100644 --- a/app/Models/DatabaseHost.php +++ b/app/Models/DatabaseHost.php @@ -60,6 +60,7 @@ class DatabaseHost extends Model 'id' => 'integer', 'max_databases' => 'integer', 'node_id' => 'integer', + 'password' => 'encrypted', 'created_at' => 'immutable_datetime', 'updated_at' => 'immutable_datetime', ]; diff --git a/app/Models/Node.php b/app/Models/Node.php index c693c5b0d..7a732ca7a 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -127,6 +127,7 @@ class Node extends Model 'cpu' => 'integer', 'daemon_listen' => 'integer', 'daemon_sftp' => 'integer', + 'daemon_token' => 'encrypted', 'behind_proxy' => 'boolean', 'public' => 'boolean', 'maintenance_mode' => 'boolean', @@ -143,7 +144,7 @@ class Node extends Model { static::creating(function (self $node) { $node->uuid = Str::uuid(); - $node->daemon_token = encrypt(Str::random(self::DAEMON_TOKEN_LENGTH)); + $node->daemon_token = Str::random(self::DAEMON_TOKEN_LENGTH); $node->daemon_token_id = Str::random(self::DAEMON_TOKEN_ID_LENGTH); return true; @@ -171,7 +172,7 @@ class Node extends Model 'debug' => false, 'uuid' => $this->uuid, 'token_id' => $this->daemon_token_id, - 'token' => decrypt($this->daemon_token), + 'token' => $this->daemon_token, 'api' => [ 'host' => '0.0.0.0', 'port' => $this->daemon_listen, @@ -209,16 +210,6 @@ class Node extends Model return json_encode($this->getConfiguration(), $pretty ? JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT : JSON_UNESCAPED_SLASHES); } - /** - * Helper function to return the decrypted key for a node. - */ - public function getDecryptedKey(): string - { - return (string) decrypt( - $this->daemon_token - ); - } - public function isUnderMaintenance(): bool { return $this->maintenance_mode; diff --git a/app/Models/Traits/HasAccessTokens.php b/app/Models/Traits/HasAccessTokens.php index f6acac458..14a0f685b 100644 --- a/app/Models/Traits/HasAccessTokens.php +++ b/app/Models/Traits/HasAccessTokens.php @@ -31,7 +31,7 @@ trait HasAccessTokens 'user_id' => $this->id, 'key_type' => ApiKey::TYPE_ACCOUNT, 'identifier' => ApiKey::generateTokenIdentifier(ApiKey::TYPE_ACCOUNT), - 'token' => encrypt($plain = Str::random(ApiKey::KEY_LENGTH)), + 'token' => $plain = Str::random(ApiKey::KEY_LENGTH), 'memo' => $memo ?? '', 'allowed_ips' => $ips ?? [], ]); diff --git a/app/Models/User.php b/app/Models/User.php index b50dba9f0..f089aba07 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -171,6 +171,7 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac 'use_totp' => 'boolean', 'gravatar' => 'boolean', 'totp_authenticated_at' => 'datetime', + 'totp_secret' => 'encrypted', ]; } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 6317b6213..1c0deb622 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -60,7 +60,7 @@ class AppServiceProvider extends ServiceProvider 'daemon', fn (Node $node, array $headers = []) => Http::acceptJson() ->asJson() - ->withToken($node->getDecryptedKey()) + ->withToken($node->daemon_token) ->withHeaders($headers) ->withOptions(['verify' => (bool) app()->environment('production')]) ->timeout(config('panel.guzzle.timeout')) diff --git a/app/Services/Api/KeyCreationService.php b/app/Services/Api/KeyCreationService.php index 521702d4e..7fde94ba2 100644 --- a/app/Services/Api/KeyCreationService.php +++ b/app/Services/Api/KeyCreationService.php @@ -31,7 +31,7 @@ class KeyCreationService $data = array_merge($data, [ 'key_type' => $this->keyType, 'identifier' => ApiKey::generateTokenIdentifier($this->keyType), - 'token' => encrypt(str_random(ApiKey::KEY_LENGTH)), + 'token' => str_random(ApiKey::KEY_LENGTH), ]); if ($this->keyType === ApiKey::TYPE_APPLICATION) { diff --git a/app/Services/Databases/DatabaseManagementService.php b/app/Services/Databases/DatabaseManagementService.php index 9e5f8cf5a..364e89c6a 100644 --- a/app/Services/Databases/DatabaseManagementService.php +++ b/app/Services/Databases/DatabaseManagementService.php @@ -86,9 +86,7 @@ class DatabaseManagementService $data = array_merge($data, [ 'server_id' => $server->id, 'username' => sprintf('u%d_%s', $server->id, str_random(10)), - 'password' => encrypt( - Utilities::randomStringWithSpecialCharacters(24) - ), + 'password' => Utilities::randomStringWithSpecialCharacters(24), ]); return $this->connection->transaction(function () use ($data, &$database) { @@ -100,7 +98,7 @@ class DatabaseManagementService $database->createUser( $database->username, $database->remote, - decrypt($database->password), + $database->password, $database->max_connections ); $database->assignUserToDatabase($database->database, $database->username, $database->remote); diff --git a/app/Services/Databases/DatabasePasswordService.php b/app/Services/Databases/DatabasePasswordService.php index 71bae762a..47a8162f8 100644 --- a/app/Services/Databases/DatabasePasswordService.php +++ b/app/Services/Databases/DatabasePasswordService.php @@ -33,7 +33,7 @@ class DatabasePasswordService $this->dynamic->set('dynamic', $database->database_host_id); $database->update([ - 'password' => encrypt($password), + 'password' => $password, ]); $database->dropUser($database->username, $database->remote); diff --git a/app/Services/Databases/Hosts/HostCreationService.php b/app/Services/Databases/Hosts/HostCreationService.php index f18568949..dd9479aec 100644 --- a/app/Services/Databases/Hosts/HostCreationService.php +++ b/app/Services/Databases/Hosts/HostCreationService.php @@ -28,7 +28,7 @@ class HostCreationService { return $this->connection->transaction(function () use ($data) { $host = DatabaseHost::query()->create([ - 'password' => encrypt(array_get($data, 'password')), + 'password' => array_get($data, 'password'), 'name' => array_get($data, 'name'), 'host' => array_get($data, 'host'), 'port' => array_get($data, 'port'), diff --git a/app/Services/Databases/Hosts/HostUpdateService.php b/app/Services/Databases/Hosts/HostUpdateService.php index 16f55dddd..d4975cae0 100644 --- a/app/Services/Databases/Hosts/HostUpdateService.php +++ b/app/Services/Databases/Hosts/HostUpdateService.php @@ -26,9 +26,7 @@ class HostUpdateService */ public function handle(int $hostId, array $data): DatabaseHost { - if (!empty(array_get($data, 'password'))) { - $data['password'] = encrypt($data['password']); - } else { + if (empty(array_get($data, 'password'))) { unset($data['password']); } diff --git a/app/Services/Nodes/NodeCreationService.php b/app/Services/Nodes/NodeCreationService.php index 0c7720d33..1c10b328d 100644 --- a/app/Services/Nodes/NodeCreationService.php +++ b/app/Services/Nodes/NodeCreationService.php @@ -16,7 +16,7 @@ class NodeCreationService public function handle(array $data): Node { $data['uuid'] = Uuid::uuid4()->toString(); - $data['daemon_token'] = encrypt(Str::random(Node::DAEMON_TOKEN_LENGTH)); + $data['daemon_token'] = Str::random(Node::DAEMON_TOKEN_LENGTH); $data['daemon_token_id'] = Str::random(Node::DAEMON_TOKEN_ID_LENGTH); return Node::query()->create($data); diff --git a/app/Services/Nodes/NodeJWTService.php b/app/Services/Nodes/NodeJWTService.php index 0221c5236..325fe04c0 100644 --- a/app/Services/Nodes/NodeJWTService.php +++ b/app/Services/Nodes/NodeJWTService.php @@ -63,7 +63,7 @@ class NodeJWTService public function handle(Node $node, ?string $identifiedBy, string $algo = 'md5'): Plain { $identifier = hash($algo, $identifiedBy); - $config = Configuration::forSymmetricSigner(new Sha256(), InMemory::plainText($node->getDecryptedKey())); + $config = Configuration::forSymmetricSigner(new Sha256(), InMemory::plainText($node->daemon_token)); $builder = $config->builder(new TimestampDates()) ->issuedBy(config('app.url')) diff --git a/app/Services/Nodes/NodeUpdateService.php b/app/Services/Nodes/NodeUpdateService.php index 76d1aadbd..c4f769f8a 100644 --- a/app/Services/Nodes/NodeUpdateService.php +++ b/app/Services/Nodes/NodeUpdateService.php @@ -28,7 +28,7 @@ class NodeUpdateService public function handle(Node $node, array $data, bool $resetToken = false): Node { if ($resetToken) { - $data['daemon_token'] = encrypt(Str::random(Node::DAEMON_TOKEN_LENGTH)); + $data['daemon_token'] = Str::random(Node::DAEMON_TOKEN_LENGTH); $data['daemon_token_id'] = Str::random(Node::DAEMON_TOKEN_ID_LENGTH); } diff --git a/app/Services/Users/ToggleTwoFactorService.php b/app/Services/Users/ToggleTwoFactorService.php index 321643a35..64518e39b 100644 --- a/app/Services/Users/ToggleTwoFactorService.php +++ b/app/Services/Users/ToggleTwoFactorService.php @@ -32,9 +32,7 @@ class ToggleTwoFactorService */ public function handle(User $user, string $token, bool $toggleState = null): array { - $secret = decrypt($user->totp_secret); - - $isValidToken = $this->google2FA->verifyKey($secret, $token, config()->get('panel.auth.2fa.window')); + $isValidToken = $this->google2FA->verifyKey($user->totp_secret, $token, config()->get('panel.auth.2fa.window')); if (!$isValidToken) { throw new TwoFactorAuthenticationTokenInvalid(); diff --git a/app/Services/Users/TwoFactorSetupService.php b/app/Services/Users/TwoFactorSetupService.php index dd1671d64..fb906c9db 100644 --- a/app/Services/Users/TwoFactorSetupService.php +++ b/app/Services/Users/TwoFactorSetupService.php @@ -26,7 +26,7 @@ class TwoFactorSetupService throw new \RuntimeException($exception->getMessage(), 0, $exception); } - $user->totp_secret = encrypt($secret); + $user->totp_secret = $secret; $user->save(); $company = urlencode(preg_replace('/\s/', '', config('app.name'))); diff --git a/app/Transformers/Api/Application/ServerDatabaseTransformer.php b/app/Transformers/Api/Application/ServerDatabaseTransformer.php index 1091dc867..e74cd2586 100644 --- a/app/Transformers/Api/Application/ServerDatabaseTransformer.php +++ b/app/Transformers/Api/Application/ServerDatabaseTransformer.php @@ -45,7 +45,7 @@ class ServerDatabaseTransformer extends BaseTransformer { return $this->item($model, function (Database $model) { return [ - 'password' => decrypt($model->password), + 'password' => $model->password, ]; }, 'database_password'); } diff --git a/app/Transformers/Api/Client/DatabaseTransformer.php b/app/Transformers/Api/Client/DatabaseTransformer.php index 2739ac7ec..2d3077976 100644 --- a/app/Transformers/Api/Client/DatabaseTransformer.php +++ b/app/Transformers/Api/Client/DatabaseTransformer.php @@ -55,7 +55,7 @@ class DatabaseTransformer extends BaseClientTransformer return $this->item($database, function (Database $model) { return [ - 'password' => decrypt($model->password), + 'password' => $model->password, ]; }, 'database_password'); } diff --git a/database/Factories/ApiKeyFactory.php b/database/Factories/ApiKeyFactory.php index bfcb4b98b..3361433b4 100644 --- a/database/Factories/ApiKeyFactory.php +++ b/database/Factories/ApiKeyFactory.php @@ -26,7 +26,7 @@ class ApiKeyFactory extends Factory return [ 'key_type' => ApiKey::TYPE_APPLICATION, 'identifier' => ApiKey::generateTokenIdentifier(ApiKey::TYPE_APPLICATION), - 'token' => $token ?: $token = encrypt(Str::random(ApiKey::KEY_LENGTH)), + 'token' => $token ?: $token = Str::random(ApiKey::KEY_LENGTH), 'allowed_ips' => null, 'memo' => 'Test Function Key', 'created_at' => Carbon::now(), diff --git a/database/Factories/DatabaseFactory.php b/database/Factories/DatabaseFactory.php index 963c52add..d590a0e13 100644 --- a/database/Factories/DatabaseFactory.php +++ b/database/Factories/DatabaseFactory.php @@ -27,7 +27,7 @@ class DatabaseFactory extends Factory 'database' => Str::random(10), 'username' => Str::random(10), 'remote' => '%', - 'password' => $password ?: encrypt('test123'), + 'password' => $password ?: 'test123', 'created_at' => Carbon::now(), 'updated_at' => Carbon::now(), ]; diff --git a/database/Factories/DatabaseHostFactory.php b/database/Factories/DatabaseHostFactory.php index aaf8bbc69..ad76eac44 100644 --- a/database/Factories/DatabaseHostFactory.php +++ b/database/Factories/DatabaseHostFactory.php @@ -3,7 +3,6 @@ namespace Database\Factories; use App\Models\DatabaseHost; -use Illuminate\Support\Facades\Crypt; use Illuminate\Database\Eloquent\Factories\Factory; class DatabaseHostFactory extends Factory @@ -25,7 +24,7 @@ class DatabaseHostFactory extends Factory 'host' => $this->faker->unique()->ipv4(), 'port' => 3306, 'username' => $this->faker->colorName(), - 'password' => Crypt::encrypt($this->faker->word()), + 'password' => $this->faker->word(), ]; } } diff --git a/database/Factories/NodeFactory.php b/database/Factories/NodeFactory.php index 011db38a3..19a1fbf7b 100644 --- a/database/Factories/NodeFactory.php +++ b/database/Factories/NodeFactory.php @@ -5,7 +5,6 @@ namespace Database\Factories; use Ramsey\Uuid\Uuid; use Illuminate\Support\Str; use App\Models\Node; -use Illuminate\Support\Facades\Crypt; use Illuminate\Database\Eloquent\Factories\Factory; class NodeFactory extends Factory @@ -37,7 +36,7 @@ class NodeFactory extends Factory 'cpu_overallocate' => 0, 'upload_size' => 100, 'daemon_token_id' => Str::random(Node::DAEMON_TOKEN_ID_LENGTH), - 'daemon_token' => Crypt::encrypt(Str::random(Node::DAEMON_TOKEN_LENGTH)), + 'daemon_token' => Str::random(Node::DAEMON_TOKEN_LENGTH), 'daemon_listen' => 8080, 'daemon_sftp' => 2022, 'daemon_base' => '/var/lib/panel/volumes', diff --git a/resources/views/admin/api/index.blade.php b/resources/views/admin/api/index.blade.php index 8d848d403..717257187 100644 --- a/resources/views/admin/api/index.blade.php +++ b/resources/views/admin/api/index.blade.php @@ -33,7 +33,7 @@ @foreach($keys as $key) - {{ $key->identifier }}{{ decrypt($key->token) }} + {{ $key->identifier }}{{ $key->token }} {{ $key->memo }} @if(!is_null($key->last_used_at)) diff --git a/resources/views/admin/nodes/index.blade.php b/resources/views/admin/nodes/index.blade.php index 8f003d953..64d7cd033 100644 --- a/resources/views/admin/nodes/index.blade.php +++ b/resources/views/admin/nodes/index.blade.php @@ -49,7 +49,7 @@ @foreach ($nodes as $node) - + {!! $node->maintenance_mode ? ' ' : '' !!}{{ $node->name }} {{ $node->memory }} MiB {{ $node->disk }} MiB diff --git a/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php b/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php index 183b48c39..e4fe09570 100644 --- a/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php +++ b/tests/Integration/Api/Application/ApplicationApiIntegrationTestCase.php @@ -37,7 +37,7 @@ abstract class ApplicationApiIntegrationTestCase extends IntegrationTestCase $this ->withHeader('Accept', 'application/vnd.panel.v1+json') - ->withHeader('Authorization', 'Bearer ' . $this->key->identifier . decrypt($this->key->token)); + ->withHeader('Authorization', 'Bearer ' . $this->key->identifier . $this->key->token); } public function getApiUser(): User @@ -57,7 +57,7 @@ abstract class ApplicationApiIntegrationTestCase extends IntegrationTestCase { $this->key = $this->createApiKey($user, $permissions); - $this->withHeader('Authorization', 'Bearer ' . $this->key->identifier . decrypt($this->key->token)); + $this->withHeader('Authorization', 'Bearer ' . $this->key->identifier . $this->key->token); return $this->key; } diff --git a/tests/Integration/Api/Client/ApiKeyControllerTest.php b/tests/Integration/Api/Client/ApiKeyControllerTest.php index 5e380ad36..462875c59 100644 --- a/tests/Integration/Api/Client/ApiKeyControllerTest.php +++ b/tests/Integration/Api/Client/ApiKeyControllerTest.php @@ -71,7 +71,7 @@ class ApiKeyControllerTest extends ClientApiIntegrationTestCase $key = ApiKey::query()->where('identifier', $response->json('attributes.identifier'))->firstOrFail(); $this->assertJsonTransformedWith($response->json('attributes'), $key); - $response->assertJsonPath('meta.secret_token', decrypt($key->token)); + $response->assertJsonPath('meta.secret_token', $key->token); $this->assertActivityFor('user:api-key.create', $user, [$key, $user]); } diff --git a/tests/Integration/Api/Client/Server/WebsocketControllerTest.php b/tests/Integration/Api/Client/Server/WebsocketControllerTest.php index 6fe802ba1..44d006c7b 100644 --- a/tests/Integration/Api/Client/Server/WebsocketControllerTest.php +++ b/tests/Integration/Api/Client/Server/WebsocketControllerTest.php @@ -62,7 +62,7 @@ class WebsocketControllerTest extends ClientApiIntegrationTestCase $this->assertStringStartsWith('wss://', $connection, 'Failed asserting that websocket connection address has expected "wss://" prefix.'); $this->assertStringEndsWith("/api/servers/$server->uuid/ws", $connection, 'Failed asserting that websocket connection address uses expected Daemon endpoint.'); - $config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->getDecryptedKey())); + $config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->daemon_token)); $config->setValidationConstraints(new SignedWith(new Sha256(), $key)); /** @var \Lcobucci\JWT\Token\Plain $token */ $token = $config->parser()->parse($response->json('data.token')); @@ -107,7 +107,7 @@ class WebsocketControllerTest extends ClientApiIntegrationTestCase $response->assertOk(); $response->assertJsonStructure(['data' => ['token', 'socket']]); - $config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->getDecryptedKey())); + $config = Configuration::forSymmetricSigner(new Sha256(), $key = InMemory::plainText($server->node->daemon_token)); $config->setValidationConstraints(new SignedWith(new Sha256(), $key)); /** @var \Lcobucci\JWT\Token\Plain $token */ $token = $config->parser()->parse($response->json('data.token')); diff --git a/tests/Integration/Api/Client/TwoFactorControllerTest.php b/tests/Integration/Api/Client/TwoFactorControllerTest.php index 39bd3ddc3..24d8a2684 100644 --- a/tests/Integration/Api/Client/TwoFactorControllerTest.php +++ b/tests/Integration/Api/Client/TwoFactorControllerTest.php @@ -85,8 +85,7 @@ class TwoFactorControllerTest extends ClientApiIntegrationTestCase /** @var \PragmaRX\Google2FA\Google2FA $service */ $service = $this->app->make(Google2FA::class); - $secret = decrypt($user->totp_secret); - $token = $service->getCurrentOtp($secret); + $token = $service->getCurrentOtp($user->totp_secret); $response = $this->actingAs($user)->postJson('/api/client/account/two-factor', [ 'code' => $token, diff --git a/tests/Integration/Api/Daemon/DaemonAuthenticateTest.php b/tests/Integration/Api/Daemon/DaemonAuthenticateTest.php index a0eabde89..b18b3e5e8 100644 --- a/tests/Integration/Api/Daemon/DaemonAuthenticateTest.php +++ b/tests/Integration/Api/Daemon/DaemonAuthenticateTest.php @@ -94,7 +94,7 @@ class DaemonAuthenticateTest extends MiddlewareTestCase public function testSuccessfulMiddlewareProcess(): void { $node = Node::factory()->create(); - $node->daemon_token = encrypt('the_same'); + $node->daemon_token = 'the_same'; $node->save(); $this->request->expects('route->getName')->withNoArgs()->andReturn('random.route'); diff --git a/tests/Integration/Api/Remote/SftpAuthenticationControllerTest.php b/tests/Integration/Api/Remote/SftpAuthenticationControllerTest.php index 13eff086b..2affbef73 100644 --- a/tests/Integration/Api/Remote/SftpAuthenticationControllerTest.php +++ b/tests/Integration/Api/Remote/SftpAuthenticationControllerTest.php @@ -229,6 +229,6 @@ class SftpAuthenticationControllerTest extends IntegrationTestCase { $node = $node ?? $this->server->node; - $this->withHeader('Authorization', 'Bearer ' . $node->daemon_token_id . '.' . decrypt($node->daemon_token)); + $this->withHeader('Authorization', 'Bearer ' . $node->daemon_token_id . '.' . $node->daemon_token); } } From 639fa3399df889ba5b5d150a0896dd7947b328cb Mon Sep 17 00:00:00 2001 From: Boy132 Date: Tue, 28 May 2024 15:27:33 +0200 Subject: [PATCH 02/29] run pint --- app/Models/Database.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Database.php b/app/Models/Database.php index 7058ccf26..46a49ca35 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -64,7 +64,7 @@ class Database extends Model 'server_id' => 'integer', 'database_host_id' => 'integer', 'max_connections' => 'integer', - 'password' => 'encrypted' + 'password' => 'encrypted', ]; } From e980877bbce20a88a54beccbf9f9f9d92607dc8d Mon Sep 17 00:00:00 2001 From: notCharles Date: Wed, 29 May 2024 18:28:21 -0400 Subject: [PATCH 03/29] Fix Node Creation Add missing defaults --- app/Filament/Resources/NodeResource/Pages/CreateNode.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Filament/Resources/NodeResource/Pages/CreateNode.php b/app/Filament/Resources/NodeResource/Pages/CreateNode.php index 899e7b3ab..775fe5e9f 100644 --- a/app/Filament/Resources/NodeResource/Pages/CreateNode.php +++ b/app/Filament/Resources/NodeResource/Pages/CreateNode.php @@ -329,6 +329,7 @@ class CreateNode extends CreateRecord true => 'primary', false => 'warning', ]) + ->default(0) ->columnSpan(2), Forms\Components\TextInput::make('cpu') ->dehydratedWhenHidden() @@ -346,6 +347,7 @@ class CreateNode extends CreateRecord ->hintIconTooltip('The % allowable to go over the set limit.') ->columnSpan(2) ->numeric() + ->default(0) ->minValue(-1) ->maxValue(100) ->suffix('%'), From b6e46f758d03f11c7ce944ccafd877d065ced164 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Thu, 30 May 2024 00:41:44 +0200 Subject: [PATCH 04/29] Remove hashids (#282) and close #269 --- .env.example | 3 - .github/workflows/ci.yaml | 2 - .../Environment/AppSettingsCommand.php | 5 -- .../Schedule/ProcessRunnableCommand.php | 2 +- app/Contracts/Extensions/HashidsInterface.php | 15 ---- app/Extensions/Hashids.php | 22 ------ app/Models/Allocation.php | 9 --- app/Models/Database.php | 22 ------ app/Models/Schedule.php | 11 --- app/Models/Subuser.php | 8 -- app/Models/Task.php | 11 --- app/Providers/HashidsServiceProvider.php | 26 ------- app/Providers/RouteServiceProvider.php | 6 -- .../Api/Client/DatabaseTransformer.php | 13 +--- bootstrap/providers.php | 1 - composer.json | 1 - composer.lock | 73 +------------------ config/hashids.php | 15 ---- lang/en/command/messages.php | 2 +- .../Database/DatabaseAuthorizationTest.php | 14 ++-- 20 files changed, 11 insertions(+), 250 deletions(-) delete mode 100644 app/Contracts/Extensions/HashidsInterface.php delete mode 100644 app/Extensions/Hashids.php delete mode 100644 app/Providers/HashidsServiceProvider.php delete mode 100644 config/hashids.php diff --git a/.env.example b/.env.example index eab42b85a..c91d26013 100644 --- a/.env.example +++ b/.env.example @@ -17,9 +17,6 @@ CACHE_STORE=file QUEUE_CONNECTION=database SESSION_DRIVER=file -HASHIDS_SALT= -HASHIDS_LENGTH=8 - MAIL_MAILER=log MAIL_HOST=smtp.example.com MAIL_PORT=25 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bcc56c1a7..998654549 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -34,7 +34,6 @@ jobs: MAIL_MAILER: array SESSION_DRIVER: array QUEUE_CONNECTION: sync - HASHIDS_SALT: alittlebitofsalt1234 DB_CONNECTION: mysql DB_HOST: 127.0.0.1 DB_DATABASE: testing @@ -97,7 +96,6 @@ jobs: MAIL_MAILER: array SESSION_DRIVER: array QUEUE_CONNECTION: sync - HASHIDS_SALT: alittlebitofsalt1234 DB_CONNECTION: sqlite DB_DATABASE: testing.sqlite steps: diff --git a/app/Console/Commands/Environment/AppSettingsCommand.php b/app/Console/Commands/Environment/AppSettingsCommand.php index 8a01437fa..ff75057a3 100644 --- a/app/Console/Commands/Environment/AppSettingsCommand.php +++ b/app/Console/Commands/Environment/AppSettingsCommand.php @@ -32,7 +32,6 @@ class AppSettingsCommand extends Command protected $description = 'Configure basic environment settings for the Panel.'; protected $signature = 'p:environment:setup - {--new-salt : Whether or not to generate a new salt for Hashids.} {--url= : The URL that this Panel is running on.} {--cache= : The cache driver backend to use.} {--session= : The session driver backend to use.} @@ -61,10 +60,6 @@ class AppSettingsCommand extends Command { $this->variables['APP_TIMEZONE'] = 'UTC'; - if (empty(config('hashids.salt')) || $this->option('new-salt')) { - $this->variables['HASHIDS_SALT'] = str_random(20); - } - $this->output->comment(__('commands.appsettings.comment.url')); $this->variables['APP_URL'] = $this->option('url') ?? $this->ask( 'Application URL', diff --git a/app/Console/Commands/Schedule/ProcessRunnableCommand.php b/app/Console/Commands/Schedule/ProcessRunnableCommand.php index 343328cc8..687752a2d 100644 --- a/app/Console/Commands/Schedule/ProcessRunnableCommand.php +++ b/app/Console/Commands/Schedule/ProcessRunnableCommand.php @@ -62,7 +62,7 @@ class ProcessRunnableCommand extends Command $this->line(trans('command/messages.schedule.output_line', [ 'schedule' => $schedule->name, - 'hash' => $schedule->hashid, + 'id' => $schedule->id, ])); } catch (\Throwable|\Exception $exception) { logger()->error($exception, ['schedule_id' => $schedule->id]); diff --git a/app/Contracts/Extensions/HashidsInterface.php b/app/Contracts/Extensions/HashidsInterface.php deleted file mode 100644 index 4f02d0bea..000000000 --- a/app/Contracts/Extensions/HashidsInterface.php +++ /dev/null @@ -1,15 +0,0 @@ -decode($encoded); - if (!is_array($result)) { - return $default; - } - - return array_first($result, null, $default); - } -} diff --git a/app/Models/Allocation.php b/app/Models/Allocation.php index 6a7d45db7..33bc7f16d 100644 --- a/app/Models/Allocation.php +++ b/app/Models/Allocation.php @@ -22,7 +22,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; * @property bool $has_alias * @property \App\Models\Server|null $server * @property \App\Models\Node $node - * @property string $hashid * * @method static \Database\Factories\AllocationFactory factory(...$parameters) * @method static \Illuminate\Database\Eloquent\Builder|Allocation newModelQuery() @@ -88,14 +87,6 @@ class Allocation extends Model return $this->getKeyName(); } - /** - * Return a hashid encoded string to represent the ID of the allocation. - */ - public function getHashidAttribute(): string - { - return app()->make('hashids')->encode($this->id); - } - /** * Accessor to automatically provide the IP alias if defined. */ diff --git a/app/Models/Database.php b/app/Models/Database.php index 6d4fde2f9..99e9a27f8 100644 --- a/app/Models/Database.php +++ b/app/Models/Database.php @@ -2,9 +2,7 @@ namespace App\Models; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use App\Contracts\Extensions\HashidsInterface; use Illuminate\Support\Facades\DB; /** @@ -72,26 +70,6 @@ class Database extends Model return $this->getKeyName(); } - /** - * Resolves the database using the ID by checking if the value provided is a HashID - * string value, or just the ID to the database itself. - * - * @param mixed $value - * @param string|null $field - * - * @throws \Illuminate\Contracts\Container\BindingResolutionException - */ - public function resolveRouteBinding($value, $field = null): ?\Illuminate\Database\Eloquent\Model - { - if (is_scalar($value) && ($field ?? $this->getRouteKeyName()) === 'id') { - $value = ctype_digit((string) $value) - ? $value - : Container::getInstance()->make(HashidsInterface::class)->decodeFirst($value); - } - - return $this->where($field ?? $this->getRouteKeyName(), $value)->firstOrFail(); - } - /** * Gets the host database server associated with a database. */ diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php index 8fb3f4167..7042d25a4 100644 --- a/app/Models/Schedule.php +++ b/app/Models/Schedule.php @@ -4,10 +4,8 @@ namespace App\Models; use Cron\CronExpression; use Carbon\CarbonImmutable; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use App\Contracts\Extensions\HashidsInterface; /** * @property int $id @@ -25,7 +23,6 @@ use App\Contracts\Extensions\HashidsInterface; * @property \Carbon\Carbon|null $next_run_at * @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at - * @property string $hashid * @property \App\Models\Server $server * @property \App\Models\Task[]|\Illuminate\Support\Collection $tasks */ @@ -124,14 +121,6 @@ class Schedule extends Model ); } - /** - * Return a hashid encoded string to represent the ID of the schedule. - */ - public function getHashidAttribute(): string - { - return Container::getInstance()->make(HashidsInterface::class)->encode($this->id); - } - /** * Return tasks belonging to a schedule. */ diff --git a/app/Models/Subuser.php b/app/Models/Subuser.php index 0c1f4d382..566c8a741 100644 --- a/app/Models/Subuser.php +++ b/app/Models/Subuser.php @@ -52,14 +52,6 @@ class Subuser extends Model ]; } - /** - * Return a hashid encoded string to represent the ID of the subuser. - */ - public function getHashidAttribute(): string - { - return app()->make('hashids')->encode($this->id); - } - /** * Gets the server associated with a subuser. */ diff --git a/app/Models/Task.php b/app/Models/Task.php index 591bfcfbb..6545ab5f5 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -2,10 +2,8 @@ namespace App\Models; -use Illuminate\Container\Container; use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use App\Contracts\Extensions\HashidsInterface; /** * @property int $id @@ -18,7 +16,6 @@ use App\Contracts\Extensions\HashidsInterface; * @property bool $continue_on_failure * @property \Carbon\Carbon $created_at * @property \Carbon\Carbon $updated_at - * @property string $hashid * @property \App\Models\Schedule $schedule * @property \App\Models\Server $server */ @@ -96,14 +93,6 @@ class Task extends Model return $this->getKeyName(); } - /** - * Return a hashid encoded string to represent the ID of the task. - */ - public function getHashidAttribute(): string - { - return Container::getInstance()->make(HashidsInterface::class)->encode($this->id); - } - /** * Return the schedule that a task belongs to. */ diff --git a/app/Providers/HashidsServiceProvider.php b/app/Providers/HashidsServiceProvider.php deleted file mode 100644 index 4639bfaed..000000000 --- a/app/Providers/HashidsServiceProvider.php +++ /dev/null @@ -1,26 +0,0 @@ -app->singleton(HashidsInterface::class, function () { - return new Hashids( - config('hashids.salt', ''), - config('hashids.length', 0), - config('hashids.alphabet', 'abcdefghijkmlnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890') - ); - }); - - $this->app->alias(HashidsInterface::class, 'hashids'); - } -} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 449a083c5..432ededc0 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -3,7 +3,6 @@ namespace App\Providers; use Illuminate\Http\Request; -use App\Models\Database; use Illuminate\Foundation\Http\Middleware\TrimStrings; use Illuminate\Support\Facades\Route; use Illuminate\Cache\RateLimiting\Limit; @@ -29,11 +28,6 @@ class RouteServiceProvider extends ServiceProvider return preg_match(self::FILE_PATH_REGEX, $request->getPathInfo()) === 1; }); - // This is needed to make use of the "resolveRouteBinding" functionality in the - // model. Without it you'll never trigger that logic flow thus resulting in a 404 - // error because we request databases with a HashID, and not with a normal ID. - Route::model('database', Database::class); - $this->routes(function () { Route::middleware('web')->group(function () { Route::middleware(['auth.session', RequireTwoFactorAuthentication::class]) diff --git a/app/Transformers/Api/Client/DatabaseTransformer.php b/app/Transformers/Api/Client/DatabaseTransformer.php index 2739ac7ec..71bbb9aba 100644 --- a/app/Transformers/Api/Client/DatabaseTransformer.php +++ b/app/Transformers/Api/Client/DatabaseTransformer.php @@ -6,22 +6,11 @@ use App\Models\Database; use League\Fractal\Resource\Item; use App\Models\Permission; use League\Fractal\Resource\NullResource; -use App\Contracts\Extensions\HashidsInterface; class DatabaseTransformer extends BaseClientTransformer { protected array $availableIncludes = ['password']; - private HashidsInterface $hashids; - - /** - * Handle dependency injection. - */ - public function handle(HashidsInterface $hashids) - { - $this->hashids = $hashids; - } - public function getResourceName(): string { return Database::RESOURCE_NAME; @@ -32,7 +21,7 @@ class DatabaseTransformer extends BaseClientTransformer $model->loadMissing('host'); return [ - 'id' => $this->hashids->encode($model->id), + 'id' => $model->id, 'host' => [ 'address' => $model->getRelation('host')->host, 'port' => $model->getRelation('host')->port, diff --git a/bootstrap/providers.php b/bootstrap/providers.php index 04b20a98c..80be25c8e 100644 --- a/bootstrap/providers.php +++ b/bootstrap/providers.php @@ -6,7 +6,6 @@ return [ App\Providers\BackupsServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\Filament\AdminPanelProvider::class, - App\Providers\HashidsServiceProvider::class, App\Providers\RouteServiceProvider::class, App\Providers\ViewComposerServiceProvider::class, ]; diff --git a/composer.json b/composer.json index 29ef59290..8de5cefc6 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,6 @@ "doctrine/dbal": "~3.6.0", "filament/filament": "^3.2", "guzzlehttp/guzzle": "^7.8.1", - "hashids/hashids": "~5.0.0", "laracasts/utilities": "~3.2.2", "laravel/framework": "^11.7", "laravel/helpers": "^1.7", diff --git a/composer.lock b/composer.lock index 7a8205f17..df5e09434 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dc1c1e5ee766f2e31e84c50670fa0c98", + "content-hash": "e5ad978f95a98d7b1af728ade36c5f0d", "packages": [ { "name": "abdelhamiderrahmouni/filament-monaco-editor", @@ -2613,75 +2613,6 @@ ], "time": "2023-12-03T19:50:20+00:00" }, - { - "name": "hashids/hashids", - "version": "5.0.2", - "source": { - "type": "git", - "url": "https://github.com/vinkla/hashids.git", - "reference": "197171016b77ddf14e259e186559152eb3f8cf33" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vinkla/hashids/zipball/197171016b77ddf14e259e186559152eb3f8cf33", - "reference": "197171016b77ddf14e259e186559152eb3f8cf33", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "suggest": { - "ext-bcmath": "Required to use BC Math arbitrary precision mathematics (*).", - "ext-gmp": "Required to use GNU multiple precision mathematics (*)." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "Hashids\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ivan Akimov", - "email": "ivan@barreleye.com" - }, - { - "name": "Vincent Klaiber", - "email": "hello@doubledip.se" - } - ], - "description": "Generate short, unique, non-sequential ids (like YouTube and Bitly) from numbers", - "homepage": "https://hashids.org/php", - "keywords": [ - "bitly", - "decode", - "encode", - "hash", - "hashid", - "hashids", - "ids", - "obfuscate", - "youtube" - ], - "support": { - "issues": "https://github.com/vinkla/hashids/issues", - "source": "https://github.com/vinkla/hashids/tree/5.0.2" - }, - "time": "2023-02-23T15:00:54+00:00" - }, { "name": "kirschbaum-development/eloquent-power-joins", "version": "3.5.6", @@ -13061,5 +12992,5 @@ "ext-zip": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/config/hashids.php b/config/hashids.php deleted file mode 100644 index 199de1a32..000000000 --- a/config/hashids.php +++ /dev/null @@ -1,15 +0,0 @@ - env('HASHIDS_SALT'), - 'length' => env('HASHIDS_LENGTH', 8), - 'alphabet' => env('HASHIDS_ALPHABET', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'), -]; diff --git a/lang/en/command/messages.php b/lang/en/command/messages.php index 4e640b3fa..50adf0fa3 100644 --- a/lang/en/command/messages.php +++ b/lang/en/command/messages.php @@ -23,7 +23,7 @@ return [ '2fa_disabled' => '2-Factor authentication has been disabled for :email.', ], 'schedule' => [ - 'output_line' => 'Dispatching job for first task in `:schedule` (:hash).', + 'output_line' => 'Dispatching job for first task in `:schedule` (:id).', ], 'maintenance' => [ 'deleting_service_backup' => 'Deleting service backup file :file.', diff --git a/tests/Integration/Api/Client/Server/Database/DatabaseAuthorizationTest.php b/tests/Integration/Api/Client/Server/Database/DatabaseAuthorizationTest.php index 0b3b88cd9..b95778104 100644 --- a/tests/Integration/Api/Client/Server/Database/DatabaseAuthorizationTest.php +++ b/tests/Integration/Api/Client/Server/Database/DatabaseAuthorizationTest.php @@ -5,7 +5,6 @@ namespace App\Tests\Integration\Api\Client\Server\Database; use App\Models\Subuser; use App\Models\Database; use App\Models\DatabaseHost; -use App\Contracts\Extensions\HashidsInterface; use App\Services\Databases\DatabasePasswordService; use App\Services\Databases\DatabaseManagementService; use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase; @@ -39,23 +38,22 @@ class DatabaseAuthorizationTest extends ClientApiIntegrationTestCase ->expects($method === 'POST' ? 'handle' : 'delete') ->andReturn($method === 'POST' ? 'foo' : null); - $hashids = $this->app->make(HashidsInterface::class); // This is the only valid call for this test, accessing the database for the same // server that the API user is the owner of. - $this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $hashids->encode($database1->id) . $endpoint)) + $this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $database1->id . $endpoint)) ->assertStatus($method === 'DELETE' ? 204 : 200); // This request fails because the database is valid for that server but the user // making the request is not authorized to perform that action. - $this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $hashids->encode($database2->id) . $endpoint))->assertForbidden(); + $this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $database2->id . $endpoint))->assertForbidden(); // Both of these should report a 404 error due to the database being linked to // servers that are not the same as the server in the request, or are assigned // to a server for which the user making the request has no access to. - $this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $hashids->encode($database2->id) . $endpoint))->assertNotFound(); - $this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $hashids->encode($database3->id) . $endpoint))->assertNotFound(); - $this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $hashids->encode($database3->id) . $endpoint))->assertNotFound(); - $this->actingAs($user)->json($method, $this->link($server3, '/databases/' . $hashids->encode($database3->id) . $endpoint))->assertNotFound(); + $this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $database2->id . $endpoint))->assertNotFound(); + $this->actingAs($user)->json($method, $this->link($server1, '/databases/' . $database3->id . $endpoint))->assertNotFound(); + $this->actingAs($user)->json($method, $this->link($server2, '/databases/' . $database3->id . $endpoint))->assertNotFound(); + $this->actingAs($user)->json($method, $this->link($server3, '/databases/' . $database3->id . $endpoint))->assertNotFound(); } public static function methodDataProvider(): array From 5760e72b8f9af4ea6d812a39c4dac8bc31267826 Mon Sep 17 00:00:00 2001 From: Senna <62171904+Poseidon281@users.noreply.github.com> Date: Thu, 30 May 2024 00:51:45 +0200 Subject: [PATCH 05/29] Added 2 badges (#296) --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 192c2c3dd..b737a25aa 100644 --- a/readme.md +++ b/readme.md @@ -2,6 +2,10 @@ # Pelican Panel +![Total Downloads](https://img.shields.io/github/downloads/pelican-dev/panel/total?style=flat&label=Total%20Downloads&labelColor=rgba(0%2C%2070%2C%20114%2C%201)&color=rgba(255%2C%20255%2C%20255%2C%201)) +![Latest Release](https://img.shields.io/github/v/release/pelican-dev/panel?style=flat&label=Latest%20Release&labelColor=rgba(0%2C%2070%2C%20114%2C%201)&color=rgba(255%2C%20255%2C%20255%2C%201)) + + Pelican Panel is an open-source, web-based application designed for easy management of game servers. It offers a user-friendly interface for deploying, configuring, and managing servers, with features like real-time resource monitoring, Docker container isolation, and extensive customization options. Ideal for both individual gamers and hosting companies, it simplifies server administration without requiring deep technical knowledge. From 7674ee0e2b91aa6c7037264a64860aee03ee2621 Mon Sep 17 00:00:00 2001 From: Exotical Date: Thu, 30 May 2024 00:54:07 +0200 Subject: [PATCH 06/29] Make deploy.locations optional in the api (#295) --- .../Requests/Api/Application/Servers/StoreServerRequest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php index fd735edf0..263b7c540 100644 --- a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php +++ b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php @@ -56,11 +56,10 @@ class StoreServerRequest extends ApplicationApiRequest // Automatic deployment rules 'deploy' => 'sometimes|required|array', 'deploy.locations' => 'array', - 'deploy.locations.*' => 'integer|min:1', + 'deploy.locations.*' => 'required_with:deploy.locations,integer|min:1', 'deploy.dedicated_ip' => 'required_with:deploy,boolean', 'deploy.port_range' => 'array', 'deploy.port_range.*' => 'string', - 'start_on_completion' => 'sometimes|boolean', ]; } From f6325c07c4dddc8d133c0283f2a3e3cc86072d6e Mon Sep 17 00:00:00 2001 From: Boy132 Date: Thu, 30 May 2024 00:57:30 +0200 Subject: [PATCH 07/29] Fix overallocation `-1` and close #268 (#283) --- .../Nodes/NodeDeploymentController.php | 2 +- app/Models/Node.php | 29 ++++++++++++++----- .../Deployment/FindViableNodesService.php | 8 ++--- .../Servers/ServerCreationService.php | 2 +- .../Servers/TransferServerService.php | 4 ++- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php b/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php index f00c8d667..7a16fab01 100644 --- a/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php +++ b/app/Http/Controllers/Api/Application/Nodes/NodeDeploymentController.php @@ -24,8 +24,8 @@ class NodeDeploymentController extends ApplicationApiController $data = $request->validated(); $nodes = $this->viableNodesService->handle( - $data['disk'] ?? 0, $data['memory'] ?? 0, + $data['disk'] ?? 0, $data['cpu'] ?? 0, $data['tags'] ?? $data['location_ids'] ?? [], ); diff --git a/app/Models/Node.php b/app/Models/Node.php index c693c5b0d..8f1c42bdb 100644 --- a/app/Models/Node.php +++ b/app/Models/Node.php @@ -63,10 +63,6 @@ class Node extends Model */ protected $hidden = ['daemon_token_id', 'daemon_token']; - public int $sum_memory; - public int $sum_disk; - public int $sum_cpu; - /** * Fields that are mass assignable. */ @@ -250,11 +246,28 @@ class Node extends Model */ public function isViable(int $memory, int $disk, int $cpu): bool { - $memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100)); - $diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100)); - $cpuLimit = $this->cpu * (1 + ($this->cpu_overallocate / 100)); + if ($this->memory_overallocate >= 0) { + $memoryLimit = $this->memory * (1 + ($this->memory_overallocate / 100)); + if ($this->servers_sum_memory + $memory > $memoryLimit) { + return false; + } + } - return ($this->sum_memory + $memory) <= $memoryLimit && ($this->sum_disk + $disk) <= $diskLimit && ($this->sum_cpu + $cpu) <= $cpuLimit; + if ($this->disk_overallocate >= 0) { + $diskLimit = $this->disk * (1 + ($this->disk_overallocate / 100)); + if ($this->servers_sum_disk + $disk > $diskLimit) { + return false; + } + } + + if ($this->cpu_overallocate >= 0) { + $cpuLimit = $this->cpu * (1 + ($this->cpu_overallocate / 100)); + if ($this->servers_sum_cpu + $cpu > $cpuLimit) { + return false; + } + } + + return true; } public static function getForServerCreation() diff --git a/app/Services/Deployment/FindViableNodesService.php b/app/Services/Deployment/FindViableNodesService.php index 9a51d1c6f..4cffc71d2 100644 --- a/app/Services/Deployment/FindViableNodesService.php +++ b/app/Services/Deployment/FindViableNodesService.php @@ -17,19 +17,17 @@ class FindViableNodesService * are tossed out, as are any nodes marked as non-public, meaning automatic * deployments should not be done against them. */ - public function handle(int $disk = 0, int $memory = 0, int $cpu = 0, $tags = []): Collection + public function handle(int $memory = 0, int $disk = 0, int $cpu = 0, $tags = []): Collection { $nodes = Node::query() - ->withSum('servers', 'disk') ->withSum('servers', 'memory') + ->withSum('servers', 'disk') ->withSum('servers', 'cpu') ->where('public', true) ->get(); return $nodes ->filter(fn (Node $node) => !$tags || collect($node->tags)->intersect($tags)) - ->filter(fn (Node $node) => $node->servers_sum_disk + $disk <= $node->disk * (1 + $node->disk_overallocate / 100)) - ->filter(fn (Node $node) => $node->servers_sum_memory + $memory <= $node->memory * (1 + $node->memory_overallocate / 100)) - ->filter(fn (Node $node) => $node->servers_sum_cpu + $cpu <= $node->cpu * (1 + $node->cpu_overallocate / 100)); + ->filter(fn (Node $node) => $node->isViable($memory, $disk, $cpu)); } } diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index 8953b1325..57d8ad086 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -109,8 +109,8 @@ class ServerCreationService { /** @var Collection<\App\Models\Node> $nodes */ $nodes = $this->findViableNodesService->handle( - Arr::get($data, 'disk', 0), Arr::get($data, 'memory', 0), + Arr::get($data, 'disk', 0), Arr::get($data, 'cpu', 0), Arr::get($data, 'tags', []), ); diff --git a/app/Services/Servers/TransferServerService.php b/app/Services/Servers/TransferServerService.php index 2cc34db70..72bac7dda 100644 --- a/app/Services/Servers/TransferServerService.php +++ b/app/Services/Servers/TransferServerService.php @@ -58,7 +58,9 @@ class TransferServerService // Check if the node is viable for the transfer. $node = Node::query() ->select(['nodes.id', 'nodes.fqdn', 'nodes.scheme', 'nodes.daemon_token', 'nodes.daemon_listen', 'nodes.memory', 'nodes.disk', 'nodes.cpu', 'nodes.memory_overallocate', 'nodes.disk_overallocate', 'nodes.cpu_overallocate']) - ->selectRaw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk, IFNULL(SUM(servers.cpu), 0) as sum_cpu') + ->withSum('servers', 'disk') + ->withSum('servers', 'memory') + ->withSum('servers', 'cpu') ->leftJoin('servers', 'servers.node_id', '=', 'nodes.id') ->where('nodes.id', $node_id) ->first(); From 8ecabef6b581a244d2ba9aa840eaded9ccf9f7bf Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Wed, 29 May 2024 19:24:02 -0400 Subject: [PATCH 08/29] Add customization --- app/Providers/Filament/AdminPanelProvider.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Providers/Filament/AdminPanelProvider.php b/app/Providers/Filament/AdminPanelProvider.php index 575fa500b..60339c744 100644 --- a/app/Providers/Filament/AdminPanelProvider.php +++ b/app/Providers/Filament/AdminPanelProvider.php @@ -35,11 +35,13 @@ class AdminPanelProvider extends PanelProvider ->default() ->id('admin') ->path('admin') - ->topNavigation(config('panel.filament.top-navigation', false)) + ->topNavigation(config('panel.filament.top-navigation', true)) ->login() ->homeUrl('/') - ->favicon('/pelican.ico') - ->brandName('Pelican') + ->favicon(config('app.favicon', '/pelican.ico')) + ->brandName(config('app.name', 'Pelican')) + ->brandLogo(config('app.logo')) + ->brandLogoHeight('2rem') ->profile(EditProfile::class, false) ->colors([ 'danger' => Color::Red, From aa82c6dd047fdc2d15ce354f17270eef4fb24828 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 01:20:25 -0400 Subject: [PATCH 09/29] Update this --- app/Exceptions/DisplayException.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Exceptions/DisplayException.php b/app/Exceptions/DisplayException.php index 9c7927a43..6c44c356c 100644 --- a/app/Exceptions/DisplayException.php +++ b/app/Exceptions/DisplayException.php @@ -48,7 +48,7 @@ class DisplayException extends PanelException implements HttpExceptionInterface */ public function render(Request $request) { - if (str($request->url())->contains('livewire')) { + if ($request->is('livewire/update')) { Notification::make() ->title(static::class) ->body($this->getMessage()) From ef1a208b95b392b97464e3e5c9ef146a27047b15 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 01:26:28 -0400 Subject: [PATCH 10/29] Add 2fa setup --- .../UserResource/Pages/EditProfile.php | 61 ++++++++++++++++++- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index 7fe5728cf..386e30122 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -2,10 +2,12 @@ namespace App\Filament\Resources\UserResource\Pages; +use App\Exceptions\Service\User\TwoFactorAuthenticationTokenInvalid; use App\Facades\Activity; use App\Models\ActivityLog; use App\Models\ApiKey; use App\Models\User; +use App\Services\Users\ToggleTwoFactorService; use App\Services\Users\TwoFactorSetupService; use chillerlan\QRCode\Common\EccLevel; use chillerlan\QRCode\Common\Version; @@ -22,6 +24,7 @@ use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\Tabs\Tab; use Filament\Forms\Components\TextInput; use Filament\Forms\Get; +use Filament\Notifications\Notification; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\Hash; use Illuminate\Support\HtmlString; @@ -99,12 +102,20 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile if ($this->getUser()->use_totp) { return [ - Placeholder::make('2FA already enabled!'), + Placeholder::make('2fa-already-enabled') + ->label('Two Factor Authentication is currently enabled!'), + TextInput::make('2fa-disable-code') + ->label('Disable 2FA') + ->helperText('Enter your current 2FA code to disable Two Factor Authentication'), ]; } $setupService = app(TwoFactorSetupService::class); - ['image_url_data' => $url] = $setupService->handle($this->getUser()); + ['image_url_data' => $url, 'secret' => $secret] = cache()->remember( + 'current-two-factor-state', + now()->addMinutes(5), fn () => + $setupService->handle($this->getUser()) + ); $options = new QROptions([ 'svgLogo' => public_path('pelican.svg'), @@ -149,7 +160,15 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile ->content(fn () => new HtmlString("
$image
")) - ->default('asdfasdf'), + ->helperText($secret), + TextInput::make('2facode') + ->requiredWith('2fapassword') + ->helperText('Scan the QR code above using your two-step authentication app, then enter the code generated.'), + TextInput::make('2fapassword') + ->requiredWith('2facode') + ->currentPassword() + ->password() + ->helperText('Enter your current password to verify.'), ]; }), @@ -235,4 +254,40 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile ), ]; } + + protected function handleRecordUpdate($record, $data): \Illuminate\Database\Eloquent\Model + { + if ($token = $data['2facode'] ?? null) { + /** @var ToggleTwoFactorService $service */ + $service = resolve(ToggleTwoFactorService::class); + + $service->handle($record, $token, true); + } + + if ($token = $data['2fa-disable-code'] ?? null) { + /** @var ToggleTwoFactorService $service */ + $service = resolve(ToggleTwoFactorService::class); + + $service->handle($record, $token, false); + + cache()->forget('current-two-factor-state'); + } + + return parent::handleRecordUpdate($record, $data); + } + + public function exception($e, $stopPropagation): void + { + if ($e instanceof TwoFactorAuthenticationTokenInvalid) { + Notification::make() + ->title('Invalid 2FA Code') + ->body($e->getMessage()) + ->color('danger') + ->icon('tabler-2fa') + ->danger() + ->send(); + + $stopPropagation(); + } + } } From 7657364208d0f792d7dbf03b60f6bbe68a36b6b9 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 01:38:32 -0400 Subject: [PATCH 11/29] Cache per user and show backup tokens temporarily --- .../Resources/UserResource/Pages/EditProfile.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index 386e30122..8f6170be5 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -104,6 +104,11 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile return [ Placeholder::make('2fa-already-enabled') ->label('Two Factor Authentication is currently enabled!'), + Placeholder::make('backup-tokens') + ->hidden(fn () => !cache()->get("users.{$this->getUser()->id}.2fa.tokens")) + ->helperText(cache()->get("users.{$this->getUser()->id}.2fa.tokens") . + ' - these will not be shown again!') + ->label("Backup Tokens:"), TextInput::make('2fa-disable-code') ->label('Disable 2FA') ->helperText('Enter your current 2FA code to disable Two Factor Authentication'), @@ -112,7 +117,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile $setupService = app(TwoFactorSetupService::class); ['image_url_data' => $url, 'secret' => $secret] = cache()->remember( - 'current-two-factor-state', + "users.{$this->getUser()->id}.2fa.state", now()->addMinutes(5), fn () => $setupService->handle($this->getUser()) ); @@ -261,7 +266,8 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile /** @var ToggleTwoFactorService $service */ $service = resolve(ToggleTwoFactorService::class); - $service->handle($record, $token, true); + $tokens = $service->handle($record, $token, true); + cache()->set("users.$record->id.2fa.tokens", implode("\n", $tokens), now()->addSeconds(15)); } if ($token = $data['2fa-disable-code'] ?? null) { @@ -270,7 +276,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile $service->handle($record, $token, false); - cache()->forget('current-two-factor-state'); + cache()->forget("users.$record->id.2fa.state"); } return parent::handleRecordUpdate($record, $data); From 97ac0fe54b5dffa9c84acddf97c79e316c25b0c3 Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 31 May 2024 01:41:21 -0400 Subject: [PATCH 12/29] Add Reset Daemon Key Button (#298) closes #292 --- .../Resources/NodeResource/Pages/EditNode.php | 14 ++++++++++++++ app/Services/Nodes/NodeUpdateService.php | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/Filament/Resources/NodeResource/Pages/EditNode.php b/app/Filament/Resources/NodeResource/Pages/EditNode.php index a5126f694..ca0ac657f 100644 --- a/app/Filament/Resources/NodeResource/Pages/EditNode.php +++ b/app/Filament/Resources/NodeResource/Pages/EditNode.php @@ -6,9 +6,11 @@ use App\Filament\Resources\NodeResource; use App\Filament\Resources\NodeResource\Widgets\NodeMemoryChart; use App\Filament\Resources\NodeResource\Widgets\NodeStorageChart; use App\Models\Node; +use App\Services\Nodes\NodeUpdateService; use Filament\Actions; use Filament\Forms; use Filament\Forms\Components\Tabs; +use Filament\Notifications\Notification; use Filament\Resources\Pages\EditRecord; use Illuminate\Support\HtmlString; use Webbingbrasil\FilamentCopyActions\Forms\Actions\CopyAction; @@ -374,6 +376,18 @@ class EditNode extends EditRecord ->rows(19) ->hintAction(CopyAction::make()) ->columnSpanFull(), + Forms\Components\Actions::make([ + Forms\Components\Actions\Action::make('resetKey') + ->label('Reset Daemon Token') + ->color('danger') + ->requiresConfirmation() + ->modalHeading('Reset Daemon Token?') + ->modalDescription('Resetting the daemon token will void any request coming from the old token. This token is used for all sensitive operations on the daemon including server creation and deletion. We suggest changing this token regularly for security.') + ->action(fn (NodeUpdateService $nodeUpdateService, Node $node) => $nodeUpdateService->handle($node, [], true) + && Notification::make()->success()->title('Daemon Key Reset')->send() + && $this->fillForm() + ), + ]), ]), ]), ]); diff --git a/app/Services/Nodes/NodeUpdateService.php b/app/Services/Nodes/NodeUpdateService.php index 76d1aadbd..c76353d33 100644 --- a/app/Services/Nodes/NodeUpdateService.php +++ b/app/Services/Nodes/NodeUpdateService.php @@ -34,8 +34,8 @@ class NodeUpdateService [$updated, $exception] = $this->connection->transaction(function () use ($data, $node) { /** @var \App\Models\Node $updated */ - $updated = $node->replicate()->forceFill($data)->save(); - + $updated = $node->replicate(); + $updated->forceFill($data)->save(); try { // If we're changing the FQDN for the node, use the newly provided FQDN for the connection // address. This should alleviate issues where the node gets pointed to a "valid" FQDN that From 5519931ee53e4022915b446bd6a898cb67d39a90 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 01:42:02 -0400 Subject: [PATCH 13/29] Pint --- app/Filament/Resources/UserResource/Pages/EditProfile.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index 8f6170be5..4b7c22b5d 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -108,7 +108,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile ->hidden(fn () => !cache()->get("users.{$this->getUser()->id}.2fa.tokens")) ->helperText(cache()->get("users.{$this->getUser()->id}.2fa.tokens") . ' - these will not be shown again!') - ->label("Backup Tokens:"), + ->label('Backup Tokens:'), TextInput::make('2fa-disable-code') ->label('Disable 2FA') ->helperText('Enter your current 2FA code to disable Two Factor Authentication'), @@ -118,8 +118,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile ['image_url_data' => $url, 'secret' => $secret] = cache()->remember( "users.{$this->getUser()->id}.2fa.state", - now()->addMinutes(5), fn () => - $setupService->handle($this->getUser()) + now()->addMinutes(5), fn () => $setupService->handle($this->getUser()) ); $options = new QROptions([ From 8cec7368ab9f7e34bda3949cd3a4719a6294a705 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 01:59:33 -0400 Subject: [PATCH 14/29] Only show application api keys --- .../ApiKeyResource/Pages/CreateApiKey.php | 20 +++---------------- .../ApiKeyResource/Pages/ListApiKeys.php | 19 +----------------- 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php b/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php index e8abde957..1922d95cc 100644 --- a/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php +++ b/app/Filament/Resources/ApiKeyResource/Pages/CreateApiKey.php @@ -25,24 +25,10 @@ class CreateApiKey extends CreateRecord ->default(auth()->user()->id) ->required(), - Forms\Components\Select::make('key_type') + Forms\Components\Hidden::make('key_type') ->inlineLabel() - ->options(function (ApiKey $apiKey) { - $originalOptions = [ - //ApiKey::TYPE_NONE => 'None', - ApiKey::TYPE_ACCOUNT => 'Account', - ApiKey::TYPE_APPLICATION => 'Application', - //ApiKey::TYPE_DAEMON_USER => 'Daemon User', - //ApiKey::TYPE_DAEMON_APPLICATION => 'Daemon Application', - ]; - - return collect($originalOptions) - ->filter(fn ($value, $key) => $key <= ApiKey::TYPE_APPLICATION || $apiKey->key_type === $key) - ->all(); - }) - ->selectablePlaceholder(false) - ->required() - ->default(ApiKey::TYPE_APPLICATION), + ->default(ApiKey::TYPE_APPLICATION) + ->required(), Forms\Components\Fieldset::make('Permissions') ->columns([ diff --git a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php index 0932848eb..f297f0220 100644 --- a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php +++ b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php @@ -19,6 +19,7 @@ class ListApiKeys extends ListRecords { return $table ->searchable(false) + ->modifyQueryUsing(fn ($query) => $query->where('key_type', ApiKey::TYPE_APPLICATION)) ->columns([ Tables\Columns\TextColumn::make('user.username') ->hidden() @@ -64,22 +65,4 @@ class ListApiKeys extends ListRecords Actions\CreateAction::make(), ]; } - - public function getTabs(): array - { - return [ - 'all' => Tab::make('All Keys'), - 'application' => Tab::make('Application Keys') - ->modifyQueryUsing(fn (Builder $query) => $query->where('key_type', ApiKey::TYPE_APPLICATION) - ), - 'account' => Tab::make('Account Keys') - ->modifyQueryUsing(fn (Builder $query) => $query->where('key_type', ApiKey::TYPE_ACCOUNT) - ), - ]; - } - - public function getDefaultActiveTab(): string|int|null - { - return 'application'; - } } From 7d0ce1627b9ff1c90afc5cde6a0a5263373eb35d Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 02:00:38 -0400 Subject: [PATCH 15/29] Remove unused imports --- app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php index f297f0220..b64e0f4f8 100644 --- a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php +++ b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php @@ -5,10 +5,8 @@ namespace App\Filament\Resources\ApiKeyResource\Pages; use App\Filament\Resources\ApiKeyResource; use App\Models\ApiKey; use Filament\Actions; -use Filament\Resources\Components\Tab; use Filament\Resources\Pages\ListRecords; use Filament\Tables\Table; -use Illuminate\Database\Eloquent\Builder; use Filament\Tables; class ListApiKeys extends ListRecords From 957638d4ac03f86a1c52a0a989c7336833e231ab Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 15:14:22 -0400 Subject: [PATCH 16/29] Fill previously existing egg --- app/Services/Eggs/Sharing/EggImporterService.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Services/Eggs/Sharing/EggImporterService.php b/app/Services/Eggs/Sharing/EggImporterService.php index 0a949474f..7ed7f010a 100644 --- a/app/Services/Eggs/Sharing/EggImporterService.php +++ b/app/Services/Eggs/Sharing/EggImporterService.php @@ -26,8 +26,11 @@ class EggImporterService $parsed = $this->parser->handle($file); return $this->connection->transaction(function () use ($parsed) { - $egg = (new Egg())->forceFill([ - 'uuid' => Uuid::uuid4()->toString(), + $uuid = $parsed['uuid'] ?? Uuid::uuid4()->toString(); + $egg = Egg::where('uuid', $uuid)->first() ?? new Egg(); + + $egg = $egg->forceFill([ + 'uuid' => $uuid, 'author' => Arr::get($parsed, 'author'), 'copy_script_from' => null, ]); From 065f3f246803fbfa8517559f82c35d43cb426679 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 15:18:04 -0400 Subject: [PATCH 17/29] Activity log fix #257 --- app/Transformers/Api/Client/ActivityLogTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Transformers/Api/Client/ActivityLogTransformer.php b/app/Transformers/Api/Client/ActivityLogTransformer.php index af666beb6..d02f95988 100644 --- a/app/Transformers/Api/Client/ActivityLogTransformer.php +++ b/app/Transformers/Api/Client/ActivityLogTransformer.php @@ -55,7 +55,7 @@ class ActivityLogTransformer extends BaseClientTransformer $properties = $model->properties ->mapWithKeys(function ($value, $key) use ($model) { - if ($key === 'ip' && !$model->actor->is($this->request->user())) { + if ($key === 'ip' && $model->actor && !$model->actor->is($this->request->user())) { return [$key => '[hidden]']; } From 264d3498a663f87abc7ea7ab3a675d8e2ac5cdf5 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 15:44:21 -0400 Subject: [PATCH 18/29] Allow mailgun to work #257 --- composer.json | 3 +- composer.lock | 186 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 181 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 8de5cefc6..407c79890 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ "s1lentium/iptools": "~1.2.0", "spatie/laravel-fractal": "^6.2", "spatie/laravel-query-builder": "^5.8.1", - "symfony/mailgun-mailer": "^7.0.7", + "symfony/http-client": "^7.1", + "symfony/mailgun-mailer": "^7.1", "symfony/postmark-mailer": "^7.0.7", "symfony/yaml": "^7.0.7", "webbingbrasil/filament-copyactions": "^3.0.1", diff --git a/composer.lock b/composer.lock index df5e09434..d92e3bd6f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e5ad978f95a98d7b1af728ade36c5f0d", + "content-hash": "328bdd29cb83793ec0a99b2210941740", "packages": [ { "name": "abdelhamiderrahmouni/filament-monaco-editor", @@ -7653,6 +7653,178 @@ ], "time": "2024-04-18T09:29:19+00:00" }, + { + "name": "symfony/http-client", + "version": "v7.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "2266f9813ed7d8c84e04627edead7b7fd249d6e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/2266f9813ed7d8c84e04627edead7b7fd249d6e9", + "reference": "2266f9813ed7d8c84e04627edead7b7fd249d6e9", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "^3.4.1", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/amp": "^2.5", + "amphp/http-client": "^4.2.1", + "amphp/http-tunnel": "^1.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v7.1.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-13T15:35:37+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "20414d96f391677bf80078aa55baece78b82647d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", + "reference": "20414d96f391677bf80078aa55baece78b82647d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-04-18T09:32:20+00:00" + }, { "name": "symfony/http-foundation", "version": "v7.0.7", @@ -7925,16 +8097,16 @@ }, { "name": "symfony/mailgun-mailer", - "version": "v7.0.7", + "version": "v7.1.0", "source": { "type": "git", "url": "https://github.com/symfony/mailgun-mailer.git", - "reference": "e9bb8fdbdd79334a8a88bdd233204315abd992c5" + "reference": "aa5afbe846bbc8bde6afe2602f0427834b872f55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/e9bb8fdbdd79334a8a88bdd233204315abd992c5", - "reference": "e9bb8fdbdd79334a8a88bdd233204315abd992c5", + "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/aa5afbe846bbc8bde6afe2602f0427834b872f55", + "reference": "aa5afbe846bbc8bde6afe2602f0427834b872f55", "shasum": "" }, "require": { @@ -7974,7 +8146,7 @@ "description": "Symfony Mailgun Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailgun-mailer/tree/v7.0.7" + "source": "https://github.com/symfony/mailgun-mailer/tree/v7.1.0" }, "funding": [ { @@ -7990,7 +8162,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/mime", From cfe385f53a0442a8fd2ef4105e9fd6519315b4bd Mon Sep 17 00:00:00 2001 From: notCharles Date: Fri, 31 May 2024 16:01:15 -0400 Subject: [PATCH 19/29] Add uuid to egg exproter Add UUID to egg exporter. --- app/Services/Eggs/Sharing/EggExporterService.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Services/Eggs/Sharing/EggExporterService.php b/app/Services/Eggs/Sharing/EggExporterService.php index e3a561db2..19c9a5e12 100644 --- a/app/Services/Eggs/Sharing/EggExporterService.php +++ b/app/Services/Eggs/Sharing/EggExporterService.php @@ -25,6 +25,7 @@ class EggExporterService 'exported_at' => Carbon::now()->toAtomString(), 'name' => $egg->name, 'author' => $egg->author, + 'uuid' => $egg->uuid, 'description' => $egg->description, 'features' => $egg->features, 'docker_images' => $egg->docker_images, From 8eb2c23420dd093ae6a6774f4559481821150351 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 16:03:12 -0400 Subject: [PATCH 20/29] Fix creating new node --- app/Filament/Resources/NodeResource/Pages/CreateNode.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Filament/Resources/NodeResource/Pages/CreateNode.php b/app/Filament/Resources/NodeResource/Pages/CreateNode.php index 775fe5e9f..1d506083e 100644 --- a/app/Filament/Resources/NodeResource/Pages/CreateNode.php +++ b/app/Filament/Resources/NodeResource/Pages/CreateNode.php @@ -329,7 +329,6 @@ class CreateNode extends CreateRecord true => 'primary', false => 'warning', ]) - ->default(0) ->columnSpan(2), Forms\Components\TextInput::make('cpu') ->dehydratedWhenHidden() @@ -338,6 +337,7 @@ class CreateNode extends CreateRecord ->suffix('%') ->columnSpan(2) ->numeric() + ->default(0) ->minValue(0), Forms\Components\TextInput::make('cpu_overallocate') ->dehydratedWhenHidden() From 5081cc3f63b1b4023ac2a01a042ce953ec1af0fb Mon Sep 17 00:00:00 2001 From: notCharles Date: Fri, 31 May 2024 16:39:23 -0400 Subject: [PATCH 21/29] Fix badge, update table --- app/Filament/Resources/ApiKeyResource.php | 18 +----------------- .../ApiKeyResource/Pages/ListApiKeys.php | 14 +++++--------- .../UserResource/Pages/EditProfile.php | 5 +++-- 3 files changed, 9 insertions(+), 28 deletions(-) diff --git a/app/Filament/Resources/ApiKeyResource.php b/app/Filament/Resources/ApiKeyResource.php index b4bea3352..0d7817cd9 100644 --- a/app/Filament/Resources/ApiKeyResource.php +++ b/app/Filament/Resources/ApiKeyResource.php @@ -4,9 +4,7 @@ namespace App\Filament\Resources; use App\Filament\Resources\ApiKeyResource\Pages; use App\Models\ApiKey; -use Filament\Resources\Components\Tab; use Filament\Resources\Resource; -use Illuminate\Database\Eloquent\Builder; class ApiKeyResource extends Resource { @@ -16,7 +14,7 @@ class ApiKeyResource extends Resource public static function getNavigationBadge(): ?string { - return static::getModel()::count() ?: null; + return static::getModel()::where('key_type', '2')->count() ?: null; } public static function canEdit($record): bool @@ -24,20 +22,6 @@ class ApiKeyResource extends Resource return false; } - public function getTabs(): array - { - return [ - 'all' => Tab::make('All Keys'), - 'application' => Tab::make('Application Keys') - ->modifyQueryUsing(fn (Builder $query) => $query->where('key_type', ApiKey::TYPE_APPLICATION)), - ]; - } - - public function getDefaultActiveTab(): string|int|null - { - return 'application'; - } - public static function getRelations(): array { return [ diff --git a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php index b64e0f4f8..f55422299 100644 --- a/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php +++ b/app/Filament/Resources/ApiKeyResource/Pages/ListApiKeys.php @@ -19,11 +19,6 @@ class ListApiKeys extends ListRecords ->searchable(false) ->modifyQueryUsing(fn ($query) => $query->where('key_type', ApiKey::TYPE_APPLICATION)) ->columns([ - Tables\Columns\TextColumn::make('user.username') - ->hidden() - ->searchable() - ->sortable(), - Tables\Columns\TextColumn::make('key') ->copyable() ->icon('tabler-clipboard-text') @@ -40,6 +35,7 @@ class ListApiKeys extends ListRecords Tables\Columns\TextColumn::make('last_used_at') ->label('Last Used') + ->placeholder('Not Used') ->dateTime() ->sortable(), @@ -47,13 +43,13 @@ class ListApiKeys extends ListRecords ->label('Created') ->dateTime() ->sortable(), - ]) - ->filters([ - // + + Tables\Columns\TextColumn::make('user.username') + ->label('Created By') + ->url(fn (ApiKey $apiKey): string => route('filament.admin.resources.users.edit', ['record' => $apiKey->user])), ]) ->actions([ Tables\Actions\DeleteAction::make(), - //Tables\Actions\EditAction::make() ]); } diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index 7fe5728cf..1d86f4f02 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -158,7 +158,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile ->schema([ Grid::make('asdf')->columns(5)->schema([ Section::make('Create API Key')->columnSpan(3)->schema([ - TextInput::make('description'), + TextInput::make('description')->required(), TagsInput::make('allowed_ips') ->splitKeys([',', ' ', 'Tab']) ->placeholder('Example: 127.0.0.1 or 192.168.1.1') @@ -182,8 +182,9 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile $action->success(); }), ]), - Section::make('API Keys')->columnSpan(2)->schema([ + Section::make('Keys')->columnSpan(2)->schema([ Repeater::make('keys') + ->label('') ->relationship('apiKeys') ->addable(false) ->itemLabel(fn ($state) => $state['identifier']) From c956cd010678e84df08b8c9e440ef3214b3d6250 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Fri, 31 May 2024 17:03:14 -0400 Subject: [PATCH 22/29] Update old keys --- ..._05_31_204646_fix_old_encrypted_values.php | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 database/migrations/2024_05_31_204646_fix_old_encrypted_values.php diff --git a/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php b/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php new file mode 100644 index 000000000..393b3a6d4 --- /dev/null +++ b/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php @@ -0,0 +1,87 @@ +get(); + foreach ($keys as $key) { + try { + $reEncrypted = encrypt(decrypt($key->token), false); + DB::table('api_keys') + ->where('id', $key->id) + ->update(['token' => $reEncrypted]) + ; + } catch (Exception $exception) { + logger()->error($exception->getMessage()); + } + } + + $databases = DB::table('databases')->get(); + foreach ($databases as $database) { + try { + $reEncrypted = encrypt(decrypt($database->password), false); + DB::table('databases') + ->where('id', $database->id) + ->update(['password' => $reEncrypted]) + ; + } catch (Exception $exception) { + logger()->error($exception->getMessage()); + } + } + + $databaseHosts = DB::table('database_hosts')->get(); + foreach ($databaseHosts as $host) { + try { + $reEncrypted = encrypt(decrypt($host->password), false); + DB::table('database_hosts') + ->where('id', $host->id) + ->update(['password' => $reEncrypted]) + ; + } catch (Exception $exception) { + logger()->error($exception->getMessage()); + } + } + + $nodes = DB::table('nodes')->get(); + foreach ($nodes as $node) { + try { + $reEncrypted = encrypt(decrypt($node->daemon_token), false); + DB::table('nodes') + ->where('id', $node->id) + ->update(['daemon_token' => $reEncrypted]) + ; + } catch (Exception $exception) { + logger()->error($exception->getMessage()); + } + } + + $users = DB::table('users')->get(); + foreach ($users as $user) { + try { + $reEncrypted = encrypt(decrypt($user->totp_secret), false); + DB::table('users') + ->where('id', $user->id) + ->update(['totp_secret' => $reEncrypted]) + ; + } catch (Exception $exception) { + logger()->error($exception->getMessage()); + } + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // No need to do anything + } +}; From 33f6551b2180ea3a90349a5fade362b5299b08c0 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Fri, 31 May 2024 23:06:46 +0200 Subject: [PATCH 23/29] run pint --- ...24_05_31_204646_fix_old_encrypted_values.php | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php b/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php index 393b3a6d4..720fef99a 100644 --- a/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php +++ b/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php @@ -1,8 +1,6 @@ token), false); DB::table('api_keys') ->where('id', $key->id) - ->update(['token' => $reEncrypted]) - ; + ->update(['token' => $reEncrypted]); } catch (Exception $exception) { logger()->error($exception->getMessage()); } @@ -30,8 +27,7 @@ return new class extends Migration $reEncrypted = encrypt(decrypt($database->password), false); DB::table('databases') ->where('id', $database->id) - ->update(['password' => $reEncrypted]) - ; + ->update(['password' => $reEncrypted]); } catch (Exception $exception) { logger()->error($exception->getMessage()); } @@ -43,8 +39,7 @@ return new class extends Migration $reEncrypted = encrypt(decrypt($host->password), false); DB::table('database_hosts') ->where('id', $host->id) - ->update(['password' => $reEncrypted]) - ; + ->update(['password' => $reEncrypted]); } catch (Exception $exception) { logger()->error($exception->getMessage()); } @@ -56,8 +51,7 @@ return new class extends Migration $reEncrypted = encrypt(decrypt($node->daemon_token), false); DB::table('nodes') ->where('id', $node->id) - ->update(['daemon_token' => $reEncrypted]) - ; + ->update(['daemon_token' => $reEncrypted]); } catch (Exception $exception) { logger()->error($exception->getMessage()); } @@ -69,8 +63,7 @@ return new class extends Migration $reEncrypted = encrypt(decrypt($user->totp_secret), false); DB::table('users') ->where('id', $user->id) - ->update(['totp_secret' => $reEncrypted]) - ; + ->update(['totp_secret' => $reEncrypted]); } catch (Exception $exception) { logger()->error($exception->getMessage()); } From 7cda358b664c065e03dda10e25f42c7b1e2f52d0 Mon Sep 17 00:00:00 2001 From: Boy132 Date: Fri, 31 May 2024 23:07:50 +0200 Subject: [PATCH 24/29] add missing import --- .../migrations/2024_05_31_204646_fix_old_encrypted_values.php | 1 + 1 file changed, 1 insertion(+) diff --git a/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php b/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php index 720fef99a..301021349 100644 --- a/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php +++ b/database/migrations/2024_05_31_204646_fix_old_encrypted_values.php @@ -1,6 +1,7 @@ Date: Fri, 31 May 2024 17:24:03 -0400 Subject: [PATCH 25/29] Add Labels --- app/Filament/Resources/UserResource/Pages/EditProfile.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index 4b7c22b5d..d6eeac501 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -164,11 +164,13 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile ->content(fn () => new HtmlString("
$image
")) - ->helperText($secret), + ->helperText('Setup Key: '. $secret), TextInput::make('2facode') + ->label('Code') ->requiredWith('2fapassword') ->helperText('Scan the QR code above using your two-step authentication app, then enter the code generated.'), TextInput::make('2fapassword') + ->label('Current Password') ->requiredWith('2facode') ->currentPassword() ->password() From 7762e68a6cbf5d4d4b4d79d468d5278fa4ce5142 Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 1 Jun 2024 12:49:19 -0400 Subject: [PATCH 26/29] Make qr code visible on light mode --- app/Filament/Resources/UserResource/Pages/EditProfile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index d6eeac501..5f56f8fa4 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -162,7 +162,7 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile Placeholder::make('qr') ->label('Scan QR Code') ->content(fn () => new HtmlString(" -
$image
+
$image
")) ->helperText('Setup Key: '. $secret), TextInput::make('2facode') From 67cb3d4816562f5d1f22f096fd39c2fc9877b7db Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 1 Jun 2024 12:49:36 -0400 Subject: [PATCH 27/29] Show backup tokens better --- .../Resources/UserResource/Pages/EditProfile.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index 5f56f8fa4..c047b3262 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -22,6 +22,7 @@ use Filament\Forms\Components\Select; use Filament\Forms\Components\Tabs; use Filament\Forms\Components\TagsInput; use Filament\Forms\Components\Tabs\Tab; +use Filament\Forms\Components\Textarea; use Filament\Forms\Components\TextInput; use Filament\Forms\Get; use Filament\Notifications\Notification; @@ -104,10 +105,12 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile return [ Placeholder::make('2fa-already-enabled') ->label('Two Factor Authentication is currently enabled!'), - Placeholder::make('backup-tokens') + Textarea::make('backup-tokens') ->hidden(fn () => !cache()->get("users.{$this->getUser()->id}.2fa.tokens")) - ->helperText(cache()->get("users.{$this->getUser()->id}.2fa.tokens") . - ' - these will not be shown again!') + ->rows(10) + ->readOnly() + ->formatStateUsing(fn () => cache()->get("users.{$this->getUser()->id}.2fa.tokens")) + ->helperText('These will not be shown again!') ->label('Backup Tokens:'), TextInput::make('2fa-disable-code') ->label('Disable 2FA') From cd4b7cbf9eee898d25b047de2771ed0822b07f5a Mon Sep 17 00:00:00 2001 From: Lance Pioch Date: Sat, 1 Jun 2024 13:03:46 -0400 Subject: [PATCH 28/29] Refresh this --- app/Filament/Resources/UserResource/Pages/EditProfile.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Filament/Resources/UserResource/Pages/EditProfile.php b/app/Filament/Resources/UserResource/Pages/EditProfile.php index c047b3262..ece225c8b 100644 --- a/app/Filament/Resources/UserResource/Pages/EditProfile.php +++ b/app/Filament/Resources/UserResource/Pages/EditProfile.php @@ -272,6 +272,8 @@ class EditProfile extends \Filament\Pages\Auth\EditProfile $tokens = $service->handle($record, $token, true); cache()->set("users.$record->id.2fa.tokens", implode("\n", $tokens), now()->addSeconds(15)); + + $this->redirectRoute('filament.admin.auth.profile', ['tab' => '-2fa-tab']); } if ($token = $data['2fa-disable-code'] ?? null) { From c31b7b8c6a2a27bc62c2aeaf250525e4d77a27b2 Mon Sep 17 00:00:00 2001 From: notCharles Date: Sat, 1 Jun 2024 15:52:13 -0400 Subject: [PATCH 29/29] Correctly save labels on create --- app/Filament/Resources/ServerResource/Pages/CreateServer.php | 2 +- app/Services/Servers/ServerCreationService.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Filament/Resources/ServerResource/Pages/CreateServer.php b/app/Filament/Resources/ServerResource/Pages/CreateServer.php index a19129202..78ee1eec4 100644 --- a/app/Filament/Resources/ServerResource/Pages/CreateServer.php +++ b/app/Filament/Resources/ServerResource/Pages/CreateServer.php @@ -687,7 +687,7 @@ class CreateServer extends CreateRecord ->label('Container Labels') ->keyLabel('Title') ->valueLabel('Description') - ->columnSpan(1), + ->columnSpan(3), ]), ]), ]); diff --git a/app/Services/Servers/ServerCreationService.php b/app/Services/Servers/ServerCreationService.php index 57d8ad086..d555f7876 100644 --- a/app/Services/Servers/ServerCreationService.php +++ b/app/Services/Servers/ServerCreationService.php @@ -154,6 +154,7 @@ class ServerCreationService 'database_limit' => Arr::get($data, 'database_limit') ?? 0, 'allocation_limit' => Arr::get($data, 'allocation_limit') ?? 0, 'backup_limit' => Arr::get($data, 'backup_limit') ?? 0, + 'docker_labels' => Arr::get($data, 'docker_labels'), ]); }