Merge branch '4.4' into 5.2

* 4.4:
  [Security/Core] fix checking for bcrypt
  [HttpFoundation] Fixes for PHP 8.1 deprecations
  [Mime] DataPart: remove confusing fix-me comment
  expose references detected in inline notation structures
This commit is contained in:
Alexander M. Turek 2021-04-29 22:47:09 +02:00
commit 92b6458f60
8 changed files with 45 additions and 26 deletions

View File

@ -306,7 +306,7 @@ class Request
if ($_POST) {
$request->request = new InputBag($_POST);
} elseif (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded')
} elseif (0 === strpos($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded')
&& \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH'])
) {
parse_str($request->getContent(), $data);
@ -1405,7 +1405,7 @@ class Request
*/
public function getContentType()
{
return $this->getFormat($this->headers->get('CONTENT_TYPE'));
return $this->getFormat($this->headers->get('CONTENT_TYPE', ''));
}
/**
@ -1600,7 +1600,7 @@ class Request
*/
public function getETags()
{
return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), -1, \PREG_SPLIT_NO_EMPTY);
return preg_split('/\s*,\s*/', $this->headers->get('if_none_match', ''), -1, \PREG_SPLIT_NO_EMPTY);
}
/**
@ -1849,13 +1849,13 @@ class Request
*/
protected function prepareBaseUrl()
{
$filename = basename($this->server->get('SCRIPT_FILENAME'));
$filename = basename($this->server->get('SCRIPT_FILENAME', ''));
if (basename($this->server->get('SCRIPT_NAME')) === $filename) {
if (basename($this->server->get('SCRIPT_NAME', '')) === $filename) {
$baseUrl = $this->server->get('SCRIPT_NAME');
} elseif (basename($this->server->get('PHP_SELF')) === $filename) {
} elseif (basename($this->server->get('PHP_SELF', '')) === $filename) {
$baseUrl = $this->server->get('PHP_SELF');
} elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) {
} elseif (basename($this->server->get('ORIG_SCRIPT_NAME', '')) === $filename) {
$baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility
} else {
// Backtrack up the script_filename to find the portion matching
@ -1895,7 +1895,7 @@ class Request
$truncatedRequestUri = substr($requestUri, 0, $pos);
}
$basename = basename($baseUrl);
$basename = basename($baseUrl ?? '');
if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) {
// no match whatsoever; set it blank
return '';
@ -2046,7 +2046,7 @@ class Request
*/
public function isFromTrustedProxy()
{
return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies);
return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), self::$trustedProxies);
}
private function getTrustedValues(int $type, string $ip = null): array

View File

@ -9,4 +9,4 @@ $str = '?*():@&+$/%#[]';
$r->headers->setCookie(new Cookie($str, $str, 0, '/', null, false, false, true, null));
$r->sendHeaders();
setrawcookie($str, $str, 0, '/', null, false, false);
setrawcookie($str, $str, 0, '/', '', false, false);

View File

@ -46,8 +46,6 @@ class DataPart extends TextPart
public static function fromPath(string $path, string $name = null, string $contentType = null): self
{
// FIXME: if file is not readable, exception?
if (null === $contentType) {
$ext = strtolower(substr($path, strrpos($path, '.') + 1));
if (null === self::$mimeTypes) {

View File

@ -51,11 +51,11 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
$algos = [1 => \PASSWORD_BCRYPT, '2y' => \PASSWORD_BCRYPT];
if (\defined('PASSWORD_ARGON2I')) {
$this->algo = $algos[2] = $algos['argon2i'] = (string) \PASSWORD_ARGON2I;
$this->algo = $algos[2] = $algos['argon2i'] = \PASSWORD_ARGON2I;
}
if (\defined('PASSWORD_ARGON2ID')) {
$this->algo = $algos[3] = $algos['argon2id'] = (string) \PASSWORD_ARGON2ID;
$this->algo = $algos[3] = $algos['argon2id'] = \PASSWORD_ARGON2ID;
}
if (null !== $algo) {
@ -75,7 +75,7 @@ final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSalti
*/
public function encodePassword(string $raw, ?string $salt): string
{
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH || ((string) \PASSWORD_BCRYPT === $this->algo && 72 < \strlen($raw))) {
if (\strlen($raw) > self::MAX_PASSWORD_LENGTH || (\PASSWORD_BCRYPT === $this->algo && 72 < \strlen($raw))) {
throw new BadCredentialsException('Invalid password.');
}

View File

@ -58,7 +58,7 @@ class Inline
*
* @throws ParseException
*/
public static function parse(string $value = null, int $flags = 0, array $references = [])
public static function parse(string $value = null, int $flags = 0, array &$references = [])
{
self::initialize($flags);
@ -267,7 +267,7 @@ class Inline
*
* @throws ParseException When malformed inline YAML string is parsed
*/
public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array $references = [])
public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [])
{
if (\in_array($scalar[$i], ['"', "'"], true)) {
// quoted scalar
@ -343,7 +343,7 @@ class Inline
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseSequence(string $sequence, int $flags, int &$i = 0, array $references = []): array
private static function parseSequence(string $sequence, int $flags, int &$i = 0, array &$references = []): array
{
$output = [];
$len = \strlen($sequence);
@ -385,6 +385,11 @@ class Inline
}
}
if (\is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
$references[$matches['ref']] = $matches['value'];
$value = $matches['value'];
}
--$i;
}
@ -407,7 +412,7 @@ class Inline
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseMapping(string $mapping, int $flags, int &$i = 0, array $references = [])
private static function parseMapping(string $mapping, int $flags, int &$i = 0, array &$references = [])
{
$output = [];
$len = \strlen($mapping);
@ -433,14 +438,14 @@ class Inline
// key
$offsetBeforeKeyParsing = $i;
$isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
$key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, []);
$key = self::parseScalar($mapping, $flags, [':', ' '], $i, false);
if ($offsetBeforeKeyParsing === $i) {
throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
}
if ('!php/const' === $key) {
$key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false, []);
$key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false);
$key = self::evaluateScalar($key, $flags);
}
@ -522,6 +527,11 @@ class Inline
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key])) {
if (\is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
$references[$matches['ref']] = $matches['value'];
$value = $matches['value'];
}
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
@ -548,7 +558,7 @@ class Inline
*
* @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
*/
private static function evaluateScalar(string $scalar, int $flags, array $references = [])
private static function evaluateScalar(string $scalar, int $flags, array &$references = [])
{
$scalar = trim($scalar);

View File

@ -25,6 +25,7 @@ class Parser
{
public const TAG_PATTERN = '(?P<tag>![\w!.\/:-]+)';
public const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
public const REFERENCE_PATTERN = '#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u';
private $filename;
private $offset = 0;
@ -161,7 +162,7 @@ class Parser
}
$context = 'sequence';
if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#u', $values['value'], $matches)) {
if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];
@ -299,7 +300,7 @@ class Parser
$data += $parsed; // array union
}
}
} elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P<ref>[^ ]++) *+(?P<value>.*)#u', $values['value'], $matches)) {
} elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) {
$isRef = $matches['ref'];
$this->refsBeingParsed[] = $isRef;
$values['value'] = $matches['value'];

View File

@ -190,7 +190,8 @@ class InlineTest extends TestCase
*/
public function testParseReferences($yaml, $expected)
{
$this->assertSame($expected, Inline::parse($yaml, 0, ['var' => 'var-value']));
$references = ['var' => 'var-value'];
$this->assertSame($expected, Inline::parse($yaml, 0, $references));
}
public function getDataForParseReferences()
@ -214,7 +215,8 @@ class InlineTest extends TestCase
'b' => 'Clark',
'c' => 'Brian',
];
$this->assertSame([$foo], Inline::parse('[*foo]', 0, ['foo' => $foo]));
$references = ['foo' => $foo];
$this->assertSame([$foo], Inline::parse('[*foo]', 0, $references));
}
public function testParseUnquotedAsterisk()

View File

@ -1072,6 +1072,10 @@ EOF
'map' => ['key' => 'var-value'],
'list_in_map' => ['key' => ['var-value']],
'map_in_map' => ['foo' => ['bar' => 'var-value']],
'foo' => ['bar' => 'baz'],
'bar' => ['foo' => 'baz'],
'baz' => ['foo'],
'foobar' => ['foo'],
], Yaml::parse(<<<'EOF'
var: &var var-value
scalar: *var
@ -1082,6 +1086,10 @@ embedded_mapping: [ key: *var ]
map: { key: *var }
list_in_map: { key: [*var] }
map_in_map: { foo: { bar: *var } }
foo: { bar: &baz baz }
bar: { foo: *baz }
baz: [ &foo foo ]
foobar: [ *foo ]
EOF
));
}