Skip to content

Commit ddcf428

Browse files
authored
Fix whitelisting usages (#287)
1 parent 40b8942 commit ddcf428

File tree

5 files changed

+260
-26
lines changed

5 files changed

+260
-26
lines changed

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ return [
324324
'PHPUnit\Framework\TestCase',
325325
'PHPUNIT_VERSION',
326326
'iter\count',
327+
'Acme\Foo*', // Warning: will not whitelist sub namespaces like Acme\Foo\Bar but will whitelist symbols like
328+
// Acme\Foo or Acme\Fooo
327329
],
328330
];
329331
```
@@ -517,6 +519,21 @@ And whitelist the namespace `PHPUnit\Framework\*`, then the autoloading for this
517519
will be faulty and will not work. For this to work, the whole package `PHPUnit\*` would
518520
need to be whitelisted.
519521

522+
**Warning:** the following _is not_ a namespace whitelist:
523+
524+
```php
525+
<?php declare(strict_types=1);
526+
527+
// scoper.inc.php
528+
529+
return [
530+
'whitelist' => [
531+
'PHPUnit\F*', // Will only whitelist symbols such as PHPUnit\F or PHPunit\Foo, but not symbols belonging to
532+
// sub-namespaces like PHPunit\Foo\Bar
533+
],
534+
];
535+
```
536+
520537

521538
## Building a Scoped PHAR
522539

src/PhpParser/NodeVisitor/NamespaceStmtPrefixer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ private function isWhitelistedNode(Node $node): bool
9797

9898
private function shouldPrefixStmt(Namespace_ $namespace): bool
9999
{
100-
if ($this->whitelist->belongsToWhitelistedNamespace((string) $namespace->name)) {
100+
if ($this->whitelist->isWhitelistedNamespace((string) $namespace->name)) {
101101
return false;
102102
}
103103

src/Scoper/Composer/AutoloadPrefixer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ private static function prefixAutoload(array $autoload, string $prefix, Whitelis
9090
$loader = [];
9191

9292
foreach ($autoload as $namespace => $paths) {
93-
$newNamespace = $whitelist->belongsToWhitelistedNamespace($namespace)
93+
$newNamespace = $whitelist->isWhitelistedNamespace($namespace)
9494
? $namespace
9595
: sprintf('%s\\%s', $prefix, $namespace)
9696
;
@@ -213,7 +213,7 @@ private static function prefixLaravelProviders(array $providers, string $prefix,
213213
{
214214
return array_map(
215215
static function (string $provider) use ($prefix, $whitelist): string {
216-
return $whitelist->belongsToWhitelistedNamespace($provider)
216+
return $whitelist->isWhitelistedNamespace($provider)
217217
? $provider
218218
: sprintf('%s\\%s', $prefix, $provider)
219219
;

src/Whitelist.php

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Countable;
1818
use InvalidArgumentException;
1919
use PhpParser\Node\Name\FullyQualified;
20-
use const SORT_REGULAR;
2120
use function array_flip;
2221
use function array_key_exists;
2322
use function array_map;
@@ -153,6 +152,19 @@ private function __construct(
153152
}
154153

155154
public function belongsToWhitelistedNamespace(string $name): bool
155+
{
156+
$nameNamespace = $this->retrieveNameNamespace($name);
157+
158+
foreach ($this->namespaces as $namespace) {
159+
if ('' === $namespace || 0 === strpos($nameNamespace, $namespace)) {
160+
return true;
161+
}
162+
}
163+
164+
return false;
165+
}
166+
167+
public function isWhitelistedNamespace(string $name): bool
156168
{
157169
$name = strtolower($name);
158170

@@ -161,9 +173,24 @@ public function belongsToWhitelistedNamespace(string $name): bool
161173
}
162174

163175
foreach ($this->namespaces as $namespace) {
164-
if ('' === $namespace || 0 === strpos($name, $namespace)) {
176+
if ('' === $namespace) {
165177
return true;
166178
}
179+
180+
if ('' !== $namespace && 0 !== strpos($name, $namespace)) {
181+
continue;
182+
}
183+
184+
$nameParts = explode('\\', $name);
185+
$namespaceParts = explode('\\', $namespace);
186+
187+
foreach ($namespaceParts as $index => $namespacePart) {
188+
if ($nameParts[$index] !== $namespacePart) {
189+
return false;
190+
}
191+
}
192+
193+
return true;
167194
}
168195

169196
return false;
@@ -184,17 +211,12 @@ public function isGlobalWhitelistedFunction(string $functionName): bool
184211

185212
public function recordWhitelistedFunction(FullyQualified $original, FullyQualified $alias): void
186213
{
187-
$this->whitelistedFunctions[] = [(string) $original, (string) $alias];
214+
$this->whitelistedFunctions[(string) $original] = [(string) $original, (string) $alias];
188215
}
189216

190217
public function getRecordedWhitelistedFunctions(): array
191218
{
192-
return array_values(
193-
array_unique(
194-
$this->whitelistedFunctions,
195-
SORT_REGULAR
196-
)
197-
);
219+
return array_values($this->whitelistedFunctions);
198220
}
199221

200222
/**
@@ -225,12 +247,12 @@ public function isGlobalWhitelistedClass(string $className): bool
225247

226248
public function recordWhitelistedClass(FullyQualified $original, FullyQualified $alias): void
227249
{
228-
$this->whitelistedClasses[] = [(string) $original, (string) $alias];
250+
$this->whitelistedClasses[(string) $original] = [(string) $original, (string) $alias];
229251
}
230252

231253
public function getRecordedWhitelistedClasses(): array
232254
{
233-
return $this->whitelistedClasses;
255+
return array_values($this->whitelistedClasses);
234256
}
235257

236258
/**
@@ -307,4 +329,19 @@ private static function lowerConstantName(string $name): string
307329

308330
return implode('\\', $parts);
309331
}
332+
333+
private function retrieveNameNamespace(string $name): string
334+
{
335+
$name = strtolower($name);
336+
337+
if (0 === strpos($name, '\\')) {
338+
$name = substr($name, 1);
339+
}
340+
341+
$nameParts = explode('\\', $name);
342+
343+
array_pop($nameParts);
344+
345+
return [] === $nameParts ? '' : implode('\\', $nameParts);
346+
}
310347
}

0 commit comments

Comments
 (0)