Skip to content

Commit e86ef99

Browse files
authored
Merge pull request #6839 from paulbalandan/fix-key-generate
Handle key generation when key is not present in .env
2 parents 46eb15c + 84eafc0 commit e86ef99

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

system/Commands/Encryption/GenerateKey.php

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,15 @@ class GenerateKey extends BaseCommand
6767
public function run(array $params)
6868
{
6969
$prefix = $params['prefix'] ?? CLI::getOption('prefix');
70+
7071
if (in_array($prefix, [null, true], true)) {
7172
$prefix = 'hex2bin';
7273
} elseif (! in_array($prefix, ['hex2bin', 'base64'], true)) {
7374
$prefix = CLI::prompt('Please provide a valid prefix to use.', ['hex2bin', 'base64'], 'required'); // @codeCoverageIgnore
7475
}
7576

7677
$length = $params['length'] ?? CLI::getOption('length');
78+
7779
if (in_array($length, [null, true], true)) {
7880
$length = 32;
7981
}
@@ -127,9 +129,7 @@ protected function setNewEncryptionKey(string $key, array $params): bool
127129

128130
if ($currentKey !== '' && ! $this->confirmOverwrite($params)) {
129131
// Not yet testable since it requires keyboard input
130-
// @codeCoverageIgnoreStart
131-
return false;
132-
// @codeCoverageIgnoreEnd
132+
return false; // @codeCoverageIgnore
133133
}
134134

135135
return $this->writeNewEncryptionKeyToFile($currentKey, $key);
@@ -163,13 +163,24 @@ protected function writeNewEncryptionKeyToFile(string $oldKey, string $newKey):
163163
copy($baseEnv, $envFile);
164164
}
165165

166-
$ret = file_put_contents($envFile, preg_replace(
167-
$this->keyPattern($oldKey),
168-
"\nencryption.key = {$newKey}",
169-
file_get_contents($envFile)
170-
));
166+
$oldFileContents = (string) file_get_contents($envFile);
167+
$replacementKey = "\nencryption.key = {$newKey}";
168+
169+
if (strpos($oldFileContents, 'encryption.key') === false) {
170+
return file_put_contents($envFile, $replacementKey, FILE_APPEND) !== false;
171+
}
172+
173+
$newFileContents = preg_replace($this->keyPattern($oldKey), $replacementKey, $oldFileContents);
174+
175+
if ($newFileContents === $oldFileContents) {
176+
$newFileContents = preg_replace(
177+
'/^[#\s]*encryption.key[=\s]*(?:hex2bin\:[a-f0-9]{64}|base64\:(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?)$/m',
178+
$replacementKey,
179+
$oldFileContents
180+
);
181+
}
171182

172-
return $ret !== false;
183+
return file_put_contents($envFile, $newFileContents) !== false;
173184
}
174185

175186
/**

tests/system/Commands/GenerateKeyTest.php

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,13 @@ protected function resetEnvironment()
7474

7575
public function testGenerateKeyShowsEncodedKey()
7676
{
77-
command('key:generate -show');
77+
command('key:generate --show');
7878
$this->assertStringContainsString('hex2bin:', $this->getBuffer());
7979

80-
command('key:generate -prefix base64 -show');
80+
command('key:generate --prefix base64 --show');
8181
$this->assertStringContainsString('base64:', $this->getBuffer());
8282

83-
command('key:generate -prefix hex2bin -show');
83+
command('key:generate --prefix hex2bin --show');
8484
$this->assertStringContainsString('hex2bin:', $this->getBuffer());
8585
}
8686

@@ -95,12 +95,12 @@ public function testGenerateKeyCreatesNewKey()
9595
$this->assertStringContainsString(env('encryption.key'), file_get_contents($this->envPath));
9696
$this->assertStringContainsString('hex2bin:', file_get_contents($this->envPath));
9797

98-
command('key:generate -prefix base64 -force');
98+
command('key:generate --prefix base64 --force');
9999
$this->assertStringContainsString('successfully set.', $this->getBuffer());
100100
$this->assertStringContainsString(env('encryption.key'), file_get_contents($this->envPath));
101101
$this->assertStringContainsString('base64:', file_get_contents($this->envPath));
102102

103-
command('key:generate -prefix hex2bin -force');
103+
command('key:generate --prefix hex2bin --force');
104104
$this->assertStringContainsString('successfully set.', $this->getBuffer());
105105
$this->assertStringContainsString(env('encryption.key'), file_get_contents($this->envPath));
106106
$this->assertStringContainsString('hex2bin:', file_get_contents($this->envPath));
@@ -115,4 +115,53 @@ public function testDefaultShippedEnvIsMissing()
115115
$this->assertStringContainsString('Both default shipped', $this->getBuffer());
116116
$this->assertStringContainsString('Error in setting', $this->getBuffer());
117117
}
118+
119+
/**
120+
* @see https://github.com/codeigniter4/CodeIgniter4/issues/6838
121+
*/
122+
public function testKeyGenerateWhenKeyIsMissingInDotEnvFile()
123+
{
124+
file_put_contents($this->envPath, '');
125+
126+
command('key:generate');
127+
128+
$this->assertStringContainsString('Application\'s new encryption key was successfully set.', $this->getBuffer());
129+
$this->assertSame("\nencryption.key = " . env('encryption.key'), file_get_contents($this->envPath));
130+
}
131+
132+
public function testKeyGenerateWhenNewHexKeyIsSubsequentlyCommentedOut()
133+
{
134+
command('key:generate');
135+
$key = env('encryption.key', '');
136+
file_put_contents($this->envPath, str_replace(
137+
'encryption.key = ' . $key,
138+
'# encryption.key = ' . $key,
139+
file_get_contents($this->envPath),
140+
$count
141+
));
142+
$this->assertSame(1, $count, 'Failed commenting out the previously set application key.');
143+
144+
CITestStreamFilter::$buffer = '';
145+
command('key:generate --force');
146+
$this->assertStringContainsString('was successfully set.', $this->getBuffer());
147+
$this->assertNotSame($key, env('encryption.key', $key), 'Failed replacing the commented out key.');
148+
}
149+
150+
public function testKeyGenerateWhenNewBase64KeyIsSubsequentlyCommentedOut()
151+
{
152+
command('key:generate --prefix base64');
153+
$key = env('encryption.key', '');
154+
file_put_contents($this->envPath, str_replace(
155+
'encryption.key = ' . $key,
156+
'# encryption.key = ' . $key,
157+
file_get_contents($this->envPath),
158+
$count
159+
));
160+
$this->assertSame(1, $count, 'Failed commenting out the previously set application key.');
161+
162+
CITestStreamFilter::$buffer = '';
163+
command('key:generate --force');
164+
$this->assertStringContainsString('was successfully set.', $this->getBuffer());
165+
$this->assertNotSame($key, env('encryption.key', $key), 'Failed replacing the commented out key.');
166+
}
118167
}

0 commit comments

Comments
 (0)