From e71395f5718326d45b6739c931ab6c0d80d79171 Mon Sep 17 00:00:00 2001 From: Miran Date: Tue, 21 Jul 2020 22:49:08 +0200 Subject: [PATCH] fix several newline problems (#15028) [backend] * prevent newlines where they shouldn't be * 'contentLength' shouldn't be negative (cherry picked from commit 5fafa2fd5c78232e4fe2d3d13bc67ab6c0cda0bb) --- lib/pure/asyncftpclient.nim | 4 ++++ lib/pure/httpclient.nim | 8 +++++++- lib/pure/smtp.nim | 39 +++++++++++++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim index 7bbfc2a35c57..51f182575839 100644 --- a/lib/pure/asyncftpclient.nim +++ b/lib/pure/asyncftpclient.nim @@ -146,7 +146,11 @@ proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} = ## Send a message to the server, and wait for a primary reply. ## ``\c\L`` is added for you. ## + ## You need to make sure that the message ``m`` doesn't contain any newline + ## characters. Failing to do so will raise ``AssertionDefect``. + ## ## **Note:** The server may return multiple lines of coded replies. + doAssert(not m.contains({'\c', '\L'}), "message shouldn't contain any newline characters") await ftp.csock.send(m & "\c\L") return await ftp.expectReply() diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index e3e5a5c11ad1..3b6c4b5b4873 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -241,7 +241,8 @@ proc contentLength*(response: Response | AsyncResponse): int = ## ## A ``ValueError`` exception will be raised if the value is not an integer. var contentLengthHeader = response.headers.getOrDefault("Content-Length") - return contentLengthHeader.parseInt() + result = contentLengthHeader.parseInt() + doAssert(result >= 0 and result <= high(int32)) proc lastModified*(response: Response | AsyncResponse): DateTime = ## Retrieves the specified response's last modified time. @@ -1018,6 +1019,11 @@ proc request*(client: HttpClient | AsyncHttpClient, url: string, ## ## This procedure will follow redirects up to a maximum number of redirects ## specified in ``client.maxRedirects``. + ## + ## You need to make sure that the ``url`` doesn't contain any newline + ## characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not url.contains({'\c', '\L'}), "url shouldn't contain any newline characters") + result = await client.requestAux(url, httpMethod, body, headers, multipart) var lastURL = url diff --git a/lib/pure/smtp.nim b/lib/pure/smtp.nim index 1a9e220299ed..9763776ad16d 100644 --- a/lib/pure/smtp.nim +++ b/lib/pure/smtp.nim @@ -43,7 +43,7 @@ ## For SSL support this module relies on OpenSSL. If you want to ## enable SSL, compile with ``-d:ssl``. -import net, strutils, strtabs, base64, os +import net, strutils, strtabs, base64, os, strutils import asyncnet, asyncdispatch export Port @@ -65,7 +65,22 @@ type Smtp* = SmtpBase[Socket] AsyncSmtp* = SmtpBase[AsyncSocket] -proc debugSend(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = +proc containsNewline(xs: seq[string]): bool = + for x in xs: + if x.contains({'\c', '\L'}): + return true + +proc debugSend*(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} = + ## Sends ``cmd`` on the socket connected to the SMTP server. + ## + ## If the ``smtp`` object was created with ``debug`` enabled, + ## debugSend will invoke ``echo("C:" & cmd)`` before sending. + ## + ## This is a lower level proc and not something that you typically + ## would need to call when using this module. One exception to + ## this is if you are implementing any + ## `SMTP extensions`_. + if smtp.debug: echo("C:" & cmd) await smtp.sock.send(cmd) @@ -95,6 +110,14 @@ else: proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], otherHeaders: openarray[tuple[name, value: string]]): Message = ## Creates a new MIME compliant message. + ## + ## You need to make sure that ``mSubject``, ``mTo`` and ``mCc`` don't contain + ## any newline characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not mSubject.contains({'\c', '\L'}), + "'mSubject' shouldn't contain any newline characters") + doAssert(not (mTo.containsNewline() or mCc.containsNewline()), + "'mTo' and 'mCc' shouldn't contain any newline characters") + result.msgTo = mTo result.msgCc = mCc result.msgSubject = mSubject @@ -106,6 +129,13 @@ proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string], proc createMessage*(mSubject, mBody: string, mTo, mCc: seq[string] = @[]): Message = ## Alternate version of the above. + ## + ## You need to make sure that ``mSubject``, ``mTo`` and ``mCc`` don't contain + ## any newline characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not mSubject.contains({'\c', '\L'}), + "'mSubject' shouldn't contain any newline characters") + doAssert(not (mTo.containsNewline() or mCc.containsNewline()), + "'mTo' and 'mCc' shouldn't contain any newline characters") result.msgTo = mTo result.msgCc = mCc result.msgSubject = mSubject @@ -213,6 +243,11 @@ proc sendMail*(smtp: Smtp | AsyncSmtp, fromAddr: string, ## Sends ``msg`` from ``fromAddr`` to the addresses specified in ``toAddrs``. ## Messages may be formed using ``createMessage`` by converting the ## Message into a string. + ## + ## You need to make sure that ``fromAddr`` and ``toAddrs`` don't contain + ## any newline characters. Failing to do so will raise ``AssertionDefect``. + doAssert(not (toAddrs.containsNewline() or fromAddr.contains({'\c', '\L'})), + "'toAddrs' and 'fromAddr' shouldn't contain any newline characters") await smtp.debugSend("MAIL FROM:<" & fromAddr & ">\c\L") await smtp.checkReply("250")