Skip to content

Commit

Permalink
Add moar tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bpolaszek committed Sep 20, 2019
1 parent a2bcec8 commit 2067d74
Show file tree
Hide file tree
Showing 18 changed files with 505 additions and 79 deletions.
4 changes: 1 addition & 3 deletions README.md
Expand Up @@ -85,7 +85,7 @@ This file can safely be committed to VCS (as soon as the private key isn't).
To encrypt and register a secret in this file, run the following command:

```bash
bin/console shh:register-secret my_secret # You will be prompted for the value of "my_secret"
bin/console shh:register:secret my_secret # You will be prompted for the value of "my_secret"
```

You can then use your secrets in your configuration files in the following way:
Expand Down Expand Up @@ -129,8 +129,6 @@ shh:
./vendor/bin/phpunit
```

More tests are welcome.

## Feedback

Don't hesitate to ping me on Symfony Slack: **@bpolaszek**.
Expand Down
6 changes: 4 additions & 2 deletions composer.json
Expand Up @@ -33,13 +33,15 @@
"symfony/filesystem": "~3.4|~4.0"
},
"require-dev": {
"phpunit/phpunit": "~7.0",
"phpunit/phpunit": "~7.0|~8.0",
"squizlabs/php_codesniffer": "~2.0",
"symfony/var-dumper": "~4.0",
"php-coveralls/php-coveralls": "2.1",
"phpstan/phpstan": "~0.11.5",
"symfony/framework-bundle": "~3.4|~4.0",
"nyholm/symfony-bundle-test": "^1.4"
"nyholm/symfony-bundle-test": "^1.4",
"bentools/cartesian-product": "^1.3",
"thecodingmachine/safe": "^0.1.16"
},
"autoload": {
"psr-4": {
Expand Down
44 changes: 22 additions & 22 deletions src/Command/ChangePassphraseCommand.php
Expand Up @@ -16,11 +16,6 @@ final class ChangePassphraseCommand extends Command
{
protected static $defaultName = 'shh:change:passphrase';

/**
* @var ContainerInterface
*/
private $container;

/**
* @var Shh
*/
Expand All @@ -31,18 +26,29 @@ final class ChangePassphraseCommand extends Command
*/
private $fs;

public function __construct(ContainerInterface $container, Shh $shh, Filesystem $fs)
/**
* @var string
*/
private $keysDir;

/**
* @var string|null
*/
private $privateKey;

public function __construct(Shh $shh, Filesystem $fs, string $keysDir, ?string $privateKey)
{
parent::__construct();
$this->container = $container;
$this->shh = $shh;
$this->fs = $fs;
$this->keysDir = $keysDir;
$this->privateKey = $privateKey;
}

protected function configure()
{
$this
->setDescription('Generate public/private keys.')
->setDescription('Change passphrase, generate a new private key.')
->addOption('old-passphrase', '', InputOption::VALUE_OPTIONAL, 'Your current passhrase.')
->addOption('new-passphrase', '', InputOption::VALUE_OPTIONAL, '(Optional) your new passhrase.')
->addOption('overwrite', '', InputOption::VALUE_NONE, 'Overwrite the existing key.')
Expand Down Expand Up @@ -97,10 +103,16 @@ protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);

if (null === $this->privateKey) {
$io->error('Private key was not found.');

return 1;
}

$passphrase = $input->getOption('new-passphrase');
$dir = $this->getDirectory();
$dir = $this->keysDir;

$oldPrivateKey = $this->container->getParameter('shh.private_key_file');
$oldPrivateKey = $this->privateKey;
$newPrivateKey = Shh::changePassphrase($oldPrivateKey, $input->getOption('old-passphrase'), $passphrase);

$io->comment('Here is your new private key:');
Expand All @@ -114,16 +126,4 @@ protected function execute(InputInterface $input, OutputInterface $output)

$io->caution('Don\'t forget to report your new passphrase into the SHH_PASSPHRASE environment variable, and to deploy the new private key to everywhere it\'s needed!');
}

/**
* @return string
*/
private function getDirectory()
{
if (Kernel::MAJOR_VERSION < 4) {
return $this->container->getParameter('kernel.project_dir') . '/app/config/shh';
}

return $this->container->getParameter('kernel.project_dir') . '/config/shh';
}
}
16 changes: 5 additions & 11 deletions src/Command/CheckCommand.php
Expand Up @@ -11,14 +11,8 @@

final class CheckCommand extends Command
{

protected static $defaultName = 'shh:check';

/**
* @var Shh
*/
private $shh;

/**
* @var string
*/
Expand All @@ -37,9 +31,8 @@ final class CheckCommand extends Command
/**
* CheckCommand constructor.
*/
public function __construct(Shh $shh, string $publicKeyFile, string $privateKeyFile, ?string $passphrase = null)
public function __construct(string $publicKeyFile, ?string $privateKeyFile, ?string $passphrase = null)
{
$this->shh = $shh;
$this->publicKeyFile = $publicKeyFile;
$this->privateKeyFile = $privateKeyFile;
$this->passphrase = $passphrase;
Expand All @@ -58,6 +51,7 @@ protected function configure()
protected function execute(InputInterface $input, OutputInterface $output)
{
$io = new SymfonyStyle($input, $output);
$shh = new Shh($this->publicKeyFile, $this->privateKeyFile, $this->passphrase);

$errors = [];

Expand All @@ -77,7 +71,7 @@ protected function execute(InputInterface $input, OutputInterface $output)

if (false === $input->getOption('decrypt-only')) {
try {
$encrypted = $this->shh->encrypt('foo');
$encrypted = $shh->encrypt('foo');
} catch (\Throwable $e) {
$errors[] = 'Encrypting a payload failed.';
$io->error(\end($errors));
Expand All @@ -88,7 +82,7 @@ protected function execute(InputInterface $input, OutputInterface $output)

if (isset($encrypted) && false === $input->getOption('encrypt-only')) {
try {
$decrypted = $this->shh->decrypt($encrypted);
$decrypted = $shh->decrypt($encrypted);

if ('foo' !== $decrypted) {
throw new \RuntimeException('Unexpected decrypted value.');
Expand All @@ -105,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output)

if (null !== $input->getOption('payload')) {
try {
$this->shh->decrypt($input->getOption('payload'));
$shh->decrypt($input->getOption('payload'));
} catch (\Throwable $e) {
$errors[] = 'The given payload could not be decrypted.';
$io->error(\end($errors));
Expand Down
30 changes: 5 additions & 25 deletions src/Command/GenerateKeyPairCommand.php
Expand Up @@ -8,34 +8,26 @@
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Kernel;

final class GenerateKeyPairCommand extends Command
{
protected static $defaultName = 'shh:generate:keys';

/**
* @var ContainerInterface
* @var string
*/
private $container;

/**
* @var Shh
*/
private $shh;
private $keysDirectory;

/**
* @var Filesystem
*/
private $fs;

public function __construct(ContainerInterface $container, Shh $shh, Filesystem $fs)
public function __construct(string $keysDirectory, Filesystem $fs)
{
parent::__construct();
$this->container = $container;
$this->shh = $shh;
$this->keysDirectory = $keysDirectory;
$this->fs = $fs;
}

Expand Down Expand Up @@ -80,7 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$io = new SymfonyStyle($input, $output);

$passphrase = $input->getOption('passphrase');
$dir = $this->getDirectory();
$dir = $this->keysDirectory;

if ($this->fs->exists($dir.'/private.pem') || $this->fs->exists($dir.'/private.pem')) {
$io->error(\sprintf("Keys are already defined in %s.", $dir));
Expand All @@ -100,16 +92,4 @@ protected function execute(InputInterface $input, OutputInterface $output)
$io->comment('Don\'t forget to report your passphrase into the SHH_PASSPHRASE environment variable.');
}
}

/**
* @return string
*/
private function getDirectory()
{
if (Kernel::MAJOR_VERSION < 4) {
return $this->container->getParameter('kernel.project_dir').'/app/config/shh';
}

return $this->container->getParameter('kernel.project_dir').'/config/shh';
}
}
16 changes: 8 additions & 8 deletions src/Command/RegisterSecretCommand.php
Expand Up @@ -13,7 +13,7 @@

final class RegisterSecretCommand extends Command
{
protected static $defaultName = 'shh:register-secret';
protected static $defaultName = 'shh:register:secret';

/**
* @var Shh
Expand All @@ -40,10 +40,14 @@ public function __construct(Shh $shh, Filesystem $fs, string $secretsFile)

protected function configure()
{
$this->setDescription(sprintf('Register a new secret into %s', $this->secretsFile))
$this->setDescription('Register a new secret.')
->addArgument('key', InputArgument::REQUIRED, 'The secret\'s key name.')
->addArgument('value', InputArgument::REQUIRED, 'The secret\'s value.')
->addOption('no-encrypt', null, InputOption::VALUE_NONE, 'If the value should not be encrypted.');
->addOption('no-encrypt', null, InputOption::VALUE_NONE, 'If the value should not be encrypted.')
->setAliases([
'shh:register-secret', // Avoid BC breaks
])
;
}

protected function interact(InputInterface $input, OutputInterface $output)
Expand Down Expand Up @@ -74,10 +78,6 @@ function ($key) {
)
);
}

if (false === $input->getOption('no-encrypt')) {
$input->setOption('no-encrypt', !$io->confirm('Should I encrypt this value?'));
}
}

protected function execute(InputInterface $input, OutputInterface $output)
Expand Down Expand Up @@ -106,7 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
$secrets = [];
} else {
$content = \file_get_contents($this->secretsFile);
$secrets = \json_decode($content, true);
$secrets = '' === $content ? [] : \json_decode($content, true);
if (\JSON_ERROR_NONE !== \json_last_error()) {
$io->error('json_decode error: ' . \json_last_error_msg());

Expand Down
14 changes: 14 additions & 0 deletions src/DependencyInjection/ShhExtension.php
Expand Up @@ -6,6 +6,7 @@
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\HttpKernel\Kernel;

final class ShhExtension extends Extension
{
Expand All @@ -21,8 +22,21 @@ public function load(array $configs, ContainerBuilder $container)
$container->setParameter('shh.private_key_file', $config['private_key_file']);
$container->setParameter('shh.public_key_file', $config['public_key_file']);
$container->setParameter('shh.passphrase', $config['passphrase']);
$container->setParameter('shh.keys_dir', $this->guessKeysDirectory($container));

$loader = new XmlFileLoader($container, new FileLocator(\dirname(__DIR__).'/Resources/config'));
$loader->load('services.xml');
}

/**
* @return string
*/
private function guessKeysDirectory(ContainerBuilder $container)
{
if (Kernel::MAJOR_VERSION < 4) {
return $container->getParameter('kernel.project_dir').'/app/config/shh';
}

return $container->getParameter('kernel.project_dir').'/config/shh';
}
}
7 changes: 3 additions & 4 deletions src/Resources/config/services.xml
Expand Up @@ -28,16 +28,14 @@
</service>

<service id="BenTools\Shh\Command\CheckCommand" class="BenTools\Shh\Command\CheckCommand">
<argument type="service" id="BenTools\Shh\Shh"/>
<argument type="string">%shh.public_key_file%</argument>
<argument type="string">%shh.private_key_file%</argument>
<argument type="string">%shh.passphrase%</argument>
<tag name="console.command" />
</service>

<service id="BenTools\Shh\Command\GenerateKeyPairCommand" class="BenTools\Shh\Command\GenerateKeyPairCommand">
<argument type="service" id="service_container"/>
<argument type="service" id="BenTools\Shh\Shh"/>
<argument type="string">%shh.keys_dir%</argument>
<argument type="service" id="Symfony\Component\Filesystem\Filesystem"/>
<tag name="console.command" />
</service>
Expand All @@ -50,9 +48,10 @@
</service>

<service id="BenTools\Shh\Command\ChangePassphraseCommand" class="BenTools\Shh\Command\ChangePassphraseCommand">
<argument type="service" id="service_container"/>
<argument type="service" id="BenTools\Shh\Shh"/>
<argument type="service" id="Symfony\Component\Filesystem\Filesystem"/>
<argument type="string">%shh.keys_dir%</argument>
<argument type="string">%shh.private_key_file%</argument>
<tag name="console.command" />
</service>

Expand Down
6 changes: 3 additions & 3 deletions src/Shh.php
Expand Up @@ -36,7 +36,7 @@ final class Shh
public function __construct(string $publicKey, ?string $privateKey = null, ?string $passphrase = null)
{
$this->publicKey = self::normalize($publicKey);
$this->privateKey = self::normalize($privateKey);
$this->privateKey = null === $privateKey ? null : self::normalize($privateKey);
$this->passphrase = $passphrase;
}

Expand Down Expand Up @@ -105,7 +105,7 @@ public function decrypt(string $base64EncodedPayload): string
* @param array $config
* @return array - [privateKey, publicKey]
*/
public static function generateKeyPair(?string $passphrase = null, array $config = self::DEFAULT_OPENSSL_GENERATION_CONFIGURATION)
public static function generateKeyPair(?string $passphrase = null, array $config = self::DEFAULT_OPENSSL_GENERATION_CONFIGURATION): array
{
$resource = \openssl_pkey_new($config)
or ShhException::throwFromLastOpenSSLError('Unable to open resource.');
Expand Down Expand Up @@ -145,7 +145,7 @@ public static function changePassphrase(string $privateKey, ?string $oldPassphra
* @param string $key
* @return string
*/
public static function normalize(string $key): string
private static function normalize(string $key): string
{
return (0 === \strpos($key, '/')) ? 'file://'.$key : $key;
}
Expand Down
3 changes: 3 additions & 0 deletions src/ShhException.php
Expand Up @@ -2,6 +2,9 @@

namespace BenTools\Shh;

/**
* @internal
*/
final class ShhException extends \RuntimeException
{
/**
Expand Down
2 changes: 1 addition & 1 deletion tests/BundleTest.php
Expand Up @@ -12,7 +12,7 @@

final class BundleTest extends KernelTestCase
{
protected function setUp()
protected function setUp(): void
{
static::bootKernel();
}
Expand Down

0 comments on commit 2067d74

Please sign in to comment.