aboutsummaryrefslogtreecommitdiff
path: root/client/js/util/markdown.js
diff options
context:
space:
mode:
authorHunternif2021-08-04 01:56:00 +0100
committerHunternif2021-08-04 01:56:00 +0100
commitca861cdc44ca476cec2949f237bbc7503862ad58 (patch)
tree520f918a9a77432bf283b46b4296812eb4332ffe /client/js/util/markdown.js
parentdd03540398fcab11bfc2c3cebed2fb7a78592c16 (diff)
parent59452711668b9f7a7aeea3c57301b22882987c2b (diff)
Merge remote-tracking branch 'origin/master' into hunternif
# Conflicts: # client/css/post-content-control.styl # client/css/post-list-view.styl # client/html/post_edit_sidebar.tpl # client/js/controllers/post_list_controller.js # client/js/controllers/post_main_controller.js # client/js/controllers/post_upload_controller.js # client/js/controllers/tag_controller.js # client/js/controllers/user_list_controller.js # client/js/controls/expander_control.js # client/js/controls/post_content_control.js # client/js/controls/post_edit_sidebar_control.js # client/js/controls/post_readonly_sidebar_control.js # client/js/controls/tag_input_control.js # client/js/main.js # client/js/models/abstract_list.js # client/js/models/post.js # client/js/models/post_list.js # client/js/models/settings.js # client/js/models/tag.js # client/js/models/tag_list.js # client/js/tags.js # client/js/util/search.js # client/js/util/touch.js # client/js/util/uri.js # client/js/util/views.js # client/js/views/post_main_view.js # client/js/views/post_upload_view.js # client/js/views/posts_header_view.js # client/js/views/posts_page_view.js # client/js/views/settings_view.js # client/js/views/tag_view.js # client/package-lock.json # client/package.json # server/config.yaml.dist # server/szurubooru/api/__init__.py # server/szurubooru/api/post_api.py # server/szurubooru/api/tag_api.py # server/szurubooru/func/posts.py # server/szurubooru/func/tags.py # server/szurubooru/model/__init__.py # server/szurubooru/model/post.py # server/szurubooru/model/tag.py # server/szurubooru/search/configs/__init__.py # server/szurubooru/search/configs/post_search_config.py # server/szurubooru/search/executor.py # server/szurubooru/tests/api/test_post_retrieving.py # server/szurubooru/tests/api/test_post_updating.py # server/szurubooru/tests/api/test_tag_updating.py # server/szurubooru/tests/conftest.py # server/szurubooru/tests/func/test_posts.py # server/szurubooru/tests/func/test_tags.py # server/szurubooru/tests/search/configs/test_post_search_config.py
Diffstat (limited to 'client/js/util/markdown.js')
-rw-r--r--client/js/util/markdown.js94
1 files changed, 53 insertions, 41 deletions
diff --git a/client/js/util/markdown.js b/client/js/util/markdown.js
index f326ebb..22cdae5 100644
--- a/client/js/util/markdown.js
+++ b/client/js/util/markdown.js
@@ -1,6 +1,7 @@
-'use strict';
+"use strict";
-const marked = require('marked');
+const marked = require("marked");
+const DOMPurify = require("dompurify");
class BaseMarkdownWrapper {
preprocess(text) {
@@ -20,62 +21,68 @@ class SjisWrapper extends BaseMarkdownWrapper {
preprocess(text) {
return text.replace(
- /\[sjis\]((?:[^\[]|\[(?!\/?sjis\]))+)\[\/sjis\]/ig,
+ /\[sjis\]((?:[^\[]|\[(?!\/?sjis\]))+)\[\/sjis\]/gi,
(match, capture) => {
- var ret = '%%%SJIS' + this.buf.length;
+ var ret = "%%%SJIS" + this.buf.length;
this.buf.push(capture);
return ret;
- });
+ }
+ );
}
postprocess(text) {
return text.replace(
/(?:<p>)?%%%SJIS(\d+)(?:<\/p>)?/,
(match, capture) => {
- return '<div class="sjis">' + this.buf[capture] + '</div>';
- });
+ return '<div class="sjis">' + this.buf[capture] + "</div>";
+ }
+ );
}
}
// fix \ before ~ being stripped away
class TildeWrapper extends BaseMarkdownWrapper {
preprocess(text) {
- return text.replace(/\\~/g, '%%%T');
+ return text.replace(/\\~/g, "%%%T");
}
postprocess(text) {
- return text.replace(/%%%T/g, '\\~');
+ return text.replace(/%%%T/g, "\\~");
}
}
-//prevent ^#... from being treated as headers, due to tag permalinks
+// prevent ^#... from being treated as headers, due to tag permalinks
class TagPermalinkFixWrapper extends BaseMarkdownWrapper {
preprocess(text) {
- return text.replace(/^#/g, '%%%#');
+ return text.replace(/^#/g, "%%%#");
}
postprocess(text) {
- return text.replace(/%%%#/g, '#');
+ return text.replace(/%%%#/g, "#");
}
}
-//post, user and tags permalinks
+// post, user and tags permalinks
class EntityPermalinkWrapper extends BaseMarkdownWrapper {
preprocess(text) {
// URL-based permalinks
+ text = text.replace(new RegExp("\\b/post/(\\d+)/?\\b", "g"), "@$1");
text = text.replace(
- new RegExp('\\b/post/(\\d+)/?\\b', 'g'), '@$1');
- text = text.replace(
- new RegExp('\\b/tag/([a-zA-Z0-9_-]+?)/?', 'g'), '#$1');
+ new RegExp("\\b/tag/([a-zA-Z0-9_-]+?)/?", "g"),
+ "#$1"
+ );
text = text.replace(
- new RegExp('\\b/user/([a-zA-Z0-9_-]+?)/?', 'g'), '+$1');
+ new RegExp("\\b/user/([a-zA-Z0-9_-]+?)/?", "g"),
+ "+$1"
+ );
text = text.replace(
/(^|^\(|(?:[^\]])\(|[\s<>\[\]\)])([+#@][a-zA-Z0-9_-]+)/g,
- '$1[$2]($2)');
- text = text.replace(/\]\(@(\d+)\)/g, '](/post/$1)');
- text = text.replace(/\]\(\+([a-zA-Z0-9_-]+)\)/g, '](/user/$1)');
- text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, '](/posts/query=$1)');
+ "$1[$2]($2)"
+ );
+ text = text.replace(/\]\(@(\d+)\)/g, "](/post/$1)");
+ text = text.replace(/\]\(\+([a-zA-Z0-9_-]+)\)/g, "](/user/$1)");
+ text = text.replace(/\]\(#([a-zA-Z0-9_-]+)\)/g, "](/posts/query=$1)");
return text;
}
}
@@ -83,51 +90,58 @@ class EntityPermalinkWrapper extends BaseMarkdownWrapper {
class SearchPermalinkWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/ig,
- '<a href="/posts/query=$1"><code>$1</code></a>');
+ /\[search\]((?:[^\[]|\[(?!\/?search\]))+)\[\/search\]/gi,
+ '<a href="/posts/query=$1"><code>$1</code></a>'
+ );
}
}
class SpoilersWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/ig,
- '<span class="spoiler">$1</span>');
+ /\[spoiler\]((?:[^\[]|\[(?!\/?spoiler\]))+)\[\/spoiler\]/gi,
+ '<span class="spoiler">$1</span>'
+ );
}
}
class SmallWrapper extends BaseMarkdownWrapper {
postprocess(text) {
return text.replace(
- /\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/ig,
- '<small>$1</small>');
+ /\[small\]((?:[^\[]|\[(?!\/?small\]))+)\[\/small\]/gi,
+ "<small>$1</small>"
+ );
}
}
class StrikeThroughWrapper extends BaseMarkdownWrapper {
postprocess(text) {
- text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, '$1<del>$3</del>');
- return text.replace(/\\~/g, '~');
+ text = text.replace(/(^|[^\\])(~~|~)([^~]+)\2/g, "$1<del>$3</del>");
+ return text.replace(/\\~/g, "~");
}
}
function createRenderer() {
function sanitize(str) {
- return str.replace(/&<"/g, m => {
- if (m === '&') {
- return '&amp;';
+ return str.replace(/&<"/g, (m) => {
+ if (m === "&") {
+ return "&amp;";
}
- if (m === '<') {
- return '&lt;';
+ if (m === "<") {
+ return "&lt;";
}
- return '&quot;';
+ return "&quot;";
});
}
const renderer = new marked.Renderer();
renderer.image = (href, title, alt) => {
- let [_, url, width, height] =
- /^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/.exec(href);
+ let [
+ _,
+ url,
+ width,
+ height,
+ ] = /^(.+?)(?:\s=\s*(\d*)\s*x\s*(\d*)\s*)?$/.exec(href);
let res = '<img src="' + sanitize(url) + '" alt="' + sanitize(alt);
if (width) {
res += '" width="' + width;
@@ -145,7 +159,6 @@ function formatMarkdown(text) {
const options = {
renderer: renderer,
breaks: true,
- sanitize: true,
smartypants: true,
};
let wrappers = [
@@ -166,7 +179,7 @@ function formatMarkdown(text) {
for (let wrapper of wrappers) {
text = wrapper.postprocess(text);
}
- return text;
+ return DOMPurify.sanitize(text);
}
function formatInlineMarkdown(text) {
@@ -174,7 +187,6 @@ function formatInlineMarkdown(text) {
const options = {
renderer: renderer,
breaks: true,
- sanitize: true,
smartypants: true,
};
let wrappers = [
@@ -193,7 +205,7 @@ function formatInlineMarkdown(text) {
for (let wrapper of wrappers) {
text = wrapper.postprocess(text);
}
- return text;
+ return DOMPurify.sanitize(text);
}
module.exports = {

© 2015 - 2026 Jakob L. Kreuze