mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 15:16:08 +08:00
FIX: pretty text allow list (#10977)
Reword whitelist to allowlist in pretty-text. This library is used by plugins so we need deprecation notice.
This commit is contained in:
parent
632942e697
commit
dbec3792b7
|
@ -268,7 +268,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||
} else {
|
||||
const opts = {
|
||||
features: { editHistory: true, historyOneboxes: true },
|
||||
whiteListed: {
|
||||
allowListed: {
|
||||
editHistory: { custom: (tag, attr) => attr === "class" },
|
||||
historyOneboxes: ["header", "article", "div[style]"],
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getURLWithCDN } from "discourse-common/lib/get-url";
|
||||
import PrettyText, { buildOptions } from "pretty-text/pretty-text";
|
||||
import { performEmojiUnescape, buildEmojiUrl } from "pretty-text/emoji";
|
||||
import WhiteLister from "pretty-text/white-lister";
|
||||
import AllowLister from "pretty-text/allow-lister";
|
||||
import { sanitize as textSanitize } from "pretty-text/sanitizer";
|
||||
import loadScript from "discourse/lib/load-script";
|
||||
import { formatUsername } from "discourse/lib/utilities";
|
||||
|
@ -49,7 +49,7 @@ export function generateCookFunction(options) {
|
|||
}
|
||||
|
||||
export function sanitize(text, options) {
|
||||
return textSanitize(text, new WhiteLister(options));
|
||||
return textSanitize(text, new AllowLister(options));
|
||||
}
|
||||
|
||||
export function sanitizeAsync(text, options) {
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
import { test, module } from "qunit";
|
||||
import WhiteLister from "pretty-text/white-lister";
|
||||
import AllowLister from "pretty-text/allow-lister";
|
||||
|
||||
module("lib:whiteLister");
|
||||
module("lib:allowLister");
|
||||
|
||||
test("whiteLister", (assert) => {
|
||||
const whiteLister = new WhiteLister();
|
||||
test("allowLister", (assert) => {
|
||||
const allowLister = new AllowLister();
|
||||
|
||||
assert.ok(
|
||||
Object.keys(whiteLister.getWhiteList().tagList).length > 1,
|
||||
Object.keys(allowLister.getAllowList().tagList).length > 1,
|
||||
"should have some defaults"
|
||||
);
|
||||
|
||||
whiteLister.disable("default");
|
||||
allowLister.disable("default");
|
||||
|
||||
assert.ok(
|
||||
Object.keys(whiteLister.getWhiteList().tagList).length === 0,
|
||||
Object.keys(allowLister.getAllowList().tagList).length === 0,
|
||||
"should have no defaults if disabled"
|
||||
);
|
||||
|
||||
whiteLister.whiteListFeature("test", [
|
||||
allowLister.allowListFeature("test", [
|
||||
"custom.foo",
|
||||
"custom.baz",
|
||||
"custom[data-*]",
|
||||
"custom[rel=nofollow]",
|
||||
]);
|
||||
|
||||
whiteLister.whiteListFeature("test", ["custom[rel=test]"]);
|
||||
allowLister.allowListFeature("test", ["custom[rel=test]"]);
|
||||
|
||||
whiteLister.enable("test");
|
||||
allowLister.enable("test");
|
||||
|
||||
assert.deepEqual(
|
||||
whiteLister.getWhiteList(),
|
||||
allowLister.getAllowList(),
|
||||
{
|
||||
tagList: {
|
||||
custom: [],
|
||||
|
@ -46,10 +46,10 @@ test("whiteLister", (assert) => {
|
|||
"Expecting a correct white list"
|
||||
);
|
||||
|
||||
whiteLister.disable("test");
|
||||
allowLister.disable("test");
|
||||
|
||||
assert.deepEqual(
|
||||
whiteLister.getWhiteList(),
|
||||
allowLister.getAllowList(),
|
||||
{
|
||||
tagList: {},
|
||||
attrList: {},
|
|
@ -6,6 +6,7 @@
|
|||
//= require ./pretty-text/addon/emoji
|
||||
//= require ./pretty-text/addon/engines/discourse-markdown-it
|
||||
//= require xss.min
|
||||
//= require ./pretty-text/addon/allow-lister
|
||||
//= require ./pretty-text/addon/white-lister
|
||||
//= require ./pretty-text/addon/sanitizer
|
||||
//= require ./pretty-text/addon/oneboxer
|
||||
|
|
246
app/assets/javascripts/pretty-text/addon/allow-lister.js
Normal file
246
app/assets/javascripts/pretty-text/addon/allow-lister.js
Normal file
|
@ -0,0 +1,246 @@
|
|||
import deprecated from "discourse-common/lib/deprecated";
|
||||
// to match:
|
||||
// abcd
|
||||
// abcd[test]
|
||||
// abcd[test=bob]
|
||||
const ALLOWLIST_REGEX = /([^\[]+)(\[([^=]+)(=(.*))?\])?/;
|
||||
|
||||
export default class AllowLister {
|
||||
constructor(options) {
|
||||
this._enabled = { default: true };
|
||||
this._allowedHrefSchemes = (options && options.allowedHrefSchemes) || [];
|
||||
this._allowedIframes = (options && options.allowedIframes) || [];
|
||||
this._rawFeatures = [["default", DEFAULT_LIST]];
|
||||
|
||||
this._cache = null;
|
||||
|
||||
if (options && options.features) {
|
||||
Object.keys(options.features).forEach((f) => {
|
||||
if (options.features[f]) {
|
||||
this._enabled[f] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
allowListFeature(feature, info) {
|
||||
this._rawFeatures.push([feature, info]);
|
||||
}
|
||||
|
||||
whiteListFeature(feature, info) {
|
||||
deprecated("`whiteListFeature` has been replaced with `allowListFeature`", {
|
||||
since: "2.6.0.beta.4",
|
||||
dropFrom: "2.7.0",
|
||||
});
|
||||
this.allowListFeature(feature, info);
|
||||
}
|
||||
|
||||
disable(feature) {
|
||||
this._enabled[feature] = false;
|
||||
this._cache = null;
|
||||
}
|
||||
|
||||
enable(feature) {
|
||||
this._enabled[feature] = true;
|
||||
this._cache = null;
|
||||
}
|
||||
|
||||
_buildCache() {
|
||||
const tagList = {};
|
||||
const attrList = {};
|
||||
const custom = [];
|
||||
|
||||
this._rawFeatures.forEach(([name, info]) => {
|
||||
if (!this._enabled[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.custom) {
|
||||
custom.push(info.custom);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof info === "string") {
|
||||
info = [info];
|
||||
}
|
||||
|
||||
(info || []).forEach((tag) => {
|
||||
const classes = tag.split(".");
|
||||
const tagWithAttr = classes.shift();
|
||||
|
||||
const m = ALLOWLIST_REGEX.exec(tagWithAttr);
|
||||
if (m) {
|
||||
const [, tagname, , attr, , val] = m;
|
||||
tagList[tagname] = [];
|
||||
|
||||
let attrs = (attrList[tagname] = attrList[tagname] || {});
|
||||
if (classes.length > 0) {
|
||||
attrs["class"] = (attrs["class"] || []).concat(classes);
|
||||
}
|
||||
|
||||
if (attr) {
|
||||
let attrInfo = (attrs[attr] = attrs[attr] || []);
|
||||
|
||||
if (val) {
|
||||
attrInfo.push(val);
|
||||
} else {
|
||||
attrs[attr] = ["*"];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this._cache = { custom, allowList: { tagList, attrList } };
|
||||
}
|
||||
|
||||
_ensureCache() {
|
||||
if (!this._cache) {
|
||||
this._buildCache();
|
||||
}
|
||||
}
|
||||
|
||||
getAllowList() {
|
||||
this._ensureCache();
|
||||
return this._cache.allowList;
|
||||
}
|
||||
|
||||
getWhiteList() {
|
||||
deprecated("`getWhiteList` has been replaced with `getAllowList`", {
|
||||
since: "2.6.0.beta.4",
|
||||
dropFrom: "2.7.0",
|
||||
});
|
||||
return this.getAllowList();
|
||||
}
|
||||
|
||||
getCustom() {
|
||||
this._ensureCache();
|
||||
return this._cache.custom;
|
||||
}
|
||||
|
||||
getAllowedHrefSchemes() {
|
||||
return this._allowedHrefSchemes;
|
||||
}
|
||||
|
||||
getAllowedIframes() {
|
||||
return this._allowedIframes;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add to `default` when you always want your allowlist to occur. In other words,
|
||||
// don't change this for a plugin or a feature that can be disabled
|
||||
export const DEFAULT_LIST = [
|
||||
"a.attachment",
|
||||
"a.hashtag",
|
||||
"a.mention",
|
||||
"a.mention-group",
|
||||
"a.onebox",
|
||||
`a.inline-onebox`,
|
||||
`a.inline-onebox-loading`,
|
||||
"a[data-bbcode]",
|
||||
"a[name]",
|
||||
"a[rel=nofollow]",
|
||||
"a[rel=ugc]",
|
||||
"a[target=_blank]",
|
||||
"a[title]",
|
||||
"abbr[title]",
|
||||
"aside.quote",
|
||||
"aside[data-*]",
|
||||
"audio",
|
||||
"audio[controls]",
|
||||
"audio[preload]",
|
||||
"b",
|
||||
"big",
|
||||
"blockquote",
|
||||
"br",
|
||||
"code",
|
||||
"dd",
|
||||
"del",
|
||||
"div",
|
||||
"div.quote-controls",
|
||||
"div.title",
|
||||
"div[align]",
|
||||
"div[lang]",
|
||||
"div[data-*]" /* This may seem a bit much but polls does
|
||||
it anyway and this is needed for themes,
|
||||
special code in sanitizer handles data-*
|
||||
nothing exists for data-theme-* and we
|
||||
don't want to slow sanitize for this case
|
||||
*/,
|
||||
"div[dir]",
|
||||
"dl",
|
||||
"dt",
|
||||
"em",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"hr",
|
||||
"i",
|
||||
"iframe",
|
||||
"iframe[frameborder]",
|
||||
"iframe[height]",
|
||||
"iframe[marginheight]",
|
||||
"iframe[marginwidth]",
|
||||
"iframe[width]",
|
||||
"iframe[allowfullscreen]",
|
||||
"img[alt]",
|
||||
"img[height]",
|
||||
"img[title]",
|
||||
"img[width]",
|
||||
"ins",
|
||||
"kbd",
|
||||
"li",
|
||||
"ol",
|
||||
"ol[start]",
|
||||
"p",
|
||||
"p[lang]",
|
||||
"picture",
|
||||
"pre",
|
||||
"s",
|
||||
"small",
|
||||
"span[lang]",
|
||||
"span.excerpt",
|
||||
"div.excerpt",
|
||||
"div.video-container",
|
||||
"div.onebox-placeholder-container",
|
||||
"span.placeholder-icon video",
|
||||
"span.hashtag",
|
||||
"span.mention",
|
||||
"strike",
|
||||
"strong",
|
||||
"sub",
|
||||
"sup",
|
||||
"source[data-orig-src]",
|
||||
"source[src]",
|
||||
"source[srcset]",
|
||||
"source[type]",
|
||||
"track",
|
||||
"track[default]",
|
||||
"track[label]",
|
||||
"track[kind]",
|
||||
"track[src]",
|
||||
"track[srclang]",
|
||||
"ul",
|
||||
"video",
|
||||
"video[autoplay]",
|
||||
"video[controls]",
|
||||
"video[controlslist]",
|
||||
"video[crossorigin]",
|
||||
"video[height]",
|
||||
"video[loop]",
|
||||
"video[muted]",
|
||||
"video[playsinline]",
|
||||
"video[poster]",
|
||||
"video[preload]",
|
||||
"video[width]",
|
||||
"ruby",
|
||||
"ruby[lang]",
|
||||
"rb",
|
||||
"rb[lang]",
|
||||
"rp",
|
||||
"rt",
|
||||
"rt[lang]",
|
||||
];
|
|
@ -1,6 +1,7 @@
|
|||
import WhiteLister from "pretty-text/white-lister";
|
||||
import AllowLister from "pretty-text/allow-lister";
|
||||
import { sanitize } from "pretty-text/sanitizer";
|
||||
import guid from "pretty-text/guid";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
|
||||
export const ATTACHMENT_CSS_CLASS = "attachment";
|
||||
|
||||
|
@ -23,11 +24,19 @@ function createHelper(
|
|||
optionCallbacks,
|
||||
pluginCallbacks,
|
||||
getOptions,
|
||||
whiteListed
|
||||
allowListed
|
||||
) {
|
||||
let helper = {};
|
||||
helper.markdownIt = true;
|
||||
helper.whiteList = (info) => whiteListed.push([featureName, info]);
|
||||
helper.allowList = (info) => allowListed.push([featureName, info]);
|
||||
helper.whiteList = (info) => {
|
||||
deprecated("`whiteList` has been replaced with `allowList`", {
|
||||
since: "2.6.0.beta.4",
|
||||
dropFrom: "2.7.0",
|
||||
});
|
||||
helper.allowList(info);
|
||||
};
|
||||
|
||||
helper.registerInline = deprecate(featureName, "registerInline");
|
||||
helper.replaceBlock = deprecate(featureName, "replaceBlock");
|
||||
helper.addPreProcessor = deprecate(featureName, "addPreProcessor");
|
||||
|
@ -296,7 +305,7 @@ export function setup(opts, siteSettings, state) {
|
|||
|
||||
const check = /discourse-markdown\/|markdown-it\//;
|
||||
let features = [];
|
||||
let whiteListed = [];
|
||||
let allowListed = [];
|
||||
|
||||
Object.keys(require._eak_seen).forEach((entry) => {
|
||||
if (check.test(entry)) {
|
||||
|
@ -319,13 +328,13 @@ export function setup(opts, siteSettings, state) {
|
|||
optionCallbacks,
|
||||
pluginCallbacks,
|
||||
getOptions,
|
||||
whiteListed
|
||||
allowListed
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Object.entries(state.whiteListed || {}).forEach((entry) => {
|
||||
whiteListed.push(entry);
|
||||
Object.entries(state.allowListed || {}).forEach((entry) => {
|
||||
allowListed.push(entry);
|
||||
});
|
||||
|
||||
optionCallbacks.forEach(([, callback]) => {
|
||||
|
@ -393,14 +402,14 @@ export function setup(opts, siteSettings, state) {
|
|||
opts.setup = true;
|
||||
|
||||
if (!opts.discourse.sanitizer || !opts.sanitizer) {
|
||||
const whiteLister = new WhiteLister(opts.discourse);
|
||||
const allowLister = new AllowLister(opts.discourse);
|
||||
|
||||
whiteListed.forEach(([feature, info]) => {
|
||||
whiteLister.whiteListFeature(feature, info);
|
||||
allowListed.forEach(([feature, info]) => {
|
||||
allowLister.allowListFeature(feature, info);
|
||||
});
|
||||
|
||||
opts.sanitizer = opts.discourse.sanitizer = !!opts.discourse.sanitize
|
||||
? (a) => sanitize(a, whiteLister)
|
||||
? (a) => sanitize(a, allowLister)
|
||||
: (a) => a;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ export function hrefAllowed(href, extraHrefMatchers) {
|
|||
}
|
||||
}
|
||||
|
||||
export function sanitize(text, whiteLister) {
|
||||
export function sanitize(text, allowLister) {
|
||||
if (!text) {
|
||||
return "";
|
||||
}
|
||||
|
@ -79,9 +79,9 @@ export function sanitize(text, whiteLister) {
|
|||
// Allow things like <3 and <_<
|
||||
text = text.replace(/<([^A-Za-z\/\!]|$)/g, "<$1");
|
||||
|
||||
const whiteList = whiteLister.getWhiteList(),
|
||||
allowedHrefSchemes = whiteLister.getAllowedHrefSchemes(),
|
||||
allowedIframes = whiteLister.getAllowedIframes();
|
||||
const allowList = allowLister.getAllowList(),
|
||||
allowedHrefSchemes = allowLister.getAllowedHrefSchemes(),
|
||||
allowedIframes = allowLister.getAllowedIframes();
|
||||
let extraHrefMatchers = null;
|
||||
|
||||
if (allowedHrefSchemes && allowedHrefSchemes.length > 0) {
|
||||
|
@ -94,12 +94,12 @@ export function sanitize(text, whiteLister) {
|
|||
}
|
||||
|
||||
let result = xss(text, {
|
||||
whiteList: whiteList.tagList,
|
||||
whiteList: allowList.tagList,
|
||||
stripIgnoreTag: true,
|
||||
stripIgnoreTagBody: ["script", "table"],
|
||||
|
||||
onIgnoreTagAttr(tag, name, value) {
|
||||
const forTag = whiteList.attrList[tag];
|
||||
const forTag = allowList.attrList[tag];
|
||||
if (forTag) {
|
||||
const forAttr = forTag[name];
|
||||
if (
|
||||
|
@ -134,7 +134,7 @@ export function sanitize(text, whiteLister) {
|
|||
return attr(name, value);
|
||||
}
|
||||
|
||||
const custom = whiteLister.getCustom();
|
||||
const custom = allowLister.getCustom();
|
||||
for (let i = 0; i < custom.length; i++) {
|
||||
const fn = custom[i];
|
||||
if (fn(tag, name, value)) {
|
||||
|
|
|
@ -1,229 +1,15 @@
|
|||
// to match:
|
||||
// abcd
|
||||
// abcd[test]
|
||||
// abcd[test=bob]
|
||||
const WHITELIST_REGEX = /([^\[]+)(\[([^=]+)(=(.*))?\])?/;
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import AllowLister from "pretty-text/allow-lister";
|
||||
import { DEFAULT_LIST as NEW_DEFAULT_LIST } from "pretty-text/allow-lister";
|
||||
|
||||
export default class WhiteLister {
|
||||
export default class WhiteLister extends AllowLister {
|
||||
constructor(options) {
|
||||
this._enabled = { default: true };
|
||||
this._allowedHrefSchemes = (options && options.allowedHrefSchemes) || [];
|
||||
this._allowedIframes = (options && options.allowedIframes) || [];
|
||||
this._rawFeatures = [["default", DEFAULT_LIST]];
|
||||
|
||||
this._cache = null;
|
||||
|
||||
if (options && options.features) {
|
||||
Object.keys(options.features).forEach((f) => {
|
||||
if (options.features[f]) {
|
||||
this._enabled[f] = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
whiteListFeature(feature, info) {
|
||||
this._rawFeatures.push([feature, info]);
|
||||
}
|
||||
|
||||
disable(feature) {
|
||||
this._enabled[feature] = false;
|
||||
this._cache = null;
|
||||
}
|
||||
|
||||
enable(feature) {
|
||||
this._enabled[feature] = true;
|
||||
this._cache = null;
|
||||
}
|
||||
|
||||
_buildCache() {
|
||||
const tagList = {};
|
||||
const attrList = {};
|
||||
const custom = [];
|
||||
|
||||
this._rawFeatures.forEach(([name, info]) => {
|
||||
if (!this._enabled[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info.custom) {
|
||||
custom.push(info.custom);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof info === "string") {
|
||||
info = [info];
|
||||
}
|
||||
|
||||
(info || []).forEach((tag) => {
|
||||
const classes = tag.split(".");
|
||||
const tagWithAttr = classes.shift();
|
||||
|
||||
const m = WHITELIST_REGEX.exec(tagWithAttr);
|
||||
if (m) {
|
||||
const [, tagname, , attr, , val] = m;
|
||||
tagList[tagname] = [];
|
||||
|
||||
let attrs = (attrList[tagname] = attrList[tagname] || {});
|
||||
if (classes.length > 0) {
|
||||
attrs["class"] = (attrs["class"] || []).concat(classes);
|
||||
}
|
||||
|
||||
if (attr) {
|
||||
let attrInfo = (attrs[attr] = attrs[attr] || []);
|
||||
|
||||
if (val) {
|
||||
attrInfo.push(val);
|
||||
} else {
|
||||
attrs[attr] = ["*"];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
deprecated("`WhiteLister` has been replaced with `AllowLister`", {
|
||||
since: "2.6.0.beta.4",
|
||||
dropFrom: "2.7.0",
|
||||
});
|
||||
|
||||
this._cache = { custom, whiteList: { tagList, attrList } };
|
||||
}
|
||||
|
||||
_ensureCache() {
|
||||
if (!this._cache) {
|
||||
this._buildCache();
|
||||
}
|
||||
}
|
||||
|
||||
getWhiteList() {
|
||||
this._ensureCache();
|
||||
return this._cache.whiteList;
|
||||
}
|
||||
|
||||
getCustom() {
|
||||
this._ensureCache();
|
||||
return this._cache.custom;
|
||||
}
|
||||
|
||||
getAllowedHrefSchemes() {
|
||||
return this._allowedHrefSchemes;
|
||||
}
|
||||
|
||||
getAllowedIframes() {
|
||||
return this._allowedIframes;
|
||||
super(options);
|
||||
}
|
||||
}
|
||||
|
||||
// Only add to `default` when you always want your allowlist to occur. In other words,
|
||||
// don't change this for a plugin or a feature that can be disabled
|
||||
export const DEFAULT_LIST = [
|
||||
"a.attachment",
|
||||
"a.hashtag",
|
||||
"a.mention",
|
||||
"a.mention-group",
|
||||
"a.onebox",
|
||||
`a.inline-onebox`,
|
||||
`a.inline-onebox-loading`,
|
||||
"a[data-bbcode]",
|
||||
"a[name]",
|
||||
"a[rel=nofollow]",
|
||||
"a[rel=ugc]",
|
||||
"a[target=_blank]",
|
||||
"a[title]",
|
||||
"abbr[title]",
|
||||
"aside.quote",
|
||||
"aside[data-*]",
|
||||
"audio",
|
||||
"audio[controls]",
|
||||
"audio[preload]",
|
||||
"b",
|
||||
"big",
|
||||
"blockquote",
|
||||
"br",
|
||||
"code",
|
||||
"dd",
|
||||
"del",
|
||||
"div",
|
||||
"div.quote-controls",
|
||||
"div.title",
|
||||
"div[align]",
|
||||
"div[lang]",
|
||||
"div[data-*]" /* This may seem a bit much but polls does
|
||||
it anyway and this is needed for themes,
|
||||
special code in sanitizer handles data-*
|
||||
nothing exists for data-theme-* and we
|
||||
don't want to slow sanitize for this case
|
||||
*/,
|
||||
"div[dir]",
|
||||
"dl",
|
||||
"dt",
|
||||
"em",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"hr",
|
||||
"i",
|
||||
"iframe",
|
||||
"iframe[frameborder]",
|
||||
"iframe[height]",
|
||||
"iframe[marginheight]",
|
||||
"iframe[marginwidth]",
|
||||
"iframe[width]",
|
||||
"iframe[allowfullscreen]",
|
||||
"img[alt]",
|
||||
"img[height]",
|
||||
"img[title]",
|
||||
"img[width]",
|
||||
"ins",
|
||||
"kbd",
|
||||
"li",
|
||||
"ol",
|
||||
"ol[start]",
|
||||
"p",
|
||||
"p[lang]",
|
||||
"picture",
|
||||
"pre",
|
||||
"s",
|
||||
"small",
|
||||
"span[lang]",
|
||||
"span.excerpt",
|
||||
"div.excerpt",
|
||||
"div.video-container",
|
||||
"div.onebox-placeholder-container",
|
||||
"span.placeholder-icon video",
|
||||
"span.hashtag",
|
||||
"span.mention",
|
||||
"strike",
|
||||
"strong",
|
||||
"sub",
|
||||
"sup",
|
||||
"source[data-orig-src]",
|
||||
"source[src]",
|
||||
"source[srcset]",
|
||||
"source[type]",
|
||||
"track",
|
||||
"track[default]",
|
||||
"track[label]",
|
||||
"track[kind]",
|
||||
"track[src]",
|
||||
"track[srclang]",
|
||||
"ul",
|
||||
"video",
|
||||
"video[autoplay]",
|
||||
"video[controls]",
|
||||
"video[controlslist]",
|
||||
"video[crossorigin]",
|
||||
"video[height]",
|
||||
"video[loop]",
|
||||
"video[muted]",
|
||||
"video[playsinline]",
|
||||
"video[poster]",
|
||||
"video[preload]",
|
||||
"video[width]",
|
||||
"ruby",
|
||||
"ruby[lang]",
|
||||
"rb",
|
||||
"rb[lang]",
|
||||
"rp",
|
||||
"rt",
|
||||
"rt[lang]",
|
||||
];
|
||||
export const DEFAULT_LIST = NEW_DEFAULT_LIST;
|
||||
|
|
|
@ -147,7 +147,7 @@ function processBBCode(state, silent) {
|
|||
}
|
||||
|
||||
export function setup(helper) {
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"span.bbcode-b",
|
||||
"span.bbcode-i",
|
||||
"span.bbcode-u",
|
||||
|
|
|
@ -41,7 +41,7 @@ export function setup(helper) {
|
|||
.concat(["auto", "nohighlight"]);
|
||||
});
|
||||
|
||||
helper.whiteList({
|
||||
helper.allowList({
|
||||
custom(tag, name, value) {
|
||||
if (tag === "code" && name === "class") {
|
||||
const m = /^lang\-(.+)$/.exec(value);
|
||||
|
|
|
@ -68,5 +68,5 @@ export function setup(helper) {
|
|||
md.block.bbcode.ruler.push("block-wrap", blockRule);
|
||||
});
|
||||
|
||||
helper.whiteList([`div.${WRAP_CLASS}`, `span.${WRAP_CLASS}`, "span[data-*]"]);
|
||||
helper.allowList([`div.${WRAP_CLASS}`, `span.${WRAP_CLASS}`, "span[data-*]"]);
|
||||
}
|
||||
|
|
|
@ -339,7 +339,7 @@ export function setup(helper) {
|
|||
);
|
||||
});
|
||||
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"img[class=emoji]",
|
||||
"img[class=emoji emoji-custom]",
|
||||
"img[class=emoji emoji-custom only-emoji]",
|
||||
|
|
|
@ -2,7 +2,7 @@ export function setup(helper) {
|
|||
const opts = helper.getOptions();
|
||||
|
||||
if (opts.previewing && opts.injectLineNumbersToPreview) {
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"p.preview-sync-line",
|
||||
"p[data-line-number]",
|
||||
"h1.preview-sync-line",
|
||||
|
|
|
@ -168,8 +168,8 @@ export function setup(helper) {
|
|||
md.block.bbcode.ruler.push("quotes", rule);
|
||||
});
|
||||
|
||||
helper.whiteList(["img[class=avatar]"]);
|
||||
helper.whiteList({
|
||||
helper.allowList(["img[class=avatar]"]);
|
||||
helper.allowList({
|
||||
custom(tag, name, value) {
|
||||
if (tag === "aside" && name === "class") {
|
||||
return (
|
||||
|
|
|
@ -71,7 +71,7 @@ export const priority = 1;
|
|||
export function setup(helper) {
|
||||
const opts = helper.getOptions();
|
||||
if (opts.previewing) {
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"span.image-wrapper",
|
||||
"span.button-wrapper",
|
||||
"span[class=scale-btn]",
|
||||
|
|
|
@ -10,7 +10,7 @@ export function setup(helper) {
|
|||
});
|
||||
|
||||
// we need a custom callback for style handling
|
||||
helper.whiteList({
|
||||
helper.allowList({
|
||||
custom: function (tag, attr, val) {
|
||||
if (tag !== "th" && tag !== "td") {
|
||||
return false;
|
||||
|
@ -28,7 +28,7 @@ export function setup(helper) {
|
|||
},
|
||||
});
|
||||
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"table",
|
||||
"tbody",
|
||||
"thead",
|
||||
|
|
|
@ -91,10 +91,10 @@ function rule(state) {
|
|||
export function setup(helper) {
|
||||
const opts = helper.getOptions();
|
||||
if (opts.previewing) {
|
||||
helper.whiteList(["img.resizable"]);
|
||||
helper.allowList(["img.resizable"]);
|
||||
}
|
||||
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"img[data-orig-src]",
|
||||
"img[data-base62-sha1]",
|
||||
"a[data-orig-href]",
|
||||
|
|
|
@ -90,6 +90,7 @@ module PrettyText
|
|||
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/get-url")
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/object")
|
||||
apply_es6_file(ctx, root_path, "discourse-common/addon/lib/deprecated")
|
||||
apply_es6_file(ctx, root_path, "discourse/app/lib/to-markdown")
|
||||
apply_es6_file(ctx, root_path, "discourse/app/lib/utilities")
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ const rule = {
|
|||
};
|
||||
|
||||
export function setup(helper) {
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"summary",
|
||||
"summary[title]",
|
||||
"details",
|
||||
|
|
|
@ -138,7 +138,7 @@ function closeBuffer(buffer, state, text) {
|
|||
}
|
||||
|
||||
export function setup(helper) {
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"span.discourse-local-date",
|
||||
"span[data-*]",
|
||||
"span[aria-label]",
|
||||
|
|
|
@ -272,7 +272,7 @@ function newApiInit(helper) {
|
|||
}
|
||||
|
||||
export function setup(helper) {
|
||||
helper.whiteList([
|
||||
helper.allowList([
|
||||
"div.poll",
|
||||
"div.poll-info",
|
||||
"div.poll-container",
|
||||
|
|
Loading…
Reference in New Issue
Block a user