Skip to content

Commit 6e951b7

Browse files
feat: interactive env:encrypt & env:decrypt (#53081)
* feat: add interactive mode for env:encrypt & env:decrypt * style: remove whitespace changes * feat: use password prompt & isInteractive() * style: added end of line comma in array * test: change/provide tests for interactive mode * style: remove empty line * formatting --------- Co-authored-by: Taylor Otwell <[email protected]>
1 parent 34f5ef6 commit 6e951b7

File tree

4 files changed

+73
-0
lines changed

4 files changed

+73
-0
lines changed

src/Illuminate/Foundation/Console/EnvironmentDecryptCommand.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
use Illuminate\Support\Str;
1111
use Symfony\Component\Console\Attribute\AsCommand;
1212

13+
use function Laravel\Prompts\password;
14+
1315
#[AsCommand(name: 'env:decrypt')]
1416
class EnvironmentDecryptCommand extends Command
1517
{
@@ -62,6 +64,10 @@ public function handle()
6264
{
6365
$key = $this->option('key') ?: Env::get('LARAVEL_ENV_ENCRYPTION_KEY');
6466

67+
if (! $key && $this->input->isInteractive()) {
68+
$key = password('What is the decryption key?');
69+
}
70+
6571
if (! $key) {
6672
$this->fail('A decryption key is required.');
6773
}

src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
use Illuminate\Support\Str;
1010
use Symfony\Component\Console\Attribute\AsCommand;
1111

12+
use function Laravel\Prompts\password;
13+
use function Laravel\Prompts\select;
14+
1215
#[AsCommand(name: 'env:encrypt')]
1316
class EnvironmentEncryptCommand extends Command
1417
{
@@ -62,6 +65,21 @@ public function handle()
6265

6366
$key = $this->option('key');
6467

68+
if (! $key && $this->input->isInteractive()) {
69+
$ask = select(
70+
label: 'What encryption key would you like to use?',
71+
options: [
72+
'generate' => 'Generate a random encryption key',
73+
'ask' => 'Provide an encryption key',
74+
],
75+
default: 'generate'
76+
);
77+
78+
if ($ask == 'ask') {
79+
$key = password('What is the encryption key?');
80+
}
81+
}
82+
6583
$keyPassed = $key !== null;
6684

6785
$environmentFile = $this->option('env')

tests/Integration/Console/EnvironmentDecryptCommandTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,28 @@ public function testItCannotOverwriteEncryptedFiles()
284284
->expectsOutputToContain('Invalid filename.')
285285
->assertExitCode(1);
286286
}
287+
288+
public function testItGeneratesTheEnvironmentFileWithInteractivelyUserProvidedKey()
289+
{
290+
$this->filesystem->shouldReceive('exists')
291+
->once()
292+
->andReturn(true)
293+
->shouldReceive('exists')
294+
->once()
295+
->andReturn(false)
296+
->shouldReceive('get')
297+
->once()
298+
->andReturn(
299+
(new Encrypter($key = 'abcdefghijklmnop', 'aes-128-gcm'))
300+
->encrypt('APP_NAME="Laravel Two"')
301+
);
302+
303+
$this->artisan('env:decrypt', ['--cipher' => 'aes-128-gcm'])
304+
->expectsQuestion('What is the decryption key?', $key)
305+
->expectsOutputToContain('Environment successfully decrypted.')
306+
->assertExitCode(0);
307+
308+
$this->filesystem->shouldHaveReceived('put')
309+
->with(base_path('.env'), 'APP_NAME="Laravel Two"');
310+
}
287311
}

tests/Integration/Console/EnvironmentEncryptCommandTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public function testItFailsWithInvalidCipherFails()
3434
->andReturn(false);
3535

3636
$this->artisan('env:encrypt', ['--cipher' => 'invalid'])
37+
->expectsQuestion('What encryption key would you like to use?', 'generate')
3738
->expectsOutputToContain('Unsupported cipher')
3839
->assertExitCode(1);
3940
}
@@ -62,6 +63,7 @@ public function testItGeneratesTheCorrectFileWhenUsingEnvironment()
6263
->andReturn(false);
6364

6465
$this->artisan('env:encrypt', ['--env' => 'production'])
66+
->expectsQuestion('What encryption key would you like to use?', 'generate')
6567
->expectsOutputToContain('.env.production.encrypted')
6668
->assertExitCode(0);
6769

@@ -80,6 +82,7 @@ public function testItGeneratesTheCorrectFileWhenNotUsingEnvironment()
8082
->shouldReceive('get');
8183

8284
$this->artisan('env:encrypt')
85+
->expectsQuestion('What encryption key would you like to use?', 'generate')
8386
->expectsOutputToContain('.env.encrypted')
8487
->assertExitCode(0);
8588

@@ -92,6 +95,7 @@ public function testItFailsWhenEnvironmentFileCannotBeFound()
9295
$this->filesystem->shouldReceive('exists')->andReturn(false);
9396

9497
$this->artisan('env:encrypt')
98+
->expectsQuestion('What encryption key would you like to use?', 'generate')
9599
->expectsOutputToContain('Environment file not found.')
96100
->assertExitCode(1);
97101
}
@@ -101,6 +105,7 @@ public function testItFailsWhenEncryptionFileExists()
101105
$this->filesystem->shouldReceive('exists')->andReturn(true);
102106

103107
$this->artisan('env:encrypt')
108+
->expectsQuestion('What encryption key would you like to use?', 'generate')
104109
->expectsOutputToContain('Encrypted environment file already exists.')
105110
->assertExitCode(1);
106111
}
@@ -115,6 +120,7 @@ public function testItGeneratesTheEncryptionFileWhenForcing()
115120
->andReturn(true);
116121

117122
$this->artisan('env:encrypt', ['--force' => true])
123+
->expectsQuestion('What encryption key would you like to use?', 'generate')
118124
->expectsOutputToContain('.env.encrypted')
119125
->assertExitCode(0);
120126

@@ -166,6 +172,7 @@ public function testItCanRemoveTheOriginalFile()
166172
->andReturn(false);
167173

168174
$this->artisan('env:encrypt', ['--prune' => true])
175+
->expectsQuestion('What encryption key would you like to use?', 'generate')
169176
->expectsOutputToContain('.env.encrypted')
170177
->assertExitCode(0);
171178

@@ -175,4 +182,22 @@ public function testItCanRemoveTheOriginalFile()
175182
$this->filesystem->shouldHaveReceived('delete')
176183
->with(base_path('.env'));
177184
}
185+
186+
public function testItEncryptsWithInteractivelyGivenKeyAndDisplaysIt()
187+
{
188+
$this->filesystem->shouldReceive('exists')
189+
->once()
190+
->andReturn(true)
191+
->shouldReceive('exists')
192+
->once()
193+
->andReturn(false);
194+
195+
$this->artisan('env:encrypt')
196+
->expectsQuestion('What encryption key would you like to use?', 'ask')
197+
->expectsQuestion('What is the encryption key?', $key = 'ANvVbPbE0tWMHpUySh6liY4WaCmAYKXP')
198+
->expectsOutputToContain('Environment successfully encrypted')
199+
->expectsOutputToContain($key)
200+
->expectsOutputToContain('.env.encrypted')
201+
->assertExitCode(0);
202+
}
178203
}

0 commit comments

Comments
 (0)