- * @author Nicolas Grekas
- *
- * @internal
- */
-class SecretEnvVarProcessor implements EnvVarProcessorInterface
-{
- private $vault;
- private $localVault;
-
- public function __construct(AbstractVault $vault, AbstractVault $localVault = null)
- {
- $this->vault = $vault;
- $this->localVault = $localVault;
- }
-
- /**
- * {@inheritdoc}
- */
- public static function getProvidedTypes()
- {
- return [
- 'secret' => 'string',
- ];
- }
-
- /**
- * {@inheritdoc}
- */
- public function getEnv($prefix, $name, \Closure $getEnv): string
- {
- if (null !== $this->localVault && null !== ($secret = $this->localVault->reveal($name)) && \array_key_exists($name, $this->vault->list())) {
- return $secret;
- }
-
- if (null !== $secret = $this->vault->reveal($name)) {
- return $secret;
- }
-
- throw new EnvNotFoundException($this->vault->getLastMessage() ?? sprintf('Secret "%s" not found or decryption key is missing.', $name));
- }
-}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
index cb6e9f527fdae..e6fcab506057d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php
@@ -11,6 +11,8 @@
namespace Symfony\Bundle\FrameworkBundle\Secrets;
+use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
+
/**
* @author Tobias Schultze
* @author Jérémy Derussé
@@ -18,7 +20,7 @@
*
* @internal
*/
-class SodiumVault extends AbstractVault
+class SodiumVault extends AbstractVault implements EnvVarLoaderInterface
{
private $encryptionKey;
private $decryptionKey;
@@ -56,8 +58,8 @@ public function generateKeys(bool $override = false): bool
// ignore failures to load keys
}
- if ('' !== $this->decryptionKey && !file_exists($this->pathPrefix.'sodium.encrypt.public')) {
- $this->export('sodium.encrypt.public', $this->encryptionKey);
+ if ('' !== $this->decryptionKey && !file_exists($this->pathPrefix.'encrypt.public.php')) {
+ $this->export('encrypt.public', $this->encryptionKey);
}
if (!$override && null !== $this->encryptionKey) {
@@ -69,10 +71,10 @@ public function generateKeys(bool $override = false): bool
$this->decryptionKey = sodium_crypto_box_keypair();
$this->encryptionKey = sodium_crypto_box_publickey($this->decryptionKey);
- $this->export('sodium.encrypt.public', $this->encryptionKey);
- $this->export('sodium.decrypt.private', $this->decryptionKey);
+ $this->export('encrypt.public', $this->encryptionKey);
+ $this->export('decrypt.private', $this->decryptionKey);
- $this->lastMessage = sprintf('Sodium keys have been generated at "%s*.{public,private}".', $this->getPrettyPath($this->pathPrefix));
+ $this->lastMessage = sprintf('Sodium keys have been generated at "%s*.public/private.php".', $this->getPrettyPath($this->pathPrefix));
return true;
}
@@ -82,12 +84,12 @@ public function seal(string $name, string $value): void
$this->lastMessage = null;
$this->validateName($name);
$this->loadKeys();
- $this->export($name.'.'.substr_replace(md5($name), '.sodium', -26), sodium_crypto_box_seal($value, $this->encryptionKey ?? sodium_crypto_box_publickey($this->decryptionKey)));
+ $this->export($name.'.'.substr(md5($name), 0, 6), sodium_crypto_box_seal($value, $this->encryptionKey ?? sodium_crypto_box_publickey($this->decryptionKey)));
$list = $this->list();
$list[$name] = null;
uksort($list, 'strnatcmp');
- file_put_contents($this->pathPrefix.'sodium.list', sprintf("pathPrefix.'list.php', sprintf("lastMessage = sprintf('Secret "%s" encrypted in "%s"; you can commit it.', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
}
@@ -97,7 +99,7 @@ public function reveal(string $name): ?string
$this->lastMessage = null;
$this->validateName($name);
- if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.sodium', -26))) {
+ if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.php', -26))) {
$this->lastMessage = sprintf('Secret "%s" not found in "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
return null;
@@ -131,7 +133,7 @@ public function remove(string $name): bool
$this->lastMessage = null;
$this->validateName($name);
- if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.sodium', -26))) {
+ if (!file_exists($file = $this->pathPrefix.$name.'.'.substr_replace(md5($name), '.php', -26))) {
$this->lastMessage = sprintf('Secret "%s" not found in "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
return false;
@@ -139,7 +141,7 @@ public function remove(string $name): bool
$list = $this->list();
unset($list[$name]);
- file_put_contents($this->pathPrefix.'sodium.list', sprintf("pathPrefix.'list.php', sprintf("lastMessage = sprintf('Secret "%s" removed from "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR));
@@ -150,7 +152,7 @@ public function list(bool $reveal = false): array
{
$this->lastMessage = null;
- if (!file_exists($file = $this->pathPrefix.'sodium.list')) {
+ if (!file_exists($file = $this->pathPrefix.'list.php')) {
return [];
}
@@ -167,6 +169,11 @@ public function list(bool $reveal = false): array
return $secrets;
}
+ public function loadEnvVars(): array
+ {
+ return $this->list(true);
+ }
+
private function loadKeys(): void
{
if (!\function_exists('sodium_crypto_box_seal')) {
@@ -177,12 +184,12 @@ private function loadKeys(): void
return;
}
- if (file_exists($this->pathPrefix.'sodium.decrypt.private')) {
- $this->decryptionKey = (string) include $this->pathPrefix.'sodium.decrypt.private';
+ if (file_exists($this->pathPrefix.'decrypt.private.php')) {
+ $this->decryptionKey = (string) include $this->pathPrefix.'decrypt.private.php';
}
- if (file_exists($this->pathPrefix.'sodium.encrypt.public')) {
- $this->encryptionKey = (string) include $this->pathPrefix.'sodium.encrypt.public';
+ if (file_exists($this->pathPrefix.'encrypt.public.php')) {
+ $this->encryptionKey = (string) include $this->pathPrefix.'encrypt.public.php';
} elseif ('' !== $this->decryptionKey) {
$this->encryptionKey = sodium_crypto_box_publickey($this->decryptionKey);
} else {
@@ -196,7 +203,7 @@ private function export(string $file, string $data): void
$data = str_replace('%', '\x', rawurlencode($data));
$data = sprintf("pathPrefix.$file, $data, LOCK_EX)) {
+ if (false === file_put_contents($this->pathPrefix.$file.'.php', $data, LOCK_EX)) {
$e = error_get_last();
throw new \ErrorException($e['message'] ?? 'Failed to write secrets data.', 0, $e['type'] ?? E_USER_WARNING);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/SodiumVaultTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/SodiumVaultTest.php
index 2e25df902462b..a9b88b1763bd5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/SodiumVaultTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Secrets/SodiumVaultTest.php
@@ -26,19 +26,19 @@ public function testGenerateKeys()
$vault = new SodiumVault($this->secretsDir);
$this->assertTrue($vault->generateKeys());
- $this->assertFileExists($this->secretsDir.'/test.sodium.encrypt.public');
- $this->assertFileExists($this->secretsDir.'/test.sodium.decrypt.private');
+ $this->assertFileExists($this->secretsDir.'/test.encrypt.public.php');
+ $this->assertFileExists($this->secretsDir.'/test.decrypt.private.php');
- $encKey = file_get_contents($this->secretsDir.'/test.sodium.encrypt.public');
- $decKey = file_get_contents($this->secretsDir.'/test.sodium.decrypt.private');
+ $encKey = file_get_contents($this->secretsDir.'/test.encrypt.public.php');
+ $decKey = file_get_contents($this->secretsDir.'/test.decrypt.private.php');
$this->assertFalse($vault->generateKeys());
- $this->assertStringEqualsFile($this->secretsDir.'/test.sodium.encrypt.public', $encKey);
- $this->assertStringEqualsFile($this->secretsDir.'/test.sodium.decrypt.private', $decKey);
+ $this->assertStringEqualsFile($this->secretsDir.'/test.encrypt.public.php', $encKey);
+ $this->assertStringEqualsFile($this->secretsDir.'/test.decrypt.private.php', $decKey);
$this->assertTrue($vault->generateKeys(true));
- $this->assertStringNotEqualsFile($this->secretsDir.'/test.sodium.encrypt.public', $encKey);
- $this->assertStringNotEqualsFile($this->secretsDir.'/test.sodium.decrypt.private', $decKey);
+ $this->assertStringNotEqualsFile($this->secretsDir.'/test.encrypt.public.php', $encKey);
+ $this->assertStringNotEqualsFile($this->secretsDir.'/test.decrypt.private.php', $decKey);
}
public function testEncryptAndDecrypt()
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
index ea4a05cfd94d9..2147d53f1263d 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php
@@ -188,7 +188,7 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar
$checkFunction = sprintf('is_%s', $parameter->getType()->getName());
if (!$parameter->getType()->isBuiltin() || !$checkFunction($value)) {
- throw new InvalidParameterTypeException($this->currentId, \gettype($value), $parameter);
+ throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? \get_class($value) : \gettype($value), $parameter);
}
}
}
diff --git a/src/Symfony/Component/DependencyInjection/EnvVarLoaderInterface.php b/src/Symfony/Component/DependencyInjection/EnvVarLoaderInterface.php
new file mode 100644
index 0000000000000..0c547f8a5fae2
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/EnvVarLoaderInterface.php
@@ -0,0 +1,25 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\DependencyInjection;
+
+/**
+ * EnvVarLoaderInterface objects return key/value pairs that are added to the list of available env vars.
+ *
+ * @author Nicolas Grekas
+ */
+interface EnvVarLoaderInterface
+{
+ /**
+ * @return string[] Key/value pairs that can be accessed using the regular "%env()%" syntax
+ */
+ public function loadEnvVars(): array;
+}
diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
index aef13a9ad1c63..6451ac9b0e9d3 100644
--- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
+++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection;
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
+use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
@@ -20,10 +21,17 @@
class EnvVarProcessor implements EnvVarProcessorInterface
{
private $container;
+ private $loaders;
+ private $loadedVars = [];
- public function __construct(ContainerInterface $container)
+ /**
+ * @param EnvVarLoaderInterface[] $loaders
+ */
+ public function __construct(ContainerInterface $container, \Traversable $loaders = null)
{
$this->container = $container;
+ $this->loaders = new \IteratorIterator($loaders ?? new \ArrayIterator());
+ $this->loaders = $this->loaders->getInnerIterator();
}
/**
@@ -127,12 +135,31 @@ public function getEnv($prefix, $name, \Closure $getEnv)
} elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) {
$env = $_SERVER[$name];
} elseif (false === ($env = getenv($name)) || null === $env) { // null is a possible value because of thread safety issues
- if (!$this->container->hasParameter("env($name)")) {
- throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".', $name));
+ foreach ($this->loadedVars as $vars) {
+ if (false !== $env = ($vars[$name] ?? false)) {
+ break;
+ }
}
- if (null === $env = $this->container->getParameter("env($name)")) {
- return null;
+ try {
+ while ((false === $env || null === $env) && $this->loaders->valid()) {
+ $loader = $this->loaders->current();
+ $this->loaders->next();
+ $this->loadedVars[] = $vars = $loader->loadEnvVars();
+ $env = $vars[$name] ?? false;
+ }
+ } catch (ParameterCircularReferenceException $e) {
+ // skip loaders that need an env var that is not defined
+ }
+
+ if (false === $env || null === $env) {
+ if (!$this->container->hasParameter("env($name)")) {
+ throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".', $name));
+ }
+
+ if (null === $env = $this->container->getParameter("env($name)")) {
+ return null;
+ }
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
index 12d852f4535c4..9970eb474f6be 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
@@ -5,6 +5,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
use Symfony\Component\DependencyInjection\EnvVarProcessor;
class EnvVarProcessorTest extends TestCase
@@ -517,4 +518,39 @@ public function validCsv()
[null, null],
];
}
+
+ public function testEnvLoader()
+ {
+ $loaders = function () {
+ yield new class() implements EnvVarLoaderInterface {
+ public function loadEnvVars(): array
+ {
+ return [
+ 'FOO_ENV_LOADER' => '123',
+ ];
+ }
+ };
+
+ yield new class() implements EnvVarLoaderInterface {
+ public function loadEnvVars(): array
+ {
+ return [
+ 'FOO_ENV_LOADER' => '234',
+ 'BAR_ENV_LOADER' => '456',
+ ];
+ }
+ };
+ };
+
+ $processor = new EnvVarProcessor(new Container(), $loaders());
+
+ $result = $processor->getEnv('string', 'FOO_ENV_LOADER', function () {});
+ $this->assertSame('123', $result);
+
+ $result = $processor->getEnv('string', 'BAR_ENV_LOADER', function () {});
+ $this->assertSame('456', $result);
+
+ $result = $processor->getEnv('string', 'FOO_ENV_LOADER', function () {});
+ $this->assertSame('123', $result); // check twice
+ }
}
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy