domain improvements over UTF16 and invalid ascii chars

This commit is contained in:
Eduardo Gulias Davis
2020-12-05 22:58:13 +01:00
parent c41a7b491e
commit 3dc66acf64
7 changed files with 100 additions and 57 deletions
+1
View File
@@ -1,3 +1,4 @@
phpunit.result.cache
.idea
composer.lock
report/
+68 -53
View File
@@ -7,50 +7,52 @@ use Doctrine\Common\Lexer\AbstractLexer;
class EmailLexer extends AbstractLexer
{
//ASCII values
const C_DEL = 127;
const S_EMPTY = null;
const C_NUL = 0;
const S_AT = 64;
const S_BACKSLASH = 92;
const S_DOT = 46;
const S_HTAB = 9;
const S_LF = 10;
const S_CR = 13;
const S_SP = 32;
const EXCLAMATION = 33;
const S_DQUOTE = 34;
const NUMBER_SIGN = 35;
const DOLLAR = 36;
const PERCENTAGE = 37;
const AMPERSAND = 38;
const S_SQUOTE = 39;
const S_OPENPARENTHESIS = 40;
const S_CLOSEPARENTHESIS = 41;
const ASTERISK = 42;
const S_PLUS = 43;
const S_COMMA = 44;
const S_HYPHEN = 45;
const S_DOT = 46;
const S_SLASH = 47;
const S_COLON = 58;
const S_SEMICOLON = 59;
const S_LOWERTHAN = 60;
const S_EQUAL = 61;
const S_GREATERTHAN = 62;
const QUESTIONMARK = 63;
const S_AT = 64;
const S_OPENBRACKET = 91;
const S_BACKSLASH = 92;
const S_CLOSEBRACKET = 93;
const CARET = 94;
const S_UNDERSCORE = 95;
const S_BACKTICK = 96;
const S_OPENCURLYBRACES = 123;
const S_CLOSECURLYBRACES = 125;
const S_OPENPARENTHESIS = 49;
const S_CLOSEPARENTHESIS = 261;
const S_OPENBRACKET = 262;
const S_CLOSEBRACKET = 263;
const S_HYPHEN = 264;
const S_COLON = 265;
const S_DOUBLECOLON = 266;
const S_PIPE = 124;
const S_CLOSECURLYBRACES = 125;
const S_TILDE = 126;
const S_UNDERSCORE = 95;
const S_PLUS = 43;
const S_EQUAL = 61;
const S_SP = 267;
const S_HTAB = 268;
const S_CR = 269;
const S_LF = 270;
const S_IPV6TAG = 271;
const S_LOWERTHAN = 272;
const S_GREATERTHAN = 273;
const S_COMMA = 274;
const S_SEMICOLON = 275;
const S_OPENQBRACKET = 276;
const S_CLOSEQBRACKET = 277;
const S_SLASH = 278;
const S_EMPTY = null;
const C_DEL = 127;
const INVERT_QUESTIONMARK= 168;
const INVERT_EXCLAMATION = 173;
const GENERIC = 300;
const CRLF = 301;
const ASTERISK = 42;
const EXCLAMATION = 33;
const AMPERSAND = 38;
const CARET = 94;
const PERCENTAGE = 37;
const DOLLAR = 36;
const S_IPV6TAG = 301;
const INVALID = 302;
const CRLF = 1310;
const S_DOUBLECOLON = 5858;
const ASCII_INVALID_FROM = 127;
const ASCII_INVALID_TO = 199;
@@ -99,6 +101,11 @@ class EmailLexer extends AbstractLexer
'_' => self::S_UNDERSCORE,
'=' => self::S_EQUAL,
'+' => self::S_PLUS,
'¿' => self::INVERT_QUESTIONMARK,
'?' => self::QUESTIONMARK,
'#' => self::NUMBER_SIGN,
'¡' => self::INVERT_EXCLAMATION,
null => self::S_EMPTY,
);
/**
@@ -247,7 +254,9 @@ class EmailLexer extends AbstractLexer
*/
protected function getNonCatchablePatterns()
{
return array('[\xA0-\xff]+');
return [
'[\xA0-\xff]+',
];
}
/**
@@ -259,28 +268,38 @@ class EmailLexer extends AbstractLexer
*/
protected function getType(&$value)
{
if ($this->isNullType($value)) {
$encoded = $value;
if (mb_detect_encoding($value, 'auto', true) !== 'UTF-8') {
$encoded = utf8_encode($value);
}
if ($this->isValid($encoded)) {
return $this->charValue[$encoded];
}
if ($this->isNullType($encoded)) {
return self::C_NUL;
}
if ($this->isValid($value)) {
return $this->charValue[$value];
}
if ($this->isUTF8Invalid($value)) {
if ($this->isInvalidChar($encoded)) {
$this->hasInvalidTokens = true;
return self::INVALID;
}
return self::GENERIC;
}
/**
* @param string $value
*
* @return bool
*/
protected function isValid($value)
protected function isInvalidChar(string $value) : bool
{
if(preg_match("/[^\p{S}\p{C}\p{Cc}]+/iu", $value) ) {
return false;
}
return true;
}
protected function isValid(string $value) : bool
{
if (isset($this->charValue[$value])) {
return true;
@@ -302,11 +321,7 @@ class EmailLexer extends AbstractLexer
return false;
}
/**
* @param string $value
* @return bool
*/
protected function isUTF8Invalid($value)
protected function isUTF8Invalid(string $value) : bool
{
if (preg_match('/\p{Cc}+/u', $value)) {
return true;
+2 -2
View File
@@ -36,7 +36,7 @@ class DomainLiteral extends Parser
$this->addObsoleteWarnings();
if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) {
if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENBRACKET, EmailLexer::S_OPENBRACKET))) {
return new InvalidEmail(new ExpectingDTEXT(), $this->lexer->token['value']);
}
@@ -58,7 +58,7 @@ class DomainLiteral extends Parser
$IPv6TAG = true;
}
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) {
if ($this->lexer->token['type'] === EmailLexer::S_CLOSEBRACKET) {
break;
}
+1 -1
View File
@@ -256,7 +256,7 @@ class DomainPart extends Parser
$validDomainTokens[EmailLexer::S_CLOSEPARENTHESIS] = true;
}
if ($this->lexer->token['type'] === EmailLexer::S_OPENQBRACKET && $prev['type'] !== EmailLexer::S_AT) {
if ($this->lexer->token['type'] === EmailLexer::S_OPENBRACKET && $prev['type'] !== EmailLexer::S_AT) {
return new InvalidEmail(new ExpectingATEXT('OPENBRACKET not after AT'), $this->lexer->token['value']);
}
+4
View File
@@ -159,6 +159,10 @@ class EmailLexerTests extends TestCase
array('~', EmailLexer::S_TILDE),
array('=', EmailLexer::S_EQUAL),
array('+', EmailLexer::S_PLUS),
array('¿', EmailLexer::INVERT_QUESTIONMARK),
array('?', EmailLexer::QUESTIONMARK),
array('#', EmailLexer::NUMBER_SIGN),
array('¡', EmailLexer::INVERT_EXCLAMATION),
array('_', EmailLexer::S_UNDERSCORE),
array('', EmailLexer::S_EMPTY),
array(chr(31), EmailLexer::INVALID),
@@ -140,6 +140,13 @@ class RFCValidationDomainPartTest extends TestCase
['test@email=a.com'],
['test@email+a.com'],
['test@email_a.com'],
['test@email¡a.com'],
['test@email?a.com'],
['test@email#a.com'],
['test@email¨a.com'],
['test@email€a.com'],
['test@email$a.com'],
['test@email£a.com'],
];
}
@@ -220,5 +227,20 @@ class RFCValidationDomainPartTest extends TestCase
];
}
public function invalidUTF16Chars()
{
return [
['example@symƒony.com'],
];
}
/**
* @dataProvider invalidUTF16Chars
*/
public function testInvalidUTF16($email)
{
$this->markTestSkipped('Util finding a way to control this kind of chars');
$this->assertFalse($this->validator->isValid($email, $this->lexer));
}
}
@@ -148,13 +148,14 @@ class RFCValidationTest extends TestCase
['\r\n \r\ntest@iana.org'],
['\r\n \r\n test@iana.org'],
['test;123@foobar.com'],
['examp║le@symfony.com'],
];
}
/**
* @dataProvider getInvalidEmailsWithErrors
*/
public function testInvalidEmailsWithErrorsCheck($error, $email)
public function testInvalidDEmailsWithErrorsCheck($error, $email)
{
$this->assertFalse($this->validator->isValid($email, $this->lexer));
$this->assertEquals($error, $this->validator->getError());