From 07464f87c84e4c8014a2d2c547ec563f2683d2bd Mon Sep 17 00:00:00 2001 From: Eduardo Gulias Davis Date: Sun, 21 Feb 2021 22:41:37 +0100 Subject: [PATCH] MessageIDParser passing tests. --- src/MessageIDParser.php | 109 +++++++++++++++++++++++++ src/Parser/DomainPart.php | 4 +- src/Parser/FoldingWhiteSpace.php | 17 ++-- src/Parser/IDLeftPart.php | 29 +++++++ src/Parser/LocalPart.php | 37 +++++---- src/Parser/Parser.php | 7 +- src/Validation/MessageIDValidation.php | 16 ++++ 7 files changed, 186 insertions(+), 33 deletions(-) create mode 100644 src/MessageIDParser.php create mode 100644 src/Parser/IDLeftPart.php diff --git a/src/MessageIDParser.php b/src/MessageIDParser.php new file mode 100644 index 0000000..82b0b51 --- /dev/null +++ b/src/MessageIDParser.php @@ -0,0 +1,109 @@ +lexer = $lexer; + } + + public function parse(string $str) : Result + { + $result = parent::parse($str); + + $this->addLongEmailWarning($this->localPart, $this->domainPart); + + return $result; + } + + protected function preRightParsing(): Result + { + if (!$this->hasAtToken()) { + return new InvalidEmail(new NoLocalPart(), $this->lexer->token["value"]); + } + return new ValidEmail(); + } + + protected function parseRightFromAt(): Result + { + return $this->processIDRight(); + } + + protected function parseLeftFromAt(): Result + { + return $this->processIDLeft(); + } + + private function processIDRight() : Result + { + $localPartParser = new LocalPart($this->lexer); + $localPartResult = $localPartParser->parse(); + $this->localPart = $localPartParser->localPart(); + $this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings); + + return $localPartResult; + } + + private function processIDLeft() : Result + { + $domainPartParser = new IDLeftPart($this->lexer); + $domainPartResult = $domainPartParser->parse(); + $this->domainPart = $domainPartParser->domainPart(); + $this->warnings = array_merge($domainPartParser->getWarnings(), $this->warnings); + + return $domainPartResult; + } + + public function getLeftPart() : string + { + return $this->idLeft; + } + + public function getRightPart() : string + { + return $this->idRight; + } + + private function hasAtToken() : bool + { + $this->lexer->moveNext(); + $this->lexer->moveNext(); + if ($this->lexer->token['type'] === EmailLexer::S_AT) { + return false; + } + + return true; + } + + private function addLongEmailWarning(string $localPart, string $parsedDomainPart) : void + { + if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAILID_MAX_LENGTH) { + $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); + } + } +} \ No newline at end of file diff --git a/src/Parser/DomainPart.php b/src/Parser/DomainPart.php index 6688c40..bb01132 100644 --- a/src/Parser/DomainPart.php +++ b/src/Parser/DomainPart.php @@ -234,7 +234,6 @@ class DomainPart extends Parser */ protected function parseDomainLiteral() : Result { - try { $this->lexer->find(EmailLexer::S_CLOSEBRACKET); } catch (\RuntimeException $e) { @@ -268,7 +267,7 @@ class DomainPart extends Parser return $this->validateTokens($hasComments); } - private function validateTokens(bool $hasComments) : Result + protected function validateTokens(bool $hasComments) : Result { $validDomainTokens = array( EmailLexer::GENERIC => true, @@ -288,7 +287,6 @@ class DomainPart extends Parser return new ValidEmail(); } - private function checkLabelLength(bool $isEndOfDomain = false) : Result { if ($this->lexer->token['type'] === EmailLexer::S_DOT || $isEndOfDomain) { diff --git a/src/Parser/FoldingWhiteSpace.php b/src/Parser/FoldingWhiteSpace.php index 0d131fb..8b56628 100644 --- a/src/Parser/FoldingWhiteSpace.php +++ b/src/Parser/FoldingWhiteSpace.php @@ -23,7 +23,10 @@ class FoldingWhiteSpace extends Parser $previous = $this->lexer->getPrevious(); - $this->checkCRLFInFWS(); + $resultCRLF = $this->checkCRLFInFWS(); + if ($resultCRLF->isInvalid()) { + return $resultCRLF; + } if ($this->lexer->token['type'] === EmailLexer::S_CR) { return new InvalidEmail(new CRNoLF(), $this->lexer->token['value']); @@ -46,10 +49,7 @@ class FoldingWhiteSpace extends Parser return new ValidEmail(); } - /** - * @return InvalidEmail|ValidEmail|null - */ - protected function checkCRLFInFWS() + protected function checkCRLFInFWS() : Result { if ($this->lexer->token['type'] !== EmailLexer::CRLF) { return new ValidEmail(); @@ -63,12 +63,11 @@ class FoldingWhiteSpace extends Parser if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { return new InvalidEmail(new CRLFAtTheEnd(), $this->lexer->token['value']); } + + return new ValidEmail(); } - /** - * @return bool - */ - protected function isFWS() + protected function isFWS() : bool { if ($this->escaped()) { return false; diff --git a/src/Parser/IDLeftPart.php b/src/Parser/IDLeftPart.php new file mode 100644 index 0000000..5fca0c4 --- /dev/null +++ b/src/Parser/IDLeftPart.php @@ -0,0 +1,29 @@ + true, + EmailLexer::S_SQUOTE => true, + EmailLexer::S_BACKTICK => true, + EmailLexer::S_SEMICOLON => true, + EmailLexer::S_GREATERTHAN => true, + EmailLexer::S_LOWERTHAN => true, + ); + + if (isset($invalidDomainTokens[$this->lexer->token['type']])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token in domain: ' . $this->lexer->token['value']), $this->lexer->token['value']); + } + return new ValidEmail(); + } +} \ No newline at end of file diff --git a/src/Parser/LocalPart.php b/src/Parser/LocalPart.php index 154b149..4627413 100644 --- a/src/Parser/LocalPart.php +++ b/src/Parser/LocalPart.php @@ -20,20 +20,6 @@ class LocalPart extends Parser */ private $localPart = ''; - /** - * Invalid lexer tokens for local part - * @var array - */ - private $invalidTokens = array( - EmailLexer::S_COMMA => EmailLexer::S_COMMA, - EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET, - EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET, - EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN, - EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN, - EmailLexer::S_COLON => EmailLexer::S_COLON, - EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON, - EmailLexer::INVALID => EmailLexer::INVALID - ); public function parse() : Result { @@ -78,8 +64,9 @@ class LocalPart extends Parser return $resultEscaping; } - if (isset($this->invalidTokens[$this->lexer->token['type']])) { - return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']); + $resultToken = $this->validateTokens(false); + if ($resultToken->isInvalid()) { + return $resultToken; } $resultFWS = $this->parseLocalFWS(); @@ -99,6 +86,24 @@ class LocalPart extends Parser return new ValidEmail(); } + protected function validateTokens(bool $hasComments) : Result + { + $invalidTokens = array( + EmailLexer::S_COMMA => EmailLexer::S_COMMA, + EmailLexer::S_CLOSEBRACKET => EmailLexer::S_CLOSEBRACKET, + EmailLexer::S_OPENBRACKET => EmailLexer::S_OPENBRACKET, + EmailLexer::S_GREATERTHAN => EmailLexer::S_GREATERTHAN, + EmailLexer::S_LOWERTHAN => EmailLexer::S_LOWERTHAN, + EmailLexer::S_COLON => EmailLexer::S_COLON, + EmailLexer::S_SEMICOLON => EmailLexer::S_SEMICOLON, + EmailLexer::INVALID => EmailLexer::INVALID + ); + if (isset($invalidTokens[$this->lexer->token['type']])) { + return new InvalidEmail(new ExpectingATEXT('Invalid token found'), $this->lexer->token['value']); + } + return new ValidEmail(); + } + public function localPart() : string { return $this->localPart; diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php index 2ddd6cc..7e0ccf9 100644 --- a/src/Parser/Parser.php +++ b/src/Parser/Parser.php @@ -25,6 +25,8 @@ abstract class Parser $this->lexer = $lexer; } + abstract public function parse() : Result; + /** * @return \Egulias\EmailValidator\Warning\Warning[] */ @@ -33,8 +35,6 @@ abstract class Parser return $this->warnings; } - abstract public function parse() : Result; - protected function parseFWS() : Result { $foldingWS = new FoldingWhiteSpace($this->lexer); @@ -52,9 +52,6 @@ abstract class Parser return new ValidEmail(); } - /** - * @return bool - */ protected function escaped() : bool { $previous = $this->lexer->getPrevious(); diff --git a/src/Validation/MessageIDValidation.php b/src/Validation/MessageIDValidation.php index bd17d34..a2e49b8 100644 --- a/src/Validation/MessageIDValidation.php +++ b/src/Validation/MessageIDValidation.php @@ -3,12 +3,28 @@ namespace Egulias\EmailValidator\Validation; use Egulias\EmailValidator\EmailLexer; +use Egulias\EmailValidator\MessageIDParser; use Egulias\EmailValidator\Result\InvalidEmail; +use Egulias\EmailValidator\Result\Reason\ExceptionFound; class MessageIDValidation implements EmailValidation { public function isValid(string $email, EmailLexer $emailLexer): bool { + $this->parser = new MessageIDParser($emailLexer); + try { + $result = $this->parser->parse($email); + $this->warnings = $this->parser->getWarnings(); + if ($result->isInvalid()) { + /** @psalm-suppress PropertyTypeCoercion */ + $this->error = $result; + return false; + } + } catch (\Exception $invalid) { + $this->error = new InvalidEmail(new ExceptionFound($invalid), ''); + return false; + } + return true; }