FIX: bbcode URLs not handling paths correctly (#21215)
Due to the order we were parsing markdown, bbcode [url] elements were not handled properly. `[url]https://example.com/path[/url]` was not currectly parsing cause linkify was detecting the url as: `https://example.com/path[/url]` which is legit. To resolve this I swapped url to use a replace rule, and instead re-parsed the internal payload and injected the tokens in. This fix is complex cause we support stuff like `[url][b]test.com[/b][/url]` So we need to parse the content inside url `[b]test.com[/b]`
This commit is contained in:
parent
366ff0e76b
commit
fd4aea7bc5
|
@ -989,6 +989,24 @@ eviltrout</p>
|
||||||
'<p><a href="http://discourse.org" data-bbcode="true">discourse</a></p>',
|
'<p><a href="http://discourse.org" data-bbcode="true">discourse</a></p>',
|
||||||
"named links are properly parsed"
|
"named links are properly parsed"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assert.cooked(
|
||||||
|
"[url]https://discourse.org/path[/url]",
|
||||||
|
'<p><a href="https://discourse.org/path" data-bbcode="true">https://discourse.org/path</a></p>',
|
||||||
|
"paths are correctly handled"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.cooked(
|
||||||
|
"[url]discourse.org/path[/url]",
|
||||||
|
'<p><a href="https://discourse.org/path" data-bbcode="true">discourse.org/path</a></p>',
|
||||||
|
"paths are correctly handled"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.cooked(
|
||||||
|
"[url][b]discourse.org/path[/b][/url]",
|
||||||
|
'<p><a href="https://discourse.org/path" data-bbcode="true"><span class="bbcode-b">discourse.org/path</span></a></p>',
|
||||||
|
"paths are correctly handled"
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("images", function (assert) {
|
test("images", function (assert) {
|
||||||
|
@ -1216,7 +1234,7 @@ eviltrout</p>
|
||||||
);
|
);
|
||||||
assert.cookedPara(
|
assert.cookedPara(
|
||||||
"[url]abc.com[/url]",
|
"[url]abc.com[/url]",
|
||||||
'<a href="http://abc.com">abc.com</a>',
|
'<a href="https://abc.com" data-bbcode="true">abc.com</a>',
|
||||||
"it magically links using linkify"
|
"it magically links using linkify"
|
||||||
);
|
);
|
||||||
assert.cookedPara(
|
assert.cookedPara(
|
||||||
|
|
|
@ -182,56 +182,88 @@ export function setup(helper) {
|
||||||
const simpleUrlRegex = /^https?:\/\//;
|
const simpleUrlRegex = /^https?:\/\//;
|
||||||
ruler.push("url", {
|
ruler.push("url", {
|
||||||
tag: "url",
|
tag: "url",
|
||||||
wrap(startToken, endToken, tagInfo, content, state) {
|
|
||||||
const url = (tagInfo.attrs["_default"] || content).trim();
|
|
||||||
let linkifyFound = false;
|
|
||||||
|
|
||||||
if (state.md.options.linkify) {
|
replace(state, tagInfo, content) {
|
||||||
const tokens = state.tokens;
|
let token;
|
||||||
const startIndex = tokens.indexOf(startToken);
|
|
||||||
const endIndex = tokens.indexOf(endToken);
|
|
||||||
|
|
||||||
// reuse existing tokens from linkify if they exist
|
// we need to tokenize the content and reinsert tokens in the stream
|
||||||
for (let index = startIndex + 1; index < endIndex; index++) {
|
// this is because we need to support nested bbcode
|
||||||
const token = tokens[index];
|
let tokens = [];
|
||||||
|
md.inline.parse(content, state.md, state.env, tokens);
|
||||||
|
|
||||||
if (
|
let url = tagInfo.attrs["_default"];
|
||||||
token.markup === "linkify" &&
|
|
||||||
token.info === "auto" &&
|
if (!url) {
|
||||||
token.type === "link_open"
|
// try to find the actual url in the tokens
|
||||||
) {
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
linkifyFound = true;
|
token = tokens[i];
|
||||||
token.attrs.push(["data-bbcode", "true"]);
|
// nested linkify or link, just pick it
|
||||||
|
if (token.type === "link_open") {
|
||||||
|
for (let j = 0; j < token.attrs.length; j++) {
|
||||||
|
if (token.attrs[j][0] === "href") {
|
||||||
|
url = token.attrs[j][1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (url) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (token.type === "text") {
|
||||||
|
url = token.content;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!linkifyFound && simpleUrlRegex.test(url)) {
|
if (md.linkify) {
|
||||||
startToken.type = "link_open";
|
let match = null;
|
||||||
startToken.tag = "a";
|
|
||||||
startToken.attrs = [
|
// linkify has trouble with strings containing spaces, so just ban
|
||||||
|
// them outright
|
||||||
|
if (url && !url.includes(" ")) {
|
||||||
|
match = md.linkify.matchAtStart(url);
|
||||||
|
if (!match) {
|
||||||
|
match = md.linkify.matchAtStart("https://" + url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
url = match.url;
|
||||||
|
} else {
|
||||||
|
url = null;
|
||||||
|
}
|
||||||
|
} else if (!url.match(simpleUrlRegex)) {
|
||||||
|
url = "https://" + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
token = state.push("link_open", "a", 0);
|
||||||
|
token.attrs = ["href", url];
|
||||||
|
token.attrs = [
|
||||||
["href", url],
|
["href", url],
|
||||||
["data-bbcode", "true"],
|
["data-bbcode", "true"],
|
||||||
];
|
];
|
||||||
startToken.content = "";
|
token.content = "";
|
||||||
startToken.nesting = 1;
|
token.nesting = 1;
|
||||||
|
|
||||||
endToken.type = "link_close";
|
|
||||||
endToken.tag = "a";
|
|
||||||
endToken.content = "";
|
|
||||||
endToken.nesting = -1;
|
|
||||||
} else {
|
|
||||||
// just strip the bbcode tag
|
|
||||||
endToken.content = "";
|
|
||||||
startToken.content = "";
|
|
||||||
|
|
||||||
// edge case, we don't want this detected as a onebox if auto linked
|
|
||||||
// this ensures it is not stripped
|
|
||||||
startToken.type = "html_inline";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
for (let i = 0; i < tokens.length; i++) {
|
||||||
|
token = tokens[i];
|
||||||
|
if (token.type === "link_open" || token.type === "link_close") {
|
||||||
|
// linkify nested tokens, do nothing
|
||||||
|
} else {
|
||||||
|
state.tokens.push(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
token = state.push("link_close", "a", 0);
|
||||||
|
token.nesting = -1;
|
||||||
|
token.content = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue