-
Notifications
You must be signed in to change notification settings - Fork 660
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow to implement custom taint type classes
Instead of just having a generic `TaintedCustom` for custom taint - this change allows plugins/extensions to register their own custom taint type classes. Examples ``` TaintTypeRegistry::get('html'); // returns \Psalm\Issue\TaintedHtml TaintTypeRegistry::add('my-type', \Example\TaintedMyType::class); ```
- Loading branch information
Showing
24 changed files
with
224 additions
and
163 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<?php | ||
|
||
namespace Psalm\Issue; | ||
|
||
use Psalm\CodeLocation; | ||
|
||
final class TaintTypeFactory | ||
{ | ||
/** | ||
* @readonly | ||
*/ | ||
private TaintTypeRegistry $registry; | ||
|
||
public function __construct(TaintTypeRegistry $registry) | ||
{ | ||
$this->registry = $registry; | ||
} | ||
|
||
public function create( | ||
string $type, | ||
CodeLocation $code_location, | ||
array $journey, | ||
string $journey_text | ||
): CodeIssue { | ||
/** @var TaintedInput $class_name */ | ||
$class_name = $this->registry->get($type) ?? $this->registry->getDefault(); | ||
return new $class_name($class_name::MESSAGE, $code_location, $journey, $journey_text); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
<?php | ||
|
||
namespace Psalm\Issue; | ||
|
||
use LogicException; | ||
use Psalm\Type\TaintKind; | ||
use ReflectionClass; | ||
use RuntimeException; | ||
|
||
use function class_exists; | ||
use function stripos; | ||
|
||
final class TaintTypeRegistry | ||
{ | ||
/** | ||
* @var array<string, class-string<CodeIssue>> | ||
*/ | ||
private array $taint_types = [ | ||
TaintKind::INPUT_CALLABLE => TaintedCallable::class, | ||
TaintKind::INPUT_UNSERIALIZE => TaintedUnserialize::class, | ||
TaintKind::INPUT_INCLUDE => TaintedInclude::class, | ||
TaintKind::INPUT_EVAL => TaintedEval::class, | ||
TaintKind::INPUT_SQL => TaintedSql::class, | ||
TaintKind::INPUT_HTML => TaintedHtml::class, | ||
TaintKind::INPUT_HAS_QUOTES => TaintedTextWithQuotes::class, | ||
TaintKind::INPUT_SHELL => TaintedShell::class, | ||
TaintKind::USER_SECRET => TaintedUserSecret::class, | ||
TaintKind::SYSTEM_SECRET => TaintedSystemSecret::class, | ||
TaintKind::INPUT_SSRF => TaintedSSRF::class, | ||
TaintKind::INPUT_LDAP => TaintedLdap::class, | ||
TaintKind::INPUT_COOKIE => TaintedCookie::class, | ||
TaintKind::INPUT_FILE => TaintedFile::class, | ||
TaintKind::INPUT_HEADER => TaintedHeader::class, | ||
]; | ||
|
||
/** | ||
* @var class-string<CodeIssue> | ||
*/ | ||
private string $default = TaintedCustom::class; | ||
|
||
/** | ||
* @param class-string<CodeIssue> $class_name | ||
*/ | ||
public function add(string $type, string $class_name): void | ||
{ | ||
if ($this->has($type)) { | ||
throw new RuntimeException('Taint type ' . $type . ' is already defined'); | ||
} | ||
$this->assertClassName($class_name); | ||
$this->taint_types[$type] = $class_name; | ||
} | ||
|
||
public function has(string $type): bool | ||
{ | ||
return isset($this->taint_types[$type]); | ||
} | ||
|
||
/** | ||
* @return class-string<CodeIssue>|null | ||
*/ | ||
public function get(string $type): ?string | ||
{ | ||
return $this->taint_types[$type] ?? null; | ||
} | ||
|
||
/** | ||
* @return class-string<CodeIssue> | ||
*/ | ||
public function getDefault(): string | ||
{ | ||
return $this->default; | ||
} | ||
|
||
/** | ||
* @psalm-suppress PossiblyUnusedMethod | ||
* @param class-string<CodeIssue> $class_name | ||
*/ | ||
public function setDefault(string $class_name): void | ||
{ | ||
$this->assertClassName($class_name); | ||
$this->default = $class_name; | ||
} | ||
|
||
private function assertClassName(string $class_name): void | ||
{ | ||
if (!class_exists($class_name)) { | ||
throw new LogicException('Taint class ' . $class_name . ' does not exist'); | ||
} | ||
if (stripos((new ReflectionClass($class_name))->getShortName(), 'Tainted') !== 0) { | ||
throw new LogicException('Taint class name ' . $class_name . ' must start with "Tainted"'); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.