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,25 +12,21 @@
<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.
If you change the Redis Username in the database, please sync it here, otherwise automations (like backups) won't work.
<br><br>
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