fixes a possible 'javascript:' protocol exploit [backport:1.0] (#19134)
* fixes a possible 'javascript:' protocol exploit [backport:1.0] * add tests * Update tests/stdlib/trstgen.nim * add the same logic for hyperlinks * move the logic into a proc Co-authored-by: narimiran <narimiran@disroot.org>
This commit is contained in:
parent
c989542339
commit
9338aa2497
2 changed files with 45 additions and 5 deletions
|
|
@ -40,7 +40,7 @@
|
||||||
## can be done by simply searching for [footnoteName].
|
## can be done by simply searching for [footnoteName].
|
||||||
|
|
||||||
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
import strutils, os, hashes, strtabs, rstast, rst, highlite, tables, sequtils,
|
||||||
algorithm, parseutils, std/strbasics
|
algorithm, parseutils, std/strbasics, strscans
|
||||||
|
|
||||||
import ../../std/private/since
|
import ../../std/private/since
|
||||||
|
|
||||||
|
|
@ -827,6 +827,16 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||||
rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName])
|
rstnodeToRefname(n).idS, tmp, $chr(n.level - 1 + ord('A')), tocName])
|
||||||
|
|
||||||
|
|
||||||
|
proc safeProtocol(linkStr: var string) =
|
||||||
|
var protocol = ""
|
||||||
|
if scanf(linkStr, "$w:", protocol):
|
||||||
|
# if it has a protocol at all, ensure that it's not 'javascript:' or worse:
|
||||||
|
if cmpIgnoreCase(protocol, "http") == 0 or cmpIgnoreCase(protocol, "https") == 0 or
|
||||||
|
cmpIgnoreCase(protocol, "ftp") == 0:
|
||||||
|
discard "it's fine"
|
||||||
|
else:
|
||||||
|
linkStr = ""
|
||||||
|
|
||||||
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
|
proc renderTocEntry(d: PDoc, e: TocEntry, result: var string) =
|
||||||
dispA(d.target, result,
|
dispA(d.target, result,
|
||||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||||
|
|
@ -891,6 +901,8 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
||||||
|
|
||||||
# support for `:target:` links for images:
|
# support for `:target:` links for images:
|
||||||
var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl)
|
var target = esc(d.target, getFieldValue(n, "target").strip(), escMode=emUrl)
|
||||||
|
safeProtocol(target)
|
||||||
|
|
||||||
if target.len > 0:
|
if target.len > 0:
|
||||||
# `htmlOut` needs to be of the following format for link to work for images:
|
# `htmlOut` needs to be of the following format for link to work for images:
|
||||||
# <a class="reference external" href="target"><img src=\"$1\"$2/></a>
|
# <a class="reference external" href="target"><img src=\"$1\"$2/></a>
|
||||||
|
|
@ -1192,6 +1204,7 @@ proc renderHyperlink(d: PDoc, text, link: PRstNode, result: var string,
|
||||||
d.escMode = emUrl
|
d.escMode = emUrl
|
||||||
renderRstToOut(d, link, linkStr)
|
renderRstToOut(d, link, linkStr)
|
||||||
d.escMode = mode
|
d.escMode = mode
|
||||||
|
safeProtocol(linkStr)
|
||||||
var textStr = ""
|
var textStr = ""
|
||||||
renderRstToOut(d, text, textStr)
|
renderRstToOut(d, text, textStr)
|
||||||
let nimDocStr = if nimdoc: " nimdoc" else: ""
|
let nimDocStr = if nimdoc: " nimdoc" else: ""
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,7 @@ Some chapter
|
||||||
|
|
||||||
Level2
|
Level2
|
||||||
------
|
------
|
||||||
|
|
||||||
Level3
|
Level3
|
||||||
~~~~~~
|
~~~~~~
|
||||||
|
|
||||||
|
|
@ -407,7 +407,7 @@ Some chapter
|
||||||
|
|
||||||
More
|
More
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Another
|
Another
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
@ -683,7 +683,7 @@ Test1
|
||||||
test "RST line blocks":
|
test "RST line blocks":
|
||||||
let input2 = dedent"""
|
let input2 = dedent"""
|
||||||
Paragraph1
|
Paragraph1
|
||||||
|
|
||||||
|
|
|
|
||||||
|
|
||||||
Paragraph2"""
|
Paragraph2"""
|
||||||
|
|
@ -704,7 +704,7 @@ Test1
|
||||||
# check that '| ' with a few spaces is still parsed as new line
|
# check that '| ' with a few spaces is still parsed as new line
|
||||||
let input4 = dedent"""
|
let input4 = dedent"""
|
||||||
| xxx
|
| xxx
|
||||||
|
|
|
|
||||||
| zzz"""
|
| zzz"""
|
||||||
|
|
||||||
let output4 = input4.toHtml
|
let output4 = input4.toHtml
|
||||||
|
|
@ -1549,3 +1549,30 @@ suite "RST/Code highlight":
|
||||||
|
|
||||||
check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
|
check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
|
||||||
strip(expected)
|
strip(expected)
|
||||||
|
|
||||||
|
|
||||||
|
suite "invalid targets":
|
||||||
|
test "invalid image target":
|
||||||
|
let input1 = dedent """.. image:: /images/myimage.jpg
|
||||||
|
:target: https://bar.com
|
||||||
|
:alt: Alt text for the image"""
|
||||||
|
let output1 = input1.toHtml
|
||||||
|
check output1 == """<a class="reference external" href="https://bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
|
||||||
|
|
||||||
|
let input2 = dedent """.. image:: /images/myimage.jpg
|
||||||
|
:target: javascript://bar.com
|
||||||
|
:alt: Alt text for the image"""
|
||||||
|
let output2 = input2.toHtml
|
||||||
|
check output2 == """<img src="/images/myimage.jpg" alt="Alt text for the image"/>"""
|
||||||
|
|
||||||
|
let input3 = dedent """.. image:: /images/myimage.jpg
|
||||||
|
:target: bar.com
|
||||||
|
:alt: Alt text for the image"""
|
||||||
|
let output3 = input3.toHtml
|
||||||
|
check output3 == """<a class="reference external" href="bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
|
||||||
|
|
||||||
|
test "invalid links":
|
||||||
|
check("(([Nim](https://nim-lang.org/)))".toHtml ==
|
||||||
|
"""((<a class="reference external" href="https://nim-lang.org/">Nim</a>))""")
|
||||||
|
check("(([Nim](javascript://nim-lang.org/)))".toHtml ==
|
||||||
|
"""((<a class="reference external" href="">Nim</a>))""")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue