Ignore invalid SMTP EHLO response lines
This commit is contained in:
parent
c78d70719b
commit
60bf78d3f0
2 changed files with 54 additions and 46 deletions
|
@ -115,20 +115,25 @@ internal class SmtpResponseParser(
|
|||
|
||||
private fun parseEhloLine(ehloLine: String, keywords: MutableMap<String, List<String>>) {
|
||||
val parts = ehloLine.split(" ")
|
||||
val keyword = checkAndNormalizeEhloKeyword(parts[0])
|
||||
val parameters = checkEhloParameters(parts)
|
||||
|
||||
if (keywords.containsKey(keyword)) {
|
||||
parserError("Same EHLO keyword present in more than one response line")
|
||||
try {
|
||||
val keyword = checkAndNormalizeEhloKeyword(parts[0])
|
||||
val parameters = checkEhloParameters(parts)
|
||||
|
||||
if (keywords.containsKey(keyword)) {
|
||||
parserError("Same EHLO keyword present in more than one response line", logging = false)
|
||||
}
|
||||
|
||||
keywords[keyword] = parameters
|
||||
} catch (e: SmtpResponseParserException) {
|
||||
logger.log(e, "Ignoring EHLO keyword line: $ehloLine")
|
||||
}
|
||||
|
||||
keywords[keyword] = parameters
|
||||
}
|
||||
|
||||
private fun checkAndNormalizeEhloKeyword(text: String): String {
|
||||
val keyword = text.uppercase()
|
||||
if (!keyword[0].isCapitalAlphaDigit() || keyword.any { !it.isCapitalAlphaDigit() && it != DASH }) {
|
||||
parserError("EHLO keyword contains invalid character")
|
||||
parserError("EHLO keyword contains invalid character", logging = false)
|
||||
}
|
||||
|
||||
return keyword
|
||||
|
@ -138,9 +143,9 @@ internal class SmtpResponseParser(
|
|||
for (i in 1..parts.lastIndex) {
|
||||
val parameter = parts[i]
|
||||
if (parameter.isEmpty()) {
|
||||
parserError("EHLO parameter must not be empty")
|
||||
parserError("EHLO parameter must not be empty", logging = false)
|
||||
} else if (parameter.any { it.code !in 33..126 }) {
|
||||
parserError("EHLO parameter contains invalid character")
|
||||
parserError("EHLO parameter contains invalid character", logging = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -145,26 +145,36 @@ class SmtpResponseParserTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `read EHLO response with invalid keyword`() {
|
||||
fun `read EHLO response with invalid keywords`() {
|
||||
val input = """
|
||||
250-smtp.domain.example
|
||||
250 KEY:WORD
|
||||
250-SIZE 52428800
|
||||
250-8BITMIME
|
||||
250-PIPELINING
|
||||
250-PIPE_CONNECT
|
||||
250-AUTH=PLAIN
|
||||
250 HELP
|
||||
""".toPeekableInputStream()
|
||||
val parser = SmtpResponseParser(logger, input)
|
||||
|
||||
assertFailsWithMessage("EHLO keyword contains invalid character") {
|
||||
parser.readHelloResponse()
|
||||
val response = parser.readHelloResponse()
|
||||
|
||||
assertType<SmtpHelloResponse.Hello>(response) { hello ->
|
||||
assertThat(hello.keywords.keys).containsExactly(
|
||||
"SIZE",
|
||||
"8BITMIME",
|
||||
"PIPELINING",
|
||||
"HELP"
|
||||
)
|
||||
}
|
||||
|
||||
assertThat(logger.logEntries).containsExactly(
|
||||
LogEntry(
|
||||
throwable = null,
|
||||
message = """
|
||||
SMTP response data on parser error:
|
||||
250-smtp.domain.example
|
||||
250 KEY:WORD
|
||||
""".trimIndent()
|
||||
)
|
||||
assertThat(logger.logEntries.map { it.message }).containsExactly(
|
||||
"Ignoring EHLO keyword line: PIPE_CONNECT",
|
||||
"Ignoring EHLO keyword line: AUTH=PLAIN"
|
||||
)
|
||||
assertThat(logger.logEntries.map { it.throwable?.message }).containsExactly(
|
||||
"EHLO keyword contains invalid character",
|
||||
"EHLO keyword contains invalid character"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -176,44 +186,37 @@ class SmtpResponseParserTest {
|
|||
""".toPeekableInputStream()
|
||||
val parser = SmtpResponseParser(logger, input)
|
||||
|
||||
assertFailsWithMessage("EHLO parameter must not be empty") {
|
||||
parser.readHelloResponse()
|
||||
val response = parser.readHelloResponse()
|
||||
|
||||
assertType<SmtpHelloResponse.Hello>(response) { hello ->
|
||||
assertThat(hello.keywords.keys).isEmpty()
|
||||
}
|
||||
|
||||
assertThat(logger.logEntries).containsExactly(
|
||||
LogEntry(
|
||||
throwable = null,
|
||||
message = """
|
||||
SMTP response data on parser error:
|
||||
250-smtp.domain.example
|
||||
250 KEYWORD${" "}
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
assertThat(logger.logEntries).hasSize(1)
|
||||
assertThat(logger.logEntries.first().throwable).hasMessageThat().isEqualTo("EHLO parameter must not be empty")
|
||||
assertThat(logger.logEntries.first().message).isEqualTo("Ignoring EHLO keyword line: KEYWORD ")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read EHLO response with invalid parameter`() {
|
||||
val input = """
|
||||
250-smtp.domain.example
|
||||
250-8BITMIME
|
||||
250 KEYWORD para${"\t"}meter
|
||||
""".toPeekableInputStream()
|
||||
val parser = SmtpResponseParser(logger, input)
|
||||
|
||||
assertFailsWithMessage("EHLO parameter contains invalid character") {
|
||||
parser.readHelloResponse()
|
||||
val response = parser.readHelloResponse()
|
||||
|
||||
assertType<SmtpHelloResponse.Hello>(response) { hello ->
|
||||
assertThat(hello.keywords.keys).containsExactly("8BITMIME")
|
||||
}
|
||||
|
||||
assertThat(logger.logEntries).containsExactly(
|
||||
LogEntry(
|
||||
throwable = null,
|
||||
message = """
|
||||
SMTP response data on parser error:
|
||||
250-smtp.domain.example
|
||||
250 KEYWORD para${"\t"}meter
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
assertThat(logger.logEntries).hasSize(1)
|
||||
assertThat(logger.logEntries.first().throwable)
|
||||
.hasMessageThat().isEqualTo("EHLO parameter contains invalid character")
|
||||
assertThat(logger.logEntries.first().message)
|
||||
.isEqualTo("Ignoring EHLO keyword line: KEYWORD para${"\t"}meter")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in a new issue