fix: redis database user and password

This commit is contained in:
Andras Bacsai
2024-10-21 12:13:42 +02:00
parent e8c7d7f972
commit bf7b0f9e06
7 changed files with 77 additions and 95 deletions

View File

@@ -4,7 +4,6 @@ namespace App\Livewire\Project\Database\Redis;
use App\Actions\Database\StartDatabaseProxy;
use App\Actions\Database\StopDatabaseProxy;
use App\Models\EnvironmentVariable;
use App\Models\Server;
use App\Models\StandaloneRedis;
use Exception;
@@ -12,12 +11,21 @@ use Livewire\Component;
class General extends Component
{
protected $listeners = ['refresh'];
protected $listeners = [
'envsUpdated' => 'refresh',
'refresh',
];
public Server $server;
public StandaloneRedis $database;
public ?string $redis_username;
public ?string $redis_password;
public string $redis_version;
public ?string $db_url = null;
public ?string $db_url_public = null;
@@ -26,35 +34,33 @@ class General extends Component
'database.name' => 'required',
'database.description' => 'nullable',
'database.redis_conf' => 'nullable',
'database.redis_username' => 'required',
'database.redis_password' => 'required',
'database.image' => 'required',
'database.ports_mappings' => 'nullable',
'database.is_public' => 'nullable|boolean',
'database.public_port' => 'nullable|integer',
'database.is_log_drain_enabled' => 'nullable|boolean',
'database.custom_docker_run_options' => 'nullable',
'redis_username' => 'required',
'redis_password' => 'required',
];
protected $validationAttributes = [
'database.name' => 'Name',
'database.description' => 'Description',
'database.redis_conf' => 'Redis Configuration',
'database.redis_username' => 'Redis Username',
'database.redis_password' => 'Redis Password',
'database.image' => 'Image',
'database.ports_mappings' => 'Port Mapping',
'database.is_public' => 'Is Public',
'database.public_port' => 'Public Port',
'database.custom_docker_run_options' => 'Custom Docker Options',
'redis_username' => 'Redis Username',
'redis_password' => 'Redis Password',
];
public function mount()
{
$this->db_url = $this->database->internal_db_url;
$this->db_url_public = $this->database->external_db_url;
$this->server = data_get($this->database, 'destination.server');
$this->refreshView();
}
public function instantSaveAdvanced()
@@ -79,31 +85,26 @@ class General extends Component
try {
$this->validate();
$redis_version = $this->get_redis_version();
if (version_compare($redis_version, '6.0', '>=') && $this->database->isDirty('redis_username')) {
$this->updateEnvironmentVariable('REDIS_USERNAME', $this->database->redis_username);
}
if ($this->database->isDirty('redis_password')) {
$this->updateEnvironmentVariable('REDIS_PASSWORD', $this->database->redis_password);
if (version_compare($this->redis_version, '6.0', '>=')) {
$this->database->runtime_environment_variables()->updateOrCreate(
['key' => 'REDIS_USERNAME'],
['value' => $this->redis_username, 'standalone_redis_id' => $this->database->id]
);
}
$this->database->runtime_environment_variables()->updateOrCreate(
['key' => 'REDIS_PASSWORD'],
['value' => $this->redis_password, 'standalone_redis_id' => $this->database->id]
);
$this->database->save();
$this->dispatch('success', 'Database updated.');
} catch (Exception $e) {
return handleError($e, $this);
} finally {
$this->dispatch('refreshEnvs');
}
}
private function get_redis_version()
{
$image_parts = explode(':', $this->database->image);
return $image_parts[1] ?? '0.0';
}
public function instantSave()
{
try {
@@ -138,6 +139,14 @@ class General extends Component
public function refresh(): void
{
$this->database->refresh();
$this->refreshView();
}
private function refreshView() {
$this->db_url = $this->database->internal_db_url;
$this->db_url_public = $this->database->external_db_url;
$this->redis_version = $this->database->getRedisVersion();
$this->redis_username = $this->database->redis_username;
$this->redis_password = $this->database->redis_password;
}
public function render()
@@ -147,28 +156,7 @@ class General extends Component
public function isSharedVariable($name)
{
return EnvironmentVariable::where('key', $name)
->where('standalone_redis_id', $this->database->id)
->where('is_shared', true)
->exists();
return $this->database->runtime_environment_variables()->where('key', $name)->where('is_shared', true)->exists();
}
private function updateEnvironmentVariable($key, $value)
{
$envVar = $this->database->runtime_environment_variables()
->where('key', $key)
->first();
if ($envVar) {
if (! $envVar->is_shared) {
$envVar->update(['value' => $value]);
}
} else {
$this->database->runtime_environment_variables()->create([
'key' => $key,
'value' => $value,
'is_shared' => false,
]);
}
}
}

View File

@@ -33,8 +33,6 @@ class Index extends Component
protected Server $server;
public $timezones;
protected $rules = [
'settings.fqdn' => 'nullable',
'settings.resale_license' => 'nullable',

View File

@@ -16,13 +16,6 @@ class StandaloneRedis extends BaseModel
protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status'];
protected $casts = [
'redis_password' => 'encrypted',
];
protected $attributes = [
'redis_username' => 'default',
];
protected static function booted()
{
@@ -219,7 +212,7 @@ class StandaloneRedis extends BaseModel
{
return new Attribute(
get: function () {
$redis_version = $this->get_redis_version();
$redis_version = $this->getRedisVersion();
$username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
return "redis://{$username_part}{$this->redis_password}@{$this->uuid}:6379/0";
@@ -232,7 +225,7 @@ class StandaloneRedis extends BaseModel
return new Attribute(
get: function () {
if ($this->is_public && $this->public_port) {
$redis_version = $this->get_redis_version();
$redis_version = $this->getRedisVersion();
$username_part = version_compare($redis_version, '6.0', '>=') ? "{$this->redis_username}:" : '';
return "redis://{$username_part}{$this->redis_password}@{$this->destination->server->getIp}:{$this->public_port}/0";
@@ -243,7 +236,7 @@ class StandaloneRedis extends BaseModel
);
}
private function get_redis_version()
public function getRedisVersion()
{
$image_parts = explode(':', $this->image);
@@ -318,4 +311,32 @@ class StandaloneRedis extends BaseModel
{
return false;
}
public function redisPassword(): Attribute
{
return new Attribute(
get: function () {
$password = $this->runtime_environment_variables()->where('key', 'REDIS_PASSWORD')->first();
if (! $password) {
return null;
}
return $password->value;
},
);
}
public function redisUsername(): Attribute
{
return new Attribute(
get: function () {
$username = $this->runtime_environment_variables()->where('key', 'REDIS_USERNAME')->first();
if (! $username) {
return null;
}
return $username->value;
}
);
}
}

View File

@@ -50,7 +50,6 @@ function create_standalone_redis($environment_id, $destination_uuid, ?array $oth
$database = new StandaloneRedis;
$database->name = generate_database_name('redis');
$database->redis_password = \Illuminate\Support\Str::password(length: 64, symbols: false);
$database->redis_username = 'default';
$database->environment_id = $environment_id;
$database->destination_id = $destination->id;
$database->destination_type = $destination->getMorphClass();
@@ -68,7 +67,7 @@ function create_standalone_redis($environment_id, $destination_uuid, ?array $oth
EnvironmentVariable::create([
'key' => 'REDIS_USERNAME',
'value' => $database->redis_username,
'value' => 'default',
'standalone_redis_id' => $database->id,
'is_shared' => false,
]);

View File

@@ -1,22 +0,0 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('standalone_redis', function (Blueprint $table) {
$table->string('redis_username')->default('redis')->after('description');
});
}
public function down(): void
{
Schema::table('standalone_redis', function (Blueprint $table) {
$table->dropColumn('redis_username');
});
}
};

View File

@@ -4,7 +4,7 @@ use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
class EncryptExistingRedisPasswords extends Migration
class MoveRedisPasswordToEnvs extends Migration
{
/**
* Run the migrations.
@@ -14,13 +14,15 @@ class EncryptExistingRedisPasswords extends Migration
try {
DB::table('standalone_redis')->chunkById(100, function ($redisInstances) {
foreach ($redisInstances as $redis) {
DB::table('standalone_redis')
->where('id', $redis->id)
->update(['redis_password' => Crypt::encryptString($redis->redis_password)]);
$redis->runtime_environment_variables()->firstOrCreate([
'key' => 'REDIS_PASSWORD',
'value' => $redis->redis_password,
]);
}
});
DB::statement('ALTER TABLE standalone_redis DROP COLUMN redis_password');
} catch (\Exception $e) {
echo 'Encrypting Redis passwords failed.';
echo 'Moving Redis passwords to envs failed.';
echo $e->getMessage();
}
}

View File

@@ -12,11 +12,8 @@
<x-forms.input label="Image" id="database.image" required helper="For all available images, check here:<br><br><a target='_blank' href='https://hub.docker.com/_/redis'>https://hub.docker.com/_/redis</a>" />
</div>
<div class="flex flex-col gap-2">
@php
$redis_version = explode(':', $database->image)[1] ?? '0.0';
@endphp
@if (version_compare($redis_version, '6.0', '>='))
<x-forms.input label="Username" id="database.redis_username" required
<x-forms.input label="Username" id="redis_username" required
helper="You can change the Redis Username in the input field below or by editing the value of the REDIS_USERNAME environment variable.
<br><br>
If you change the Redis Username in the database, please sync it here, otherwise automations (like backups) won't work.
@@ -24,13 +21,12 @@
Note: If the environment variable REDIS_USERNAME is set as a shared variable (environment, project, or team-based), this input field will become read-only."
:disabled="$this->isSharedVariable('REDIS_USERNAME')" />
@endif
<x-forms.input label="Password" id="database.redis_password" type="password" required
<x-forms.input label="Password" id="redis_password" type="password" required
helper="You can change the Redis Password in the input field below or by editing the value of the REDIS_PASSWORD environment variable.
<br><br>
If you change the Redis Password in the database, please sync it here, otherwise automations (like backups) won't work.
<br><br>
Note: If the environment variable REDIS_PASSWORD is set as a shared variable (environment, project, or team-based), this input field will become read-only."
wire:model.defer="database.redis_password"
:disabled="$this->isSharedVariable('REDIS_PASSWORD')" />
</div>
<x-forms.input