Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions system/Commands/Encryption/GenerateKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

use CodeIgniter\CLI\AbstractCommand;
use CodeIgniter\CLI\Attributes\Command;
use CodeIgniter\CLI\CLI;
use CodeIgniter\CLI\Input\Option;
use CodeIgniter\Config\DotEnv;
use CodeIgniter\Encryption\Encryption;
Expand Down Expand Up @@ -81,25 +80,26 @@ protected function interact(array &$arguments, array &$options): void
return;
}

if (CLI::prompt('Overwrite existing key?', ['n', 'y']) === 'y') {
if ($this->getPrompt()->ask('Overwrite existing key?', ['n', 'y']) === 'y') {
$options['force'] = null; // simulate the presence of the --force option
}
}

protected function execute(array $arguments, array $options): int
{
$prefix = $options['prefix'];
$output = $this->getOutput();

if (! in_array($prefix, self::VALID_PREFIXES, true)) {
CLI::error(sprintf('Invalid prefix "%s". Use either "hex2bin" or "base64".', $prefix));
$output->error(sprintf('Invalid prefix "%s". Use either "hex2bin" or "base64".', $prefix));

return EXIT_ERROR;
}

$encodedKey = $this->generateRandomKey($prefix, (int) $options['length']);

if ($options['show'] === true) {
CLI::write($encodedKey, 'yellow');
$output->write($encodedKey, 'yellow');

return EXIT_SUCCESS;
}
Expand All @@ -108,12 +108,12 @@ protected function execute(array $arguments, array $options): int

if ($currentKey !== '' && $options['force'] === false) {
if ($this->isInteractive()) {
CLI::write('Setting new encryption key cancelled.', 'yellow');
$output->write('Setting new encryption key cancelled.', 'yellow');

return EXIT_SUCCESS;
}

CLI::error('Setting new encryption key aborted: pass --force to overwrite the existing key in non-interactive mode.');
$output->error('Setting new encryption key aborted: pass --force to overwrite the existing key in non-interactive mode.');

return EXIT_ERROR;
}
Expand All @@ -122,14 +122,14 @@ protected function execute(array $arguments, array $options): int
$baseEnv = ROOTPATH . 'env';

if (! is_file($envFile) && ! is_file($baseEnv)) {
CLI::write('Both default shipped `env` file and custom `.env` are missing.', 'yellow');
CLI::write(sprintf('Here\'s your new key instead: %s', CLI::color($encodedKey, 'yellow')));
$output->write('Both default shipped `env` file and custom `.env` are missing.', 'yellow');
$output->write(sprintf('Here\'s your new key instead: %s', $output->color($encodedKey, 'yellow')));

return EXIT_ERROR;
}

if (! $this->writeNewEncryptionKeyToFile($encodedKey, $envFile, $baseEnv)) {
CLI::error(sprintf('Failed to write new encryption key to %s.', clean_path($envFile)));
$output->error(sprintf('Failed to write new encryption key to %s.', clean_path($envFile)));

return EXIT_ERROR;
}
Expand All @@ -141,8 +141,7 @@ protected function execute(array $arguments, array $options): int
$dotenv = new DotEnv((new Paths())->envDirectory ?? ROOTPATH); // @phpstan-ignore nullCoalesce.property
$dotenv->load();

CLI::write(sprintf('New encryption key written to %s.', clean_path($envFile)), 'green');
CLI::newLine();
$output->write(sprintf('New encryption key written to %s.', clean_path($envFile)), 'green');

return EXIT_SUCCESS;
}
Expand Down
26 changes: 13 additions & 13 deletions system/Commands/Encryption/RotateKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

use CodeIgniter\CLI\AbstractCommand;
use CodeIgniter\CLI\Attributes\Command;
use CodeIgniter\CLI\CLI;
use CodeIgniter\CLI\Input\Option;
use Config\Paths;

Expand Down Expand Up @@ -81,53 +80,54 @@ protected function interact(array &$arguments, array &$options): void
return;
}

if (CLI::prompt('Rotate encryption key? The current key will be moved to `previousKeys`.', ['n', 'y']) === 'y') {
if ($this->getPrompt()->ask('Rotate encryption key? The current key will be moved to `previousKeys`.', ['n', 'y']) === 'y') {
$options['force'] = null; // simulate the presence of the --force option
}
}

protected function execute(array $arguments, array $options): int
{
$prefix = $options['prefix'];
$output = $this->getOutput();

if (! in_array($prefix, self::VALID_PREFIXES, true)) {
CLI::error(sprintf('Invalid prefix "%s". Use either "hex2bin" or "base64".', $prefix));
$output->error(sprintf('Invalid prefix "%s". Use either "hex2bin" or "base64".', $prefix));

return EXIT_ERROR;
}

$currentKey = env('encryption.key', '');

if ($currentKey === '') {
CLI::error('No existing `encryption.key` to rotate. Run `spark key:generate` first.');
$output->error('No existing `encryption.key` to rotate. Run `spark key:generate` first.');

return EXIT_ERROR;
}

if ($options['force'] === false) {
if ($this->isInteractive()) {
CLI::write('Key rotation cancelled.', 'yellow');
$output->write('Key rotation cancelled.', 'yellow');

return EXIT_SUCCESS;
}

CLI::error('Key rotation aborted: pass --force to rotate the encryption key in non-interactive mode.');
$output->error('Key rotation aborted: pass --force to rotate the encryption key in non-interactive mode.');

return EXIT_ERROR;
}

$keep = $options['keep'];

if (! is_string($keep) || ! ctype_digit($keep)) {
CLI::error('The --keep option must be a non-negative integer.');
$output->error('The --keep option must be a non-negative integer.');

return EXIT_ERROR;
}

$length = $options['length'];

if (! is_string($length) || ! ctype_digit($length) || (int) $length < 1) {
CLI::error('The --length option must be a positive integer.');
$output->error('The --length option must be a positive integer.');

return EXIT_ERROR;
}
Expand All @@ -140,20 +140,20 @@ protected function execute(array $arguments, array $options): int
$envFile = ((new Paths())->envDirectory ?? ROOTPATH) . '.env'; // @phpstan-ignore nullCoalesce.property

if (! is_file($envFile)) {
CLI::error(sprintf('Cannot rotate: `.env` file not found at %s.', clean_path($envFile)));
$output->error(sprintf('Cannot rotate: `.env` file not found at %s.', clean_path($envFile)));

return EXIT_ERROR;
}

if (! is_writable($envFile)) {
CLI::error(sprintf('Cannot rotate: `.env` file at %s is not writable.', clean_path($envFile)));
$output->error(sprintf('Cannot rotate: `.env` file at %s is not writable.', clean_path($envFile)));

return EXIT_ERROR;
}

if (! $this->writePreviousKeys($previousKeys, $envFile)) {
// @codeCoverageIgnoreStart
CLI::error(sprintf('Failed to write `encryption.previousKeys` to %s.', clean_path($envFile)));
$output->error(sprintf('Failed to write `encryption.previousKeys` to %s.', clean_path($envFile)));

return EXIT_ERROR;
// @codeCoverageIgnoreEnd
Expand All @@ -178,12 +178,12 @@ protected function execute(array $arguments, array $options): int

$count = count($previousKeys);

CLI::write(sprintf(
$output->write(sprintf(
'Encryption key rotated. %d %s retained for decryption fallback.',
$count,
$count === 1 ? 'previous key' : 'previous keys',
), 'green');
CLI::write('Re-encrypt existing data with the new key when ready.', 'yellow');
$output->write('Re-encrypt existing data with the new key when ready.', 'yellow');

return EXIT_SUCCESS;
}
Expand Down
44 changes: 22 additions & 22 deletions system/Commands/Help.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

use CodeIgniter\CLI\AbstractCommand;
use CodeIgniter\CLI\Attributes\Command;
use CodeIgniter\CLI\CLI;
use CodeIgniter\CLI\Input\Argument;
use CodeIgniter\CLI\Input\Option;
use CodeIgniter\CLI\Output;

/**
* Displays the basic usage information for a given command.
Expand Down Expand Up @@ -51,57 +51,57 @@ protected function execute(array $arguments, array $options): int
return EXIT_ERROR;
}

$this->describeHelp($commands->getCommand($command, legacy: false));
$this->describeHelp($commands->getCommand($command, legacy: false), $this->getOutput());

return EXIT_SUCCESS;
}

private function describeHelp(AbstractCommand $command): void
private function describeHelp(AbstractCommand $command, Output $output): void
{
CLI::write(lang('CLI.helpUsage'), 'yellow');
$output->write(lang('CLI.helpUsage'), 'yellow');

foreach ($command->getUsages() as $usage) {
CLI::write($this->addPadding($usage));
$output->write($this->addPadding($usage));
}

if ($command->getDescription() !== '') {
CLI::newLine();
CLI::write(lang('CLI.helpDescription'), 'yellow');
CLI::write($this->addPadding($command->getDescription()));
$output->newLine();
$output->write(lang('CLI.helpDescription'), 'yellow');
$output->write($this->addPadding($command->getDescription()));
}

if ($command->getAliases() !== []) {
CLI::newLine();
CLI::write(lang('CLI.helpAliases'), 'yellow');
$output->newLine();
$output->write(lang('CLI.helpAliases'), 'yellow');

foreach ($command->getAliases() as $alias) {
CLI::write($this->addPadding($alias));
$output->write($this->addPadding($alias));
}
}

$maxPadding = $this->getMaxPadding($command);

if ($command->getArgumentsDefinition() !== []) {
CLI::newLine();
CLI::write(lang('CLI.helpArguments'), 'yellow');
$output->newLine();
$output->write(lang('CLI.helpArguments'), 'yellow');

foreach ($command->getArgumentsDefinition() as $argument => $definition) {
$default = ! $definition->required && $this->shouldShowDefault($definition->default)
? sprintf(' [default: %s]', $this->formatDefaultValue($definition->default))
: '';

CLI::write(sprintf(
$output->write(sprintf(
'%s%s%s',
CLI::color($this->addPadding($argument, 2, $maxPadding), 'green'),
$output->color($this->addPadding($argument, 2, $maxPadding), 'green'),
$definition->description,
CLI::color($default, 'yellow'),
$output->color($default, 'yellow'),
));
}
}

if ($command->getOptionsDefinition() !== []) {
CLI::newLine();
CLI::write(lang('CLI.helpOptions'), 'yellow');
$output->newLine();
$output->write(lang('CLI.helpOptions'), 'yellow');

$hasShortcuts = $command->getShortcuts() !== [];

Expand Down Expand Up @@ -130,12 +130,12 @@ private function describeHelp(AbstractCommand $command): void
? sprintf(' [default: %s]', $this->formatDefaultValue($definition->default))
: '';

CLI::write(sprintf(
$output->write(sprintf(
'%s%s%s%s',
CLI::color($this->addPadding($optionString, 2, $maxPadding), 'green'),
$output->color($this->addPadding($optionString, 2, $maxPadding), 'green'),
$definition->description,
CLI::color($default, 'yellow'),
$definition->isArray ? CLI::color(' (multiple values allowed)', 'yellow') : '',
$output->color($default, 'yellow'),
$definition->isArray ? $output->color(' (multiple values allowed)', 'yellow') : '',
));
}
}
Expand Down
32 changes: 17 additions & 15 deletions system/Commands/ListCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

use CodeIgniter\CLI\AbstractCommand;
use CodeIgniter\CLI\Attributes\Command;
use CodeIgniter\CLI\CLI;
use CodeIgniter\CLI\Input\Option;
use CodeIgniter\CLI\Output;

/**
* Lists the available commands.
Expand All @@ -34,14 +34,16 @@ protected function configure(): void

protected function execute(array $arguments, array $options): int
{
$output = $this->getOutput();

if ($options['simple'] === true) {
return $this->describeCommandsSimple();
return $this->describeCommandsSimple($output);
}

return $this->describeCommandsDetailed();
return $this->describeCommandsDetailed($output);
}

private function describeCommandsSimple(): int
private function describeCommandsSimple(Output $output): int
{
// Legacy takes precedence on key collision so the listing reflects the
// command that would actually be invoked.
Expand All @@ -53,16 +55,16 @@ private function describeCommandsSimple(): int
sort($commands);

foreach ($commands as $command) {
CLI::write($command);
$output->write($command);
}

return EXIT_SUCCESS;
}

private function describeCommandsDetailed(): int
private function describeCommandsDetailed(Output $output): int
{
CLI::write(lang('CLI.helpUsage'), 'yellow');
CLI::write($this->addPadding('command [options] [--] [arguments]'));
$output->write(lang('CLI.helpUsage'), 'yellow');
$output->write($this->addPadding('command [options] [--] [arguments]'));

$entries = [];
$maxPad = 0;
Expand Down Expand Up @@ -110,23 +112,23 @@ private function describeCommandsDetailed(): int
$groups[$group][] = [$command, $description];
}

CLI::newLine();
CLI::write(lang('CLI.helpAvailableCommands'), 'yellow');
$output->newLine();
$output->write(lang('CLI.helpAvailableCommands'), 'yellow');

$firstGroup = array_key_first($groups);

foreach ($groups as $group => $commands) {
if ($group !== $firstGroup) {
CLI::newLine();
$output->newLine();
}

CLI::write($group, 'yellow');
$output->write($group, 'yellow');

foreach ($commands as $command) {
CLI::write(sprintf(
$output->write(sprintf(
'%s%s',
CLI::color($this->addPadding($command[0], 2, $maxPad), 'green'),
CLI::wrap($command[1], 0, $maxPad),
$output->color($this->addPadding($command[0], 2, $maxPad), 'green'),
$output->wrap($command[1], 0, $maxPad),
));
}
}
Expand Down
Loading