Skip to content

Commit 9fe6d5b

Browse files
committed
Add environment encryption commands
1 parent 607e4fd commit 9fe6d5b

File tree

5 files changed

+502
-13
lines changed

5 files changed

+502
-13
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?php
2+
3+
namespace Illuminate\Foundation\Console;
4+
5+
use Exception;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Encryption\Encrypter;
8+
use Illuminate\Filesystem\Filesystem;
9+
use Illuminate\Support\Env;
10+
use Illuminate\Support\Str;
11+
use Symfony\Component\Console\Attribute\AsCommand;
12+
13+
#[AsCommand(name: 'env:decrypt')]
14+
class EnvironmentDecryptCommand extends Command
15+
{
16+
/**
17+
* The name and signature of the console command.
18+
*
19+
* @var string
20+
*/
21+
protected $signature = 'env:decrypt
22+
{--key= : The encryption key}
23+
{--cipher= : The encryption cipher}
24+
{--env= : The environment to be decrypted}
25+
{--force : Overwrite existing environment file}';
26+
27+
/**
28+
* The name of the console command.
29+
*
30+
* This name is used to identify the command during lazy loading.
31+
*
32+
* @var string|null
33+
*
34+
* @deprecated
35+
*/
36+
protected static $defaultName = 'env:decrypt';
37+
38+
/**
39+
* The console command description.
40+
*
41+
* @var string
42+
*/
43+
protected $description = 'Decrypt the given environment file';
44+
45+
/**
46+
* The filesystem instance.
47+
*
48+
* @var \Illuminate\Filesystem\Filesystem
49+
*/
50+
protected $files;
51+
52+
public function __construct(Filesystem $files)
53+
{
54+
parent::__construct();
55+
56+
$this->files = $files;
57+
}
58+
59+
/**
60+
* Execute the console command.
61+
*
62+
* @return void
63+
*/
64+
public function handle()
65+
{
66+
$key = $this->option('key') ?: Env::get('LARAVEL_ENV_ENCRYPTION_KEY');
67+
68+
if (! $key) {
69+
$this->components->error('A decryption key is required.');
70+
71+
return Command::FAILURE;
72+
}
73+
74+
$cipher = $this->option('cipher') ?: 'aes-128-cbc';
75+
$key = $this->parseKey($key);
76+
$environmentFile = $this->option('env')
77+
? base_path('.env').'.'.$this->option('env')
78+
: $this->laravel->environmentFilePath();
79+
$encryptedFile = $environmentFile.'.encrypted';
80+
81+
if (! $this->files->exists($encryptedFile)) {
82+
$this->components->error('Encrypted environment file not found.');
83+
84+
return Command::FAILURE;
85+
}
86+
87+
if ($this->files->exists($environmentFile) && ! $this->option('force')) {
88+
$this->components->error('Environment file already exists.');
89+
90+
return Command::FAILURE;
91+
}
92+
93+
try {
94+
$encrypter = new Encrypter($key, $cipher);
95+
96+
$this->files->put(
97+
$environmentFile,
98+
$encrypter->decrypt($this->files->get($encryptedFile))
99+
);
100+
} catch (Exception $e) {
101+
$this->components->error($e->getMessage());
102+
103+
return Command::FAILURE;
104+
}
105+
106+
$this->components->info('Environment successfully decrypted.');
107+
}
108+
109+
/**
110+
* Parse the encryption key.
111+
*
112+
* @param string $key
113+
* @return string
114+
*/
115+
protected function parseKey(string $key)
116+
{
117+
if (Str::startsWith($key, $prefix = 'base64:')) {
118+
$key = base64_decode(Str::after($key, $prefix));
119+
}
120+
121+
return $key;
122+
}
123+
}

src/Illuminate/Foundation/Console/EnvironmentEncryptCommand.php

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
namespace Illuminate\Foundation\Console;
44

5+
use Exception;
56
use Illuminate\Console\Command;
67
use Illuminate\Encryption\Encrypter;
78
use Illuminate\Filesystem\Filesystem;
8-
use Illuminate\Support\Str;
9+
use Illuminate\Support\Env;
910
use Symfony\Component\Console\Attribute\AsCommand;
1011

1112
#[AsCommand(name: 'env:encrypt')]
@@ -19,8 +20,8 @@ class EnvironmentEncryptCommand extends Command
1920
protected $signature = 'env:encrypt
2021
{--key= : The encryption key}
2122
{--cipher= : The encryption cipher}
22-
{--file= : The environment file to be decrypted}
23-
{--force : Overwrite any existing files}';
23+
{--env= : The environment to be encrypted}
24+
{--force : Overwrite existing encrypted environment file}';
2425

2526
/**
2627
* The name of the console command.
@@ -61,23 +62,48 @@ public function __construct(Filesystem $files)
6162
*/
6263
public function handle()
6364
{
64-
$key = $this->option('key') ?: Str::random(16);
6565
$cipher = $this->option('cipher') ?: 'aes-128-cbc';
66-
$environment = $this->option('file') ?: $this->laravel->environmentFilePath();
67-
$encrypted = $environment.'.encrypted';
66+
$key = $keyPassed = $this->option('key') ?: Env::get('ENVIRONMENT_ENCRYPTION_KEY');
67+
$environmentFile = $this->option('env')
68+
? base_path('.env').'.'.$this->option('env')
69+
: $this->laravel->environmentFilePath();
70+
$encryptedFile = $environmentFile.'.encrypted';
6871

69-
if (! $this->files->exists($environment)) {
70-
return $this->components->error("The environment file {$environment} does not exist.");
72+
if (! $keyPassed) {
73+
$key = Encrypter::generateKey($cipher);
7174
}
7275

73-
if ($this->files->exists($encrypted) && ! $this->option('force')) {
74-
return $this->components->error("The encrypted environment file {$encrypted} already exists.");
76+
if (! $this->files->exists($environmentFile)) {
77+
$this->components->error('Environment file not found.');
78+
79+
return Command::FAILURE;
80+
}
81+
82+
if ($this->files->exists($encryptedFile) && ! $this->option('force')) {
83+
$this->components->error('Encrypted environment file already exists.');
84+
85+
return Command::FAILURE;
7586
}
7687

77-
$encrypter = new Encrypter($key, $cipher);
88+
try {
89+
$encrypter = new Encrypter($key, $cipher);
90+
91+
$this->files->put(
92+
$encryptedFile,
93+
$encrypter->encrypt($this->files->get($environmentFile))
94+
);
95+
} catch (Exception $e) {
96+
$this->components->error($e->getMessage());
7897

79-
$this->files->put($encrypted, $encrypter->encrypt($this->files->get($environment)));
98+
return Command::FAILURE;
99+
}
80100

81-
$this->components->info("The environment file {$environment} has been encrypted using they key {$key}.");
101+
$this->components->info('Environment successfully encrypted.');
102+
$this->components->bulletList([
103+
'Key: '.($keyPassed ? $key : 'base64:'.base64_encode($key)),
104+
"Cipher: {$cipher}",
105+
"File: {$encryptedFile}",
106+
]);
107+
$this->newLine();
82108
}
83109
}

src/Illuminate/Foundation/Providers/ArtisanServiceProvider.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use Illuminate\Foundation\Console\DocsCommand;
3535
use Illuminate\Foundation\Console\DownCommand;
3636
use Illuminate\Foundation\Console\EnvironmentCommand;
37+
use Illuminate\Foundation\Console\EnvironmentDecryptCommand;
3738
use Illuminate\Foundation\Console\EnvironmentEncryptCommand;
3839
use Illuminate\Foundation\Console\EventCacheCommand;
3940
use Illuminate\Foundation\Console\EventClearCommand;
@@ -113,6 +114,7 @@ class ArtisanServiceProvider extends ServiceProvider implements DeferrableProvid
113114
'DbWipe' => WipeCommand::class,
114115
'Down' => DownCommand::class,
115116
'Environment' => EnvironmentCommand::class,
117+
'EnvironmentDecrypt' => EnvironmentDecryptCommand::class,
116118
'EnvironmentEncrypt' => EnvironmentEncryptCommand::class,
117119
'EventCache' => EventCacheCommand::class,
118120
'EventClear' => EventClearCommand::class,
@@ -509,6 +511,16 @@ protected function registerEnvironmentCommand()
509511
$this->app->singleton(EnvironmentCommand::class);
510512
}
511513

514+
/**
515+
* Register the command.
516+
*
517+
* @return void
518+
*/
519+
protected function registerEnvironmentDecryptCommand()
520+
{
521+
$this->app->singleton(EnvironmentDecryptCommand::class);
522+
}
523+
512524
/**
513525
* Register the command.
514526
*

0 commit comments

Comments
 (0)