Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 84dd1fc

Browse files
committed
Merge pull request composer#898 from Seldaek/providefix
Fix hijacking possibility via provide bug
2 parents 1f31810 + d4aab7d commit 84dd1fc

File tree

6 files changed

+87
-21
lines changed

6 files changed

+87
-21
lines changed

src/Composer/DependencyResolver/DefaultPolicy.php

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,15 @@ public function compareByPriorityPreferInstalled(Pool $pool, array $installedMap
141141
}
142142

143143
/**
144-
* Checks if source replaces a package with the same name as target.
145-
*
146-
* Replace constraints are ignored. This method should only be used for
147-
* prioritisation, not for actual constraint verification.
148-
*
149-
* @param PackageInterface $source
150-
* @param PackageInterface $target
151-
* @return bool
152-
*/
144+
* Checks if source replaces a package with the same name as target.
145+
*
146+
* Replace constraints are ignored. This method should only be used for
147+
* prioritisation, not for actual constraint verification.
148+
*
149+
* @param PackageInterface $source
150+
* @param PackageInterface $target
151+
* @return bool
152+
*/
153153
protected function replaces(PackageInterface $source, PackageInterface $target)
154154
{
155155
foreach ($source->getReplaces() as $link) {

src/Composer/DependencyResolver/Pool.php

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,42 @@ public function whatProvides($name, LinkConstraintInterface $constraint = null)
140140
return $candidates;
141141
}
142142

143-
$result = array();
143+
$matches = $provideMatches = array();
144+
$nameMatch = false;
144145

145146
foreach ($candidates as $candidate) {
146-
if ($candidate->matches($name, $constraint)) {
147-
$result[] = $candidate;
147+
switch ($candidate->matches($name, $constraint)) {
148+
case BasePackage::MATCH_NONE:
149+
break;
150+
151+
case BasePackage::MATCH_NAME:
152+
$nameMatch = true;
153+
break;
154+
155+
case BasePackage::MATCH:
156+
$nameMatch = true;
157+
$matches[] = $candidate;
158+
break;
159+
160+
case BasePackage::MATCH_PROVIDE:
161+
$provideMatches[] = $candidate;
162+
break;
163+
164+
case BasePackage::MATCH_REPLACE:
165+
$matches[] = $candidate;
166+
break;
167+
168+
default:
169+
throw new \UnexpectedValueException('Unexpected match type');
148170
}
149171
}
150172

151-
return $result;
173+
// if a package with the required name exists, we ignore providers
174+
if ($nameMatch) {
175+
return $matches;
176+
}
177+
178+
return array_merge($matches, $provideMatches);
152179
}
153180

154181
public function literalToPackage($literal)

src/Composer/Package/BasePackage.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ abstract class BasePackage implements PackageInterface
3838
const STABILITY_ALPHA = 15;
3939
const STABILITY_DEV = 20;
4040

41+
const MATCH_NAME = -1;
42+
const MATCH_NONE = 0;
43+
const MATCH = 1;
44+
const MATCH_PROVIDE = 2;
45+
const MATCH_REPLACE = 3;
46+
4147
public static $stabilities = array(
4248
'stable' => self::STABILITY_STABLE,
4349
'RC' => self::STABILITY_RC,
@@ -122,27 +128,27 @@ public function getId()
122128
*
123129
* @param string $name Name of the package to be matched
124130
* @param LinkConstraintInterface $constraint The constraint to verify
125-
* @return bool Whether this package matches the name and constraint
131+
* @return int One of the MATCH* constants of this class or 0 if there is no match
126132
*/
127133
public function matches($name, LinkConstraintInterface $constraint)
128134
{
129135
if ($this->name === $name) {
130-
return $constraint->matches(new VersionConstraint('==', $this->getVersion()));
136+
return $constraint->matches(new VersionConstraint('==', $this->getVersion())) ? self::MATCH : self::MATCH_NAME;
131137
}
132138

133139
foreach ($this->getProvides() as $link) {
134140
if ($link->getTarget() === $name && $constraint->matches($link->getConstraint())) {
135-
return true;
141+
return self::MATCH_PROVIDE;
136142
}
137143
}
138144

139145
foreach ($this->getReplaces() as $link) {
140146
if ($link->getTarget() === $name && $constraint->matches($link->getConstraint())) {
141-
return true;
147+
return self::MATCH_REPLACE;
142148
}
143149
}
144150

145-
return false;
151+
return self::MATCH_NONE;
146152
}
147153

148154
public function getRepository()

tests/Composer/Test/DependencyResolver/SolverTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,6 @@ public function testInstallProvider()
430430
{
431431
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
432432
$this->repo->addPackage($packageQ = $this->getPackage('Q', '1.0'));
433-
$this->repo->addPackage($packageB = $this->getPackage('B', '0.8'));
434433
$packageA->setRequires(array(new Link('A', 'B', $this->getVersionConstraint('>=', '1.0'), 'requires')));
435434
$packageQ->setProvides(array(new Link('Q', 'B', $this->getVersionConstraint('=', '1.0'), 'provides')));
436435

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
Provide only applies when no existing package has the given name
3+
--COMPOSER--
4+
{
5+
"repositories": [
6+
{
7+
"type": "package",
8+
"package": [
9+
{ "name": "higher-prio-hijacker", "version": "1.1.0", "provide": { "package": "1.0.0" } },
10+
{ "name": "provider2", "version": "1.1.0", "provide": { "package2": "1.0.0" } }
11+
]
12+
},
13+
{
14+
"type": "package",
15+
"package": [
16+
{ "name": "package", "version": "0.9.0" },
17+
{ "name": "package", "version": "1.0.0" },
18+
{ "name": "hijacker", "version": "1.1.0", "provide": { "package": "1.0.0" } },
19+
{ "name": "provider3", "version": "1.1.0", "provide": { "package3": "1.0.0" } }
20+
]
21+
}
22+
],
23+
"require": {
24+
"package": "1.*",
25+
"package2": "1.*",
26+
"provider3": "1.1.0"
27+
}
28+
}
29+
--RUN--
30+
install
31+
--EXPECT--
32+
Installing package (1.0.0)
33+
Installing provider2 (1.1.0)
34+
Installing provider3 (1.1.0)

tests/Composer/Test/Fixtures/installer/replace-priorities.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ Replace takes precedence only in higher priority repositories
66
{
77
"type": "package",
88
"package": [
9-
{ "name": "forked", "version": "1.1.0", "provide": { "package2": "1.1.0" } }
9+
{ "name": "forked", "version": "1.1.0", "replace": { "package2": "1.1.0" } }
1010
]
1111
},
1212
{
1313
"type": "package",
1414
"package": [
1515
{ "name": "package", "version": "1.0.0" },
1616
{ "name": "package2", "version": "1.0.0" },
17-
{ "name": "hijacker", "version": "1.1.0", "provide": { "package": "1.1.0" } }
17+
{ "name": "hijacker", "version": "1.1.0", "replace": { "package": "1.1.0" } }
1818
]
1919
}
2020
],

0 commit comments

Comments
 (0)