diff --git a/app/Http/Controllers/Api/DatabasesController.php b/app/Http/Controllers/Api/DatabasesController.php index f47da2fbc8..5522994dd0 100644 --- a/app/Http/Controllers/Api/DatabasesController.php +++ b/app/Http/Controllers/Api/DatabasesController.php @@ -251,6 +251,7 @@ class DatabasesController extends Controller 'mysql_root_password', 'mariadb_password', 'mariadb_root_password', + ...$database::CONFIGURATION_ATTRIBUTES, ]); $this->exposeNestedServerSecrets($database); } else { diff --git a/app/Livewire/Project/Database/Clickhouse/General.php b/app/Livewire/Project/Database/Clickhouse/General.php index c8badb3cf7..b96ef411a0 100644 --- a/app/Livewire/Project/Database/Clickhouse/General.php +++ b/app/Livewire/Project/Database/Clickhouse/General.php @@ -137,17 +137,17 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; $this->clickhouseAdminUser = $this->database->clickhouse_admin_user; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->clickhouseAdminPassword = $canSeeCredentials ? $this->database->clickhouse_admin_password : ''; $this->image = $this->database->image; $this->portsMappings = $this->database->ports_mappings; $this->isPublic = $this->database->is_public; $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; } } diff --git a/app/Livewire/Project/Database/Dragonfly/General.php b/app/Livewire/Project/Database/Dragonfly/General.php index 0e35530841..f2821121bd 100644 --- a/app/Livewire/Project/Database/Dragonfly/General.php +++ b/app/Livewire/Project/Database/Dragonfly/General.php @@ -124,16 +124,16 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->dragonflyPassword = $canSeeCredentials ? $this->database->dragonfly_password : ''; $this->image = $this->database->image; $this->portsMappings = $this->database->ports_mappings; $this->isPublic = $this->database->is_public; $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; } } diff --git a/app/Livewire/Project/Database/Keydb/General.php b/app/Livewire/Project/Database/Keydb/General.php index abd9e5d025..8ab367e054 100644 --- a/app/Livewire/Project/Database/Keydb/General.php +++ b/app/Livewire/Project/Database/Keydb/General.php @@ -128,9 +128,9 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->keydbConf = $canSeeCredentials ? $this->database->keydb_conf : null; $this->keydbPassword = $canSeeCredentials ? $this->database->keydb_password : ''; $this->image = $this->database->image; @@ -138,7 +138,7 @@ class General extends Component $this->isPublic = $this->database->is_public; $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; } } diff --git a/app/Livewire/Project/Database/Mariadb/General.php b/app/Livewire/Project/Database/Mariadb/General.php index 9e951db774..bed0d6beea 100644 --- a/app/Livewire/Project/Database/Mariadb/General.php +++ b/app/Livewire/Project/Database/Mariadb/General.php @@ -153,9 +153,9 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->mariadbRootPassword = $canSeeCredentials ? $this->database->mariadb_root_password : ''; $this->mariadbUser = $this->database->mariadb_user; $this->mariadbPassword = $canSeeCredentials ? $this->database->mariadb_password : ''; @@ -167,7 +167,7 @@ class General extends Component $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; } } diff --git a/app/Livewire/Project/Database/Mongodb/General.php b/app/Livewire/Project/Database/Mongodb/General.php index 3943512636..545e8463f6 100644 --- a/app/Livewire/Project/Database/Mongodb/General.php +++ b/app/Livewire/Project/Database/Mongodb/General.php @@ -145,9 +145,9 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->mongoConf = $canSeeCredentials ? $this->database->mongo_conf : null; $this->mongoInitdbRootUsername = $this->database->mongo_initdb_root_username; $this->mongoInitdbRootPassword = $canSeeCredentials ? $this->database->mongo_initdb_root_password : ''; @@ -158,7 +158,7 @@ class General extends Component $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; } } diff --git a/app/Livewire/Project/Database/Mysql/General.php b/app/Livewire/Project/Database/Mysql/General.php index f05f9b8410..efda816200 100644 --- a/app/Livewire/Project/Database/Mysql/General.php +++ b/app/Livewire/Project/Database/Mysql/General.php @@ -153,9 +153,9 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->mysqlRootPassword = $canSeeCredentials ? $this->database->mysql_root_password : ''; $this->mysqlUser = $this->database->mysql_user; $this->mysqlPassword = $canSeeCredentials ? $this->database->mysql_password : ''; @@ -167,7 +167,7 @@ class General extends Component $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; } } diff --git a/app/Livewire/Project/Database/Postgresql/General.php b/app/Livewire/Project/Database/Postgresql/General.php index f5844d93d1..ee546680f0 100644 --- a/app/Livewire/Project/Database/Postgresql/General.php +++ b/app/Livewire/Project/Database/Postgresql/General.php @@ -169,10 +169,10 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; $this->postgresUser = $this->database->postgres_user; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->postgresPassword = $canSeeCredentials ? $this->database->postgres_password : ''; $this->postgresDb = $this->database->postgres_db; $this->postgresInitdbArgs = $this->database->postgres_initdb_args; @@ -185,7 +185,7 @@ class General extends Component $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; } } diff --git a/app/Livewire/Project/Database/Redis/General.php b/app/Livewire/Project/Database/Redis/General.php index f744f8eed6..9ab4159385 100644 --- a/app/Livewire/Project/Database/Redis/General.php +++ b/app/Livewire/Project/Database/Redis/General.php @@ -146,6 +146,7 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; $this->image = $this->database->image; @@ -154,10 +155,9 @@ class General extends Component $this->publicPort = $this->database->public_port; $this->publicPortTimeout = $this->database->public_port_timeout; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; $this->redisVersion = $this->database->getRedisVersion(); $this->redisUsername = $this->database->redis_username; - $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->redisConf = $canSeeCredentials ? $this->database->redis_conf : null; $this->isPasswordLocked = $this->database->isCredentialLocked(); $this->redisPassword = $canSeeCredentials && ! $this->isPasswordLocked ? $this->database->redis_password : null; diff --git a/app/Livewire/Project/Database/Sqlite/General.php b/app/Livewire/Project/Database/Sqlite/General.php index cd1d578554..9c79e55a40 100644 --- a/app/Livewire/Project/Database/Sqlite/General.php +++ b/app/Livewire/Project/Database/Sqlite/General.php @@ -29,6 +29,8 @@ class General extends Component public bool $isLogDrainEnabled = false; + public bool $isPasswordHiddenForMember = false; + public function mount() { try { @@ -43,6 +45,8 @@ class General extends Component } catch (\Throwable $e) { return handleError($e, $this); } + + $this->isPasswordHiddenForMember = ! (auth()->user()?->can('update', $this->database) ?? false); } protected function rules(): array @@ -83,11 +87,12 @@ class General extends Component $this->database->save(); $this->dispatch('name-changed', uuid: $this->database->uuid, name: $this->database->name); } else { + $canSeeCredentials = auth()->user()?->can('update', $this->database) ?? false; $this->name = $this->database->name; $this->description = $this->database->description; $this->sqliteDatabases = $this->database->sqlite_databases; $this->image = $this->database->image; - $this->customDockerRunOptions = $this->database->custom_docker_run_options; + $this->customDockerRunOptions = $canSeeCredentials ? $this->database->custom_docker_run_options : null; $this->isLogDrainEnabled = $this->database->is_log_drain_enabled; } } diff --git a/app/Models/StandaloneClickhouse.php b/app/Models/StandaloneClickhouse.php index eeaa59c97c..9e959b0577 100644 --- a/app/Models/StandaloneClickhouse.php +++ b/app/Models/StandaloneClickhouse.php @@ -62,6 +62,14 @@ class StandaloneClickhouse extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -69,6 +77,7 @@ class StandaloneClickhouse extends BaseModel */ protected $hidden = [ 'clickhouse_admin_password', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', ]; diff --git a/app/Models/StandaloneDragonfly.php b/app/Models/StandaloneDragonfly.php index 5484f60bce..e97402a754 100644 --- a/app/Models/StandaloneDragonfly.php +++ b/app/Models/StandaloneDragonfly.php @@ -56,6 +56,14 @@ class StandaloneDragonfly extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -63,6 +71,7 @@ class StandaloneDragonfly extends BaseModel */ protected $hidden = [ 'dragonfly_password', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', // Internal start-command state, not part of the API. diff --git a/app/Models/StandaloneKeydb.php b/app/Models/StandaloneKeydb.php index c5e03e6df0..a6842ab01e 100644 --- a/app/Models/StandaloneKeydb.php +++ b/app/Models/StandaloneKeydb.php @@ -57,6 +57,15 @@ class StandaloneKeydb extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'keydb_conf', + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -64,6 +73,7 @@ class StandaloneKeydb extends BaseModel */ protected $hidden = [ 'keydb_password', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', // Internal start-command state, not part of the API. diff --git a/app/Models/StandaloneMariadb.php b/app/Models/StandaloneMariadb.php index 90d39c4f8e..bb6aaf4dc2 100644 --- a/app/Models/StandaloneMariadb.php +++ b/app/Models/StandaloneMariadb.php @@ -60,6 +60,15 @@ class StandaloneMariadb extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'mariadb_conf', + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -68,6 +77,7 @@ class StandaloneMariadb extends BaseModel protected $hidden = [ 'mariadb_password', 'mariadb_root_password', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', ]; diff --git a/app/Models/StandaloneMongodb.php b/app/Models/StandaloneMongodb.php index a018bae7c2..f67f413133 100644 --- a/app/Models/StandaloneMongodb.php +++ b/app/Models/StandaloneMongodb.php @@ -60,6 +60,15 @@ class StandaloneMongodb extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'mongo_conf', + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -67,6 +76,7 @@ class StandaloneMongodb extends BaseModel */ protected $hidden = [ 'mongo_initdb_root_password', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', ]; diff --git a/app/Models/StandaloneMysql.php b/app/Models/StandaloneMysql.php index 68a73ae573..5ff8d8ab93 100644 --- a/app/Models/StandaloneMysql.php +++ b/app/Models/StandaloneMysql.php @@ -61,6 +61,15 @@ class StandaloneMysql extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'mysql_conf', + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -69,6 +78,7 @@ class StandaloneMysql extends BaseModel protected $hidden = [ 'mysql_password', 'mysql_root_password', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', ]; diff --git a/app/Models/StandalonePostgresql.php b/app/Models/StandalonePostgresql.php index 542358fab6..b468de9d9d 100644 --- a/app/Models/StandalonePostgresql.php +++ b/app/Models/StandalonePostgresql.php @@ -63,6 +63,15 @@ class StandalonePostgresql extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'postgres_conf', + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -71,6 +80,7 @@ class StandalonePostgresql extends BaseModel protected $hidden = [ 'postgres_password', 'init_scripts', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', ]; diff --git a/app/Models/StandaloneRedis.php b/app/Models/StandaloneRedis.php index 86b4702f49..227b07ccfb 100644 --- a/app/Models/StandaloneRedis.php +++ b/app/Models/StandaloneRedis.php @@ -58,6 +58,15 @@ class StandaloneRedis extends BaseModel protected $appends = ['internal_db_url', 'external_db_url', 'database_type', 'server_status']; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'redis_conf', + 'custom_docker_run_options', + ]; + /** * Sensitive fields hidden by default in serialized output (toArray/toJson). * API controllers should call makeVisible([...]) for callers with the @@ -65,6 +74,7 @@ class StandaloneRedis extends BaseModel */ protected $hidden = [ 'redis_password', + ...self::CONFIGURATION_ATTRIBUTES, 'internal_db_url', 'external_db_url', // Internal start-command state, not part of the API. diff --git a/app/Models/StandaloneSqlite.php b/app/Models/StandaloneSqlite.php index 2f6993865c..327a1f8731 100644 --- a/app/Models/StandaloneSqlite.php +++ b/app/Models/StandaloneSqlite.php @@ -57,6 +57,23 @@ class StandaloneSqlite extends BaseModel 'health_check_start_period', ]; + /** + * Free-form configuration that can embed credentials. Only users who can + * update the database and `read:sensitive` tokens may read it. + */ + public const CONFIGURATION_ATTRIBUTES = [ + 'custom_docker_run_options', + ]; + + /** + * Sensitive fields hidden by default in serialized output (toArray/toJson). + * API controllers should call makeVisible([...]) for callers with the + * `read:sensitive` or `root` token ability. + */ + protected $hidden = [ + ...self::CONFIGURATION_ATTRIBUTES, + ]; + protected $appends = ['database_type', 'server_status']; protected $casts = [ diff --git a/resources/views/livewire/project/database/clickhouse/general.blade.php b/resources/views/livewire/project/database/clickhouse/general.blade.php index bc9cfce208..d38027dfd0 100644 --- a/resources/views/livewire/project/database/clickhouse/general.blade.php +++ b/resources/views/livewire/project/database/clickhouse/general.blade.php @@ -104,11 +104,15 @@ - + @if ($isPasswordHiddenForMember) + + @else + + @endif - + @if ($isPasswordHiddenForMember) + + @else + + @endif - + @if ($isPasswordHiddenForMember) + + @else + + @endif @if ($isPasswordHiddenForMember) diff --git a/resources/views/livewire/project/database/mariadb/general.blade.php b/resources/views/livewire/project/database/mariadb/general.blade.php index ada8007f0e..745059ed4b 100644 --- a/resources/views/livewire/project/database/mariadb/general.blade.php +++ b/resources/views/livewire/project/database/mariadb/general.blade.php @@ -88,11 +88,15 @@ - + @if ($isPasswordHiddenForMember) + + @else + + @endif @if ($isPasswordHiddenForMember) diff --git a/resources/views/livewire/project/database/mongodb/general.blade.php b/resources/views/livewire/project/database/mongodb/general.blade.php index dacb2175e3..cd757fa14d 100644 --- a/resources/views/livewire/project/database/mongodb/general.blade.php +++ b/resources/views/livewire/project/database/mongodb/general.blade.php @@ -85,11 +85,15 @@ - + @if ($isPasswordHiddenForMember) + + @else + + @endif @if ($isPasswordHiddenForMember) diff --git a/resources/views/livewire/project/database/mysql/general.blade.php b/resources/views/livewire/project/database/mysql/general.blade.php index 8d7b3ce8fd..2fbcb6d473 100644 --- a/resources/views/livewire/project/database/mysql/general.blade.php +++ b/resources/views/livewire/project/database/mysql/general.blade.php @@ -88,11 +88,15 @@ - + @if ($isPasswordHiddenForMember) + + @else + + @endif @if ($isPasswordHiddenForMember) diff --git a/resources/views/livewire/project/database/postgresql/general.blade.php b/resources/views/livewire/project/database/postgresql/general.blade.php index f2466fc1e0..342e79470d 100644 --- a/resources/views/livewire/project/database/postgresql/general.blade.php +++ b/resources/views/livewire/project/database/postgresql/general.blade.php @@ -90,11 +90,15 @@ - + @if ($isPasswordHiddenForMember) + + @else + + @endif @if ($isPasswordHiddenForMember) diff --git a/resources/views/livewire/project/database/redis/general.blade.php b/resources/views/livewire/project/database/redis/general.blade.php index c199e525ad..2517ba86ee 100644 --- a/resources/views/livewire/project/database/redis/general.blade.php +++ b/resources/views/livewire/project/database/redis/general.blade.php @@ -90,11 +90,15 @@ - + @if ($isPasswordHiddenForMember) + + @else + + @endif @if ($isPasswordHiddenForMember) diff --git a/resources/views/livewire/project/database/sqlite/general.blade.php b/resources/views/livewire/project/database/sqlite/general.blade.php index ebe9fa1ca5..cc3a45c7bf 100644 --- a/resources/views/livewire/project/database/sqlite/general.blade.php +++ b/resources/views/livewire/project/database/sqlite/general.blade.php @@ -31,11 +31,15 @@ - + @if ($isPasswordHiddenForMember) + + @else + + @endif uuid}:6379/0"); }); + +dataset('database-api-config', [ + 'postgresql' => ['create_standalone_postgresql', 'postgresqls', ['postgres_conf' => "primary_conninfo = 'password=secret-config-value'"]], + 'mysql' => ['create_standalone_mysql', 'mysqls', ['mysql_conf' => 'password=secret-config-value']], + 'mariadb' => ['create_standalone_mariadb', 'mariadbs', ['mariadb_conf' => 'password=secret-config-value']], + 'mongodb' => ['create_standalone_mongodb', 'mongodbs', ['mongo_conf' => 'keyFile: secret-config-value']], + 'redis' => ['create_standalone_redis', 'redis', ['redis_conf' => 'masterauth secret-config-value']], + 'keydb' => ['create_standalone_keydb', null, ['keydb_conf' => 'masterauth secret-config-value']], + 'dragonfly' => ['create_standalone_dragonfly', null, []], + 'clickhouse' => ['create_standalone_clickhouse', null, []], +]); + +function apiTokenHeaders(User $user, Team $team, array $abilities): array +{ + $token = $user->createToken('config-test', $abilities); + DB::table('personal_access_tokens')->where('id', $token->accessToken->id)->update(['team_id' => $team->id]); + + return ['Authorization' => 'Bearer '.$token->plainTextToken]; +} + +it('hides custom configs and docker run options from a token without sensitive read access', function (string $createDatabase, ?string $environmentRelation, array $config) { + $database = createDatabaseWithConfig($createDatabase, [ + ...$config, + 'custom_docker_run_options' => '--env API_TOKEN=secret-docker-value', + ]); + session(['currentTeam' => $this->team]); + $project = $this->environment->project; + + foreach ([ + [$this->member, ['read']], + [$this->member, ['read', 'read:sensitive']], + [$this->owner, ['read']], + ] as [$user, $abilities]) { + $headers = apiTokenHeaders($user, $this->team, $abilities); + + $single = $this->withHeaders($headers)->getJson("/api/v1/databases/{$database->uuid}")->assertOk(); + expect($single->json('uuid'))->toBe($database->uuid) + ->and($single->getContent())->not->toContain('secret-config-value')->not->toContain('secret-docker-value'); + + $list = $this->withHeaders($headers)->getJson('/api/v1/databases')->assertOk(); + expect($list->getContent())->toContain($database->uuid) + ->not->toContain('secret-config-value')->not->toContain('secret-docker-value'); + + if ($environmentRelation !== null) { + $environment = $this->withHeaders($headers)->getJson("/api/v1/projects/{$project->uuid}/{$this->environment->uuid}")->assertOk(); + expect($environment->getContent())->toContain($database->uuid) + ->not->toContain('secret-config-value')->not->toContain('secret-docker-value'); + } + } +})->with('database-api-config'); + +it('returns custom configs and docker run options to an owner token with sensitive read access', function (string $createDatabase, ?string $environmentRelation, array $config) { + $database = createDatabaseWithConfig($createDatabase, [ + ...$config, + 'custom_docker_run_options' => '--env API_TOKEN=secret-docker-value', + ]); + session(['currentTeam' => $this->team]); + $headers = apiTokenHeaders($this->owner, $this->team, ['read', 'read:sensitive']); + + $single = $this->withHeaders($headers)->getJson("/api/v1/databases/{$database->uuid}")->assertOk() + ->assertJsonPath('custom_docker_run_options', '--env API_TOKEN=secret-docker-value'); + foreach ($config as $key => $value) { + $single->assertJsonPath($key, $value); + } + + if ($environmentRelation !== null) { + $project = $this->environment->project; + $this->withHeaders($headers)->getJson("/api/v1/projects/{$project->uuid}/{$this->environment->uuid}")->assertOk() + ->assertJsonPath("{$environmentRelation}.0.custom_docker_run_options", '--env API_TOKEN=secret-docker-value'); + } +})->with('database-api-config'); + +dataset('database-docker-options-components', [ + 'postgresql' => ['create_standalone_postgresql', PostgresqlGeneral::class], + 'mysql' => ['create_standalone_mysql', MysqlGeneral::class], + 'mariadb' => ['create_standalone_mariadb', MariadbGeneral::class], + 'mongodb' => ['create_standalone_mongodb', MongodbGeneral::class], + 'redis' => ['create_standalone_redis', RedisGeneral::class], + 'keydb' => ['create_standalone_keydb', KeydbGeneral::class], + 'dragonfly' => ['create_standalone_dragonfly', DragonflyGeneral::class], + 'clickhouse' => ['create_standalone_clickhouse', ClickhouseGeneral::class], + 'sqlite' => ['create_standalone_sqlite', SqliteGeneral::class], +]); + +it('keeps custom docker run options out of member state and html', function (string $createDatabase, string $generalClass) { + $database = createDatabaseWithConfig($createDatabase, ['custom_docker_run_options' => '--env API_TOKEN=secret-docker-value']); + $ownTeam = Team::factory()->create(); + $ownTeam->members()->attach($this->member->id, ['role' => 'owner']); + + $this->actingAs($this->member); + foreach ([$this->team, $ownTeam] as $sessionTeam) { + session(['currentTeam' => $sessionTeam]); + + $general = Livewire::test($generalClass, ['database' => $database]) + ->assertSet('customDockerRunOptions', null); + expect(json_encode($general->snapshot))->not->toContain('secret-docker-value') + ->and($general->html())->not->toContain('secret-docker-value') + ->and($general->html())->toContain('Hidden (only admins can view)'); + } +})->with('database-docker-options-components'); + +it('keeps custom docker run options available to an owner', function (string $createDatabase, string $generalClass) { + $database = createDatabaseWithConfig($createDatabase, ['custom_docker_run_options' => '--env API_TOKEN=secret-docker-value']); + + $this->actingAs($this->owner); + session(['currentTeam' => $this->team]); + + Livewire::test($generalClass, ['database' => $database]) + ->assertSet('customDockerRunOptions', '--env API_TOKEN=secret-docker-value'); +})->with('database-docker-options-components'); + +it('does not let a member save over hidden custom configs and docker run options', function (string $createDatabase, string $generalClass) { + $database = createDatabaseWithConfig($createDatabase, ['custom_docker_run_options' => '--env API_TOKEN=secret-docker-value']); + + $this->actingAs($this->member); + session(['currentTeam' => $this->team]); + + Livewire::test($generalClass, ['database' => $database]) + ->set('name', 'renamed-by-member') + ->call('submit') + ->call('instantSaveAdvanced'); + + $database = $database->fresh(); + expect($database->name)->not->toBe('renamed-by-member') + ->and($database->custom_docker_run_options)->toBe('--env API_TOKEN=secret-docker-value'); +})->with('database-docker-options-components');