mirror of
https://github.com/snipe/snipe-it.git
synced 2025-01-13 06:47:46 -08:00
Modified re-crypter to also work when given a CLI old-key
This commit is contained in:
parent
8c7edcb357
commit
ca430ec9b3
|
@ -7,6 +7,7 @@ use App\Models\CustomField;
|
||||||
use App\Models\Setting;
|
use App\Models\Setting;
|
||||||
use Artisan;
|
use Artisan;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Contracts\Encryption\DecryptException;
|
||||||
use Illuminate\Encryption\Encrypter;
|
use Illuminate\Encryption\Encrypter;
|
||||||
|
|
||||||
class RotateAppKey extends Command
|
class RotateAppKey extends Command
|
||||||
|
@ -16,14 +17,17 @@ class RotateAppKey extends Command
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'snipeit:rotate-key';
|
protected $signature = 'snipeit:rotate-key
|
||||||
|
{previous_key? : The previous key to rotate from}
|
||||||
|
{--emergency : Emergency mode - rotate from .env APP_KEY to newly-generated one, modifying .env}
|
||||||
|
{--force : Skip interactive confirmation}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $description = 'Command description';
|
protected $description = 'Rotates APP_KEY to a new value, optionally taking the previous key as an argument';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new command instance.
|
* Create a new command instance.
|
||||||
|
@ -42,26 +46,42 @@ class RotateAppKey extends Command
|
||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
if ($this->confirm("\n****************************************************\nTHIS WILL MODIFY YOUR APP_KEY AND DE-CRYPT YOUR ENCRYPTED CUSTOM FIELDS AND \nRE-ENCRYPT THEM WITH A NEWLY GENERATED KEY. \n\nThere is NO undo. \n\nMake SURE you have a database backup and a backup of your .env generated BEFORE running this command. \n\nIf you do not save the newly generated APP_KEY to your .env in this process, \nyour encrypted data will no longer be decryptable. \n\nAre you SURE you wish to continue, and have confirmed you have a database backup and an .env backup? ")) {
|
//make sure they specify only exactly one of --emergency, or a filename. Not neither, and not both.
|
||||||
|
if ( (!$this->option('emergency') && !$this->argument('previous_key')) || ( $this->option('emergency') && $this->argument('previous_key'))) {
|
||||||
|
$this->error("Specify only one of --emergency, or an app key value, in order to rotate keys");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ( $this->option('emergency') ) {
|
||||||
|
$msg = "\n****************************************************\nTHIS WILL MODIFY YOUR APP_KEY AND DE-CRYPT YOUR ENCRYPTED CUSTOM FIELDS AND \nRE-ENCRYPT THEM WITH A NEWLY GENERATED KEY. \n\nThere is NO undo. \n\nMake SURE you have a database backup and a backup of your .env generated BEFORE running this command. \n\nIf you do not save the newly generated APP_KEY to your .env in this process, \nyour encrypted data will no longer be decryptable. \n\nAre you SURE you wish to continue, and have confirmed you have a database backup and an .env backup? ";
|
||||||
|
} else {
|
||||||
|
$msg = "\n****************************************************\nTHIS WILL DE-CRYPT YOUR ENCRYPTED CUSTOM FIELDS AND RE-ENCRYPT THEM WITH YOUR\nAPP_KEY.\n\nThere is NO undo. \n\nMake SURE you have a database backup BEFORE running this command. \n\nAre you SURE you wish to continue, and have confirmed you have a database backup? ";
|
||||||
|
}
|
||||||
|
if ($this->option('force') || $this->confirm($msg)) {
|
||||||
|
|
||||||
// Get the existing app_key and ciphers
|
// Get the existing app_key and ciphers
|
||||||
// We put them in a variable since we clear the cache partway through here.
|
// We put them in a variable since we clear the cache partway through here.
|
||||||
|
if ($this->option('emergency')) {
|
||||||
$old_app_key = config('app.key');
|
$old_app_key = config('app.key');
|
||||||
$cipher = config('app.cipher');
|
$cipher = config('app.cipher');
|
||||||
|
|
||||||
// Generate a new one
|
// Generate a new one
|
||||||
Artisan::call('key:generate', ['--show' => true]);
|
Artisan::call('key:generate', ['--show' => true]);
|
||||||
$new_app_key = Artisan::output();
|
$new_app_key = trim(Artisan::output());
|
||||||
|
|
||||||
// Clear the config cache
|
// Clear the config cache
|
||||||
Artisan::call('config:clear');
|
Artisan::call('config:clear');
|
||||||
|
|
||||||
$this->warn('Your app cipher is: '.$cipher);
|
|
||||||
$this->warn('Your old APP_KEY is: '.$old_app_key);
|
|
||||||
$this->warn('Your new APP_KEY is: '.$new_app_key);
|
|
||||||
|
|
||||||
// Write the new app key to the .env file
|
// Write the new app key to the .env file
|
||||||
$this->writeNewEnvironmentFileWith($new_app_key);
|
$this->writeNewEnvironmentFileWith($new_app_key);
|
||||||
|
} elseif ($this->argument('previous_key')) {
|
||||||
|
$old_app_key = $this->argument('previous_key');
|
||||||
|
$cipher = config('app.cipher'); // just a guess?
|
||||||
|
$new_app_key = config('app.key');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->warn('Your app cipher is: ' . $cipher);
|
||||||
|
$this->warn('Your old APP_KEY is: ' . $old_app_key);
|
||||||
|
$this->warn('Your new APP_KEY is: ' . $new_app_key);
|
||||||
|
|
||||||
// Manually create an old encrypter instance using the old app key
|
// Manually create an old encrypter instance using the old app key
|
||||||
// and also create a new encrypter instance so we can re-crypt the field
|
// and also create a new encrypter instance so we can re-crypt the field
|
||||||
|
@ -75,8 +95,16 @@ class RotateAppKey extends Command
|
||||||
$assets = Asset::whereNotNull($field->db_column)->get();
|
$assets = Asset::whereNotNull($field->db_column)->get();
|
||||||
|
|
||||||
foreach ($assets as $asset) {
|
foreach ($assets as $asset) {
|
||||||
|
try {
|
||||||
$asset->{$field->db_column} = $oldEncrypter->decrypt($asset->{$field->db_column});
|
$asset->{$field->db_column} = $oldEncrypter->decrypt($asset->{$field->db_column});
|
||||||
$this->line('DECRYPTED: '.$field->db_column);
|
$this->line('DECRYPTED: ' . $field->db_column);
|
||||||
|
} catch (DecryptException $e) {
|
||||||
|
$this->line('Could not decrypt '. $field->db_column.' using "old key" - skipping...');
|
||||||
|
continue;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->error("Error decrypting ".$field->db_column.", reason: ".$e->getMessage().". Aborting key rotation");
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
$asset->{$field->db_column} = $newEncrypter->encrypt($asset->{$field->db_column});
|
$asset->{$field->db_column} = $newEncrypter->encrypt($asset->{$field->db_column});
|
||||||
$this->line('ENCRYPTED: '.$field->db_column);
|
$this->line('ENCRYPTED: '.$field->db_column);
|
||||||
$asset->save();
|
$asset->save();
|
||||||
|
@ -86,10 +114,14 @@ class RotateAppKey extends Command
|
||||||
// Handle the LDAP password if one is provided
|
// Handle the LDAP password if one is provided
|
||||||
$setting = Setting::first();
|
$setting = Setting::first();
|
||||||
if ($setting->ldap_pword != '') {
|
if ($setting->ldap_pword != '') {
|
||||||
|
try {
|
||||||
$setting->ldap_pword = $oldEncrypter->decrypt($setting->ldap_pword);
|
$setting->ldap_pword = $oldEncrypter->decrypt($setting->ldap_pword);
|
||||||
$setting->ldap_pword = $newEncrypter->encrypt($setting->ldap_pword);
|
$setting->ldap_pword = $newEncrypter->encrypt($setting->ldap_pword);
|
||||||
$setting->save();
|
$setting->save();
|
||||||
$this->warn('LDAP password has been re-encrypted.');
|
$this->warn('LDAP password has been re-encrypted.');
|
||||||
|
} catch(DecryptException $e) {
|
||||||
|
$this->warn("Unable to decrypt old LDAP password; skipping");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->info('This operation has been canceled. No changes have been made.');
|
$this->info('This operation has been canceled. No changes have been made.');
|
||||||
|
@ -104,9 +136,16 @@ class RotateAppKey extends Command
|
||||||
*/
|
*/
|
||||||
protected function writeNewEnvironmentFileWith($key)
|
protected function writeNewEnvironmentFileWith($key)
|
||||||
{
|
{
|
||||||
|
\Log::debug("here is the key replacement pattern which seems to not be firing: ".$this->keyReplacementPattern());
|
||||||
|
\Log::debug("Here's your current env vile: ".file_get_contents($this->laravel->environmentFilePath()));
|
||||||
|
\Log::debug("And here it is being replaced: ".preg_replace(
|
||||||
|
$this->keyReplacementPattern(),
|
||||||
|
'APP_KEY="'.$key.'"',
|
||||||
|
file_get_contents($this->laravel->environmentFilePath())
|
||||||
|
));
|
||||||
file_put_contents($this->laravel->environmentFilePath(), preg_replace(
|
file_put_contents($this->laravel->environmentFilePath(), preg_replace(
|
||||||
$this->keyReplacementPattern(),
|
$this->keyReplacementPattern(),
|
||||||
'APP_KEY='.$key,
|
'APP_KEY="'.$key.'"',
|
||||||
file_get_contents($this->laravel->environmentFilePath())
|
file_get_contents($this->laravel->environmentFilePath())
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -118,7 +157,7 @@ class RotateAppKey extends Command
|
||||||
*/
|
*/
|
||||||
protected function keyReplacementPattern()
|
protected function keyReplacementPattern()
|
||||||
{
|
{
|
||||||
$escaped = preg_quote('='.$this->laravel['config']['app.key'], '/');
|
$escaped = '="?'.preg_quote($this->laravel['config']['app.key'], '/').'"?';
|
||||||
|
|
||||||
return "/^APP_KEY{$escaped}/m";
|
return "/^APP_KEY{$escaped}/m";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue