1
0
Fork 0

Sanitize guessed name and vendor name before suggesting it in init command, fixes #12276

pull/12284/head
Jordi Boggiano 2025-01-20 15:00:55 +01:00
parent 34c16ad169
commit 8d8f4e8ab8
No known key found for this signature in database
2 changed files with 49 additions and 13 deletions

View File

@ -91,7 +91,7 @@ EOT
$allowlist = ['name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license', 'autoload'];
$options = array_filter(array_intersect_key($input->getOptions(), array_flip($allowlist)), function ($val) { return $val !== null && $val !== []; });
if (isset($options['name']) && !Preg::isMatch('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $options['name'])) {
if (isset($options['name']) && !Preg::isMatch('{^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$}D', $options['name'])) {
throw new \InvalidArgumentException(
'The package name '.$options['name'].' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
);
@ -274,23 +274,24 @@ EOT
$name = $input->getOption('name');
if (null === $name) {
$name = basename($cwd);
$name = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
$name = strtolower($name);
$name = $this->sanitizePackageNameComponent($name);
$vendor = $name;
if (!empty($_SERVER['COMPOSER_DEFAULT_VENDOR'])) {
$name = $_SERVER['COMPOSER_DEFAULT_VENDOR'] . '/' . $name;
$vendor = $_SERVER['COMPOSER_DEFAULT_VENDOR'];
} elseif (isset($git['github.user'])) {
$name = $git['github.user'] . '/' . $name;
$vendor = $git['github.user'];
} elseif (!empty($_SERVER['USERNAME'])) {
$name = $_SERVER['USERNAME'] . '/' . $name;
$vendor = $_SERVER['USERNAME'];
} elseif (!empty($_SERVER['USER'])) {
$name = $_SERVER['USER'] . '/' . $name;
$vendor = $_SERVER['USER'];
} elseif (get_current_user()) {
$name = get_current_user() . '/' . $name;
} else {
// package names must be in the format foo/bar
$name .= '/' . $name;
$vendor = get_current_user();
}
$name = strtolower($name);
$vendor = $this->sanitizePackageNameComponent($vendor);
$name = $vendor . '/' . $name;
}
$name = $io->askAndValidate(
@ -300,7 +301,7 @@ EOT
return $name;
}
if (!Preg::isMatch('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $value)) {
if (!Preg::isMatch('{^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$}D', $value)) {
throw new \InvalidArgumentException(
'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
);
@ -636,4 +637,14 @@ EOT
return !empty($requires) || !empty($devRequires);
}
private function sanitizePackageNameComponent(string $name): string
{
$name = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name);
$name = strtolower($name);
$name = Preg::replace('{^[_.-]+|[_.-]+$|[^a-z0-9_.-]}u', '', $name);
$name = Preg::replace('{([_.-]){2,}}u', '$1', $name);
return $name;
}
}

View File

@ -179,6 +179,31 @@ class InitCommandTest extends TestCase
self::assertEquals($expected, $file->read());
}
public function testRunGuessNameFromDirSanitizesDir(): void
{
$dir = $this->initTempComposer();
mkdir($dirName = '_foo_--bar__baz.--..qux__');
chdir($dirName);
$_SERVER['COMPOSER_DEFAULT_VENDOR'] = '.vendorName';
$appTester = $this->getApplicationTester();
$appTester->setInputs(['', '', 'n', '', '', '', 'no', 'no', 'n', 'yes']);
$appTester->run(['command' => 'init']);
self::assertSame(0, $appTester->getStatusCode());
$expected = [
'name' => 'vendor-name/foo-bar_baz.qux',
'require' => [],
];
$file = new JsonFile('./composer.json');
self::assertEquals($expected, $file->read());
unset($_SERVER['COMPOSER_DEFAULT_VENDOR']);
}
public function testRunInvalidAuthorArgumentInvalidEmail(): void
{
$this->expectException(\InvalidArgumentException::class);