@edgex-fe/editor-preview 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,228 @@
1
+ // src/sanitizerRuntime.node.ts
2
+ import { fromHtml } from "hast-util-from-html";
3
+ import { sanitize } from "hast-util-sanitize";
4
+ import { toHtml } from "hast-util-to-html";
5
+
6
+ // src/sanitizerConfig.ts
7
+ var EDITOR_ALLOWED_TAGS = [
8
+ "a",
9
+ "abbr",
10
+ "b",
11
+ "blockquote",
12
+ "br",
13
+ "caption",
14
+ "code",
15
+ "col",
16
+ "colgroup",
17
+ "dd",
18
+ "del",
19
+ "details",
20
+ "div",
21
+ "dl",
22
+ "dt",
23
+ "em",
24
+ "figcaption",
25
+ "figure",
26
+ "footer",
27
+ "h1",
28
+ "h2",
29
+ "h3",
30
+ "h4",
31
+ "h5",
32
+ "h6",
33
+ "hr",
34
+ "i",
35
+ "img",
36
+ "kbd",
37
+ "li",
38
+ "mark",
39
+ "ol",
40
+ "p",
41
+ "pre",
42
+ "s",
43
+ "section",
44
+ "small",
45
+ "source",
46
+ "span",
47
+ "strong",
48
+ "sub",
49
+ "summary",
50
+ "sup",
51
+ "table",
52
+ "tbody",
53
+ "td",
54
+ "tfoot",
55
+ "th",
56
+ "thead",
57
+ "tr",
58
+ "u",
59
+ "ul",
60
+ "video"
61
+ ];
62
+ var EDITOR_FORBIDDEN_CONTENT_TAGS = [
63
+ "base",
64
+ "button",
65
+ "embed",
66
+ "form",
67
+ "iframe",
68
+ "input",
69
+ "link",
70
+ "math",
71
+ "meta",
72
+ "object",
73
+ "script",
74
+ "select",
75
+ "style",
76
+ "svg",
77
+ "textarea"
78
+ ];
79
+
80
+ // src/sanitizerNodeConfig.ts
81
+ var HAST_ALLOWED_ATTRIBUTES = [
82
+ "abbr",
83
+ "alt",
84
+ "ariaLabel",
85
+ "ariaLabelledBy",
86
+ "autoPlay",
87
+ "className",
88
+ "colSpan",
89
+ "controls",
90
+ "data*",
91
+ "decoding",
92
+ "dir",
93
+ "headers",
94
+ "height",
95
+ "href",
96
+ "lang",
97
+ "loading",
98
+ "loop",
99
+ "muted",
100
+ "open",
101
+ "playsInline",
102
+ "poster",
103
+ "preload",
104
+ "rel",
105
+ "reversed",
106
+ "role",
107
+ "rowSpan",
108
+ "scope",
109
+ "span",
110
+ "src",
111
+ "start",
112
+ "style",
113
+ "summary",
114
+ "target",
115
+ "title",
116
+ "type",
117
+ "value",
118
+ "width"
119
+ ];
120
+ var EDITOR_HAST_SCHEMA = {
121
+ allowComments: false,
122
+ allowDoctypes: false,
123
+ attributes: { "*": HAST_ALLOWED_ATTRIBUTES },
124
+ clobber: [],
125
+ protocols: {
126
+ href: ["http", "https", "mailto"],
127
+ poster: ["http", "https"],
128
+ src: ["data", "http", "https"]
129
+ },
130
+ required: {},
131
+ strip: EDITOR_FORBIDDEN_CONTENT_TAGS,
132
+ tagNames: EDITOR_ALLOWED_TAGS
133
+ };
134
+
135
+ // src/sanitizerHook.ts
136
+ var ALLOWED_LINK_TARGETS = /* @__PURE__ */ new Set(["_blank", "_parent", "_self", "_top"]);
137
+ var SAFE_STYLE_PROPERTIES = /* @__PURE__ */ new Set(["background", "background-color", "color", "text-align"]);
138
+ var DATA_IMAGE_URI_PATTERN = /^data:image\/(?:gif|jpeg|jpg|png|svg\+xml|webp);/i;
139
+ var sanitizeEditorStyle = (style) => {
140
+ const declarations = [];
141
+ for (const rawDeclaration of style.split(";")) {
142
+ const declaration = rawDeclaration.trim();
143
+ const separatorIndex = declaration.indexOf(":");
144
+ if (separatorIndex === -1) continue;
145
+ const property = declaration.slice(0, separatorIndex).trim().toLowerCase();
146
+ const value = declaration.slice(separatorIndex + 1).trim();
147
+ if (!SAFE_STYLE_PROPERTIES.has(property)) continue;
148
+ if (!value || /(?:expression|url)\s*\(|@import|behavior\s*:/i.test(value)) {
149
+ continue;
150
+ }
151
+ if (property === "text-align" && !/^(?:center|end|justify|left|right|start)$/i.test(value)) {
152
+ continue;
153
+ }
154
+ declarations.push(`${property}: ${value}`);
155
+ }
156
+ return declarations.join("; ");
157
+ };
158
+ var isAllowedEditorLinkTarget = (target) => ALLOWED_LINK_TARGETS.has(target);
159
+ var isAllowedEditorDataImageUri = (src) => !/^data:/i.test(src.trim()) || DATA_IMAGE_URI_PATTERN.test(src.trim());
160
+
161
+ // src/sanitizerNodeTree.ts
162
+ var TABLE_CONTAINER_CLASS_NAME = "wysiwyg-table";
163
+ var readStringProperty = (properties, key) => {
164
+ const value = properties[key];
165
+ return typeof value === "string" ? value : "";
166
+ };
167
+ var hasTableContainer = (ancestors) => ancestors.some((ancestor) => {
168
+ const className = ancestor.properties["className"];
169
+ return Array.isArray(className) ? className.includes(TABLE_CONTAINER_CLASS_NAME) : className === TABLE_CONTAINER_CLASS_NAME;
170
+ });
171
+ var hasTableAncestor = (ancestors) => ancestors.some((ancestor) => ancestor.tagName === "table");
172
+ var wrapTable = (table) => ({
173
+ type: "element",
174
+ tagName: "div",
175
+ properties: { className: [TABLE_CONTAINER_CLASS_NAME] },
176
+ children: [table]
177
+ });
178
+ var sanitizeElement = (element, ancestors) => {
179
+ const { properties } = element;
180
+ const safeStyle = sanitizeEditorStyle(readStringProperty(properties, "style"));
181
+ if (safeStyle) {
182
+ properties["style"] = safeStyle;
183
+ } else {
184
+ delete properties["style"];
185
+ }
186
+ if (element.tagName === "a") {
187
+ const target = readStringProperty(properties, "target");
188
+ if (target && !isAllowedEditorLinkTarget(target)) {
189
+ delete properties["target"];
190
+ }
191
+ if (properties["target"] === "_blank") {
192
+ properties["rel"] = ["noopener", "noreferrer"];
193
+ }
194
+ }
195
+ const src = readStringProperty(properties, "src");
196
+ if (/^data:/i.test(src.trim()) && (element.tagName !== "img" || !isAllowedEditorDataImageUri(src))) {
197
+ delete properties["src"];
198
+ }
199
+ const nextAncestors = [...ancestors, element];
200
+ element.children = element.children.map((child) => {
201
+ if (child.type !== "element") return child;
202
+ sanitizeElement(child, nextAncestors);
203
+ return child.tagName === "table" && !hasTableContainer(nextAncestors) && !hasTableAncestor(nextAncestors) ? wrapTable(child) : child;
204
+ });
205
+ };
206
+ var applyEditorHastPolicy = (tree) => {
207
+ tree.children = tree.children.map((child) => {
208
+ if (child.type !== "element") return child;
209
+ sanitizeElement(child, []);
210
+ return child.tagName === "table" ? wrapTable(child) : child;
211
+ });
212
+ };
213
+
214
+ // src/sanitizerRuntime.node.ts
215
+ function sanitizeEditorHtml(html) {
216
+ const tree = sanitize(fromHtml(html, { fragment: true }), EDITOR_HAST_SCHEMA);
217
+ if (tree.type !== "root") return "";
218
+ applyEditorHastPolicy(tree);
219
+ return toHtml(tree);
220
+ }
221
+ function releaseEditorSanitizer() {
222
+ return;
223
+ }
224
+ export {
225
+ releaseEditorSanitizer,
226
+ sanitizeEditorHtml
227
+ };
228
+ //# sourceMappingURL=sanitizer-runtime.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/sanitizerRuntime.node.ts","../../src/sanitizerConfig.ts","../../src/sanitizerNodeConfig.ts","../../src/sanitizerHook.ts","../../src/sanitizerNodeTree.ts"],"sourcesContent":["import { fromHtml } from \"hast-util-from-html\";\nimport { sanitize } from \"hast-util-sanitize\";\nimport { toHtml } from \"hast-util-to-html\";\nimport { EDITOR_HAST_SCHEMA } from \"./sanitizerNodeConfig\";\nimport { applyEditorHastPolicy } from \"./sanitizerNodeTree\";\nimport type { EditorHtml } from \"./types\";\n\nexport function sanitizeEditorHtml(html: EditorHtml) {\n const tree = sanitize(fromHtml(html, { fragment: true }), EDITOR_HAST_SCHEMA);\n if (tree.type !== \"root\") return \"\";\n\n applyEditorHastPolicy(tree);\n return toHtml(tree);\n}\n\nexport function releaseEditorSanitizer(): void {\n return;\n}\n","import type { Config } from \"dompurify\";\n\nexport const EDITOR_ALLOWED_TAGS = [\n \"a\",\n \"abbr\",\n \"b\",\n \"blockquote\",\n \"br\",\n \"caption\",\n \"code\",\n \"col\",\n \"colgroup\",\n \"dd\",\n \"del\",\n \"details\",\n \"div\",\n \"dl\",\n \"dt\",\n \"em\",\n \"figcaption\",\n \"figure\",\n \"footer\",\n \"h1\",\n \"h2\",\n \"h3\",\n \"h4\",\n \"h5\",\n \"h6\",\n \"hr\",\n \"i\",\n \"img\",\n \"kbd\",\n \"li\",\n \"mark\",\n \"ol\",\n \"p\",\n \"pre\",\n \"s\",\n \"section\",\n \"small\",\n \"source\",\n \"span\",\n \"strong\",\n \"sub\",\n \"summary\",\n \"sup\",\n \"table\",\n \"tbody\",\n \"td\",\n \"tfoot\",\n \"th\",\n \"thead\",\n \"tr\",\n \"u\",\n \"ul\",\n \"video\",\n];\n\nexport const EDITOR_FORBIDDEN_CONTENT_TAGS = [\n \"base\",\n \"button\",\n \"embed\",\n \"form\",\n \"iframe\",\n \"input\",\n \"link\",\n \"math\",\n \"meta\",\n \"object\",\n \"script\",\n \"select\",\n \"style\",\n \"svg\",\n \"textarea\",\n];\n\nexport const EDITOR_ALLOWED_ATTRIBUTES = [\n \"abbr\",\n \"alt\",\n \"aria-label\",\n \"aria-labelledby\",\n \"autoplay\",\n \"class\",\n \"colspan\",\n \"controls\",\n \"data-align\",\n \"decoding\",\n \"dir\",\n \"headers\",\n \"height\",\n \"href\",\n \"lang\",\n \"loading\",\n \"loop\",\n \"muted\",\n \"open\",\n \"playsinline\",\n \"poster\",\n \"preload\",\n \"rel\",\n \"reversed\",\n \"role\",\n \"rowspan\",\n \"scope\",\n \"span\",\n \"src\",\n \"start\",\n \"style\",\n \"summary\",\n \"target\",\n \"title\",\n \"type\",\n \"value\",\n \"width\",\n];\n\nexport const EDITOR_SAFE_URI_PATTERN =\n /^(?:(?:https?|mailto):|[^a-z]|[a-z+.-]+(?:[^a-z+.:-]|$))/i;\n\nexport const EDITOR_SANITIZE_CONFIG = {\n ADD_DATA_URI_TAGS: [\"img\"],\n ALLOW_ARIA_ATTR: true,\n ALLOW_DATA_ATTR: true,\n ALLOWED_ATTR: EDITOR_ALLOWED_ATTRIBUTES,\n ALLOWED_TAGS: EDITOR_ALLOWED_TAGS,\n ALLOWED_URI_REGEXP: EDITOR_SAFE_URI_PATTERN,\n FORBID_CONTENTS: EDITOR_FORBIDDEN_CONTENT_TAGS,\n FORBID_TAGS: EDITOR_FORBIDDEN_CONTENT_TAGS,\n KEEP_CONTENT: true,\n} satisfies Config;\n","import type { Schema } from \"hast-util-sanitize\";\nimport {\n EDITOR_ALLOWED_TAGS,\n EDITOR_FORBIDDEN_CONTENT_TAGS,\n} from \"./sanitizerConfig\";\n\nconst HAST_ALLOWED_ATTRIBUTES = [\n \"abbr\",\n \"alt\",\n \"ariaLabel\",\n \"ariaLabelledBy\",\n \"autoPlay\",\n \"className\",\n \"colSpan\",\n \"controls\",\n \"data*\",\n \"decoding\",\n \"dir\",\n \"headers\",\n \"height\",\n \"href\",\n \"lang\",\n \"loading\",\n \"loop\",\n \"muted\",\n \"open\",\n \"playsInline\",\n \"poster\",\n \"preload\",\n \"rel\",\n \"reversed\",\n \"role\",\n \"rowSpan\",\n \"scope\",\n \"span\",\n \"src\",\n \"start\",\n \"style\",\n \"summary\",\n \"target\",\n \"title\",\n \"type\",\n \"value\",\n \"width\",\n];\n\nexport const EDITOR_HAST_SCHEMA: Schema = {\n allowComments: false,\n allowDoctypes: false,\n attributes: { \"*\": HAST_ALLOWED_ATTRIBUTES },\n clobber: [],\n protocols: {\n href: [\"http\", \"https\", \"mailto\"],\n poster: [\"http\", \"https\"],\n src: [\"data\", \"http\", \"https\"],\n },\n required: {},\n strip: EDITOR_FORBIDDEN_CONTENT_TAGS,\n tagNames: EDITOR_ALLOWED_TAGS,\n};\n","import type { ElementHook, NodeHook } from \"dompurify\";\n\nconst ALLOWED_LINK_TARGETS = new Set([\"_blank\", \"_parent\", \"_self\", \"_top\"]);\nconst SAFE_STYLE_PROPERTIES = new Set([\"background\", \"background-color\", \"color\", \"text-align\"]);\nconst DATA_IMAGE_URI_PATTERN = /^data:image\\/(?:gif|jpeg|jpg|png|svg\\+xml|webp);/i;\nconst TABLE_CONTAINER_CLASS_NAME = \"wysiwyg-table\";\n\nexport const sanitizeEditorStyle = (style: string) => {\n const declarations: string[] = [];\n\n for (const rawDeclaration of style.split(\";\")) {\n const declaration = rawDeclaration.trim();\n const separatorIndex = declaration.indexOf(\":\");\n if (separatorIndex === -1) continue;\n\n const property = declaration.slice(0, separatorIndex).trim().toLowerCase();\n const value = declaration.slice(separatorIndex + 1).trim();\n\n if (!SAFE_STYLE_PROPERTIES.has(property)) continue;\n if (!value || /(?:expression|url)\\s*\\(|@import|behavior\\s*:/i.test(value)) {\n continue;\n }\n if (property === \"text-align\" && !/^(?:center|end|justify|left|right|start)$/i.test(value)) {\n continue;\n }\n\n declarations.push(`${property}: ${value}`);\n }\n\n return declarations.join(\"; \");\n};\n\nexport const isAllowedEditorLinkTarget = (target: string) =>\n ALLOWED_LINK_TARGETS.has(target);\n\nexport const isAllowedEditorDataImageUri = (src: string) =>\n !/^data:/i.test(src.trim()) || DATA_IMAGE_URI_PATTERN.test(src.trim());\n\nexport const sanitizeEditorAttributes: ElementHook = (element) => {\n const safeStyle = sanitizeEditorStyle(element.getAttribute(\"style\") ?? \"\");\n if (safeStyle) {\n element.setAttribute(\"style\", safeStyle);\n } else {\n element.removeAttribute(\"style\");\n }\n\n const tagName = element.tagName.toLowerCase();\n\n if (tagName === \"a\") {\n const target = element.getAttribute(\"target\");\n if (target && !isAllowedEditorLinkTarget(target)) {\n element.removeAttribute(\"target\");\n }\n\n if (element.getAttribute(\"target\") === \"_blank\") {\n element.setAttribute(\"rel\", \"noopener noreferrer\");\n }\n return;\n }\n\n const src = element.getAttribute(\"src\") ?? \"\";\n if (\n /^data:/i.test(src.trim()) &&\n (tagName !== \"img\" || !isAllowedEditorDataImageUri(src))\n ) {\n element.removeAttribute(\"src\");\n }\n};\n\nexport const wrapEditorTable: NodeHook = (node) => {\n if (node.nodeType !== node.ELEMENT_NODE) return;\n\n const table = node as Element;\n if (table.tagName.toLowerCase() !== \"table\") return;\n\n const parent = table.parentElement;\n if (!parent || parent.closest(`.${TABLE_CONTAINER_CLASS_NAME}`)) return;\n\n const container = table.ownerDocument.createElement(\"div\");\n container.className = TABLE_CONTAINER_CLASS_NAME;\n parent.insertBefore(container, table);\n container.append(table);\n};\n","import type { Element, Properties, Root } from \"hast\";\nimport {\n isAllowedEditorDataImageUri,\n isAllowedEditorLinkTarget,\n sanitizeEditorStyle,\n} from \"./sanitizerHook\";\n\nconst TABLE_CONTAINER_CLASS_NAME = \"wysiwyg-table\";\n\nconst readStringProperty = (properties: Properties, key: string) => {\n const value = properties[key];\n return typeof value === \"string\" ? value : \"\";\n};\n\nconst hasTableContainer = (ancestors: Element[]) =>\n ancestors.some((ancestor) => {\n const className = ancestor.properties[\"className\"];\n return Array.isArray(className)\n ? className.includes(TABLE_CONTAINER_CLASS_NAME)\n : className === TABLE_CONTAINER_CLASS_NAME;\n });\n\nconst hasTableAncestor = (ancestors: Element[]) =>\n ancestors.some((ancestor) => ancestor.tagName === \"table\");\n\nconst wrapTable = (table: Element): Element => ({\n type: \"element\",\n tagName: \"div\",\n properties: { className: [TABLE_CONTAINER_CLASS_NAME] },\n children: [table],\n});\n\nconst sanitizeElement = (element: Element, ancestors: Element[]) => {\n const { properties } = element;\n const safeStyle = sanitizeEditorStyle(readStringProperty(properties, \"style\"));\n if (safeStyle) {\n properties[\"style\"] = safeStyle;\n } else {\n delete properties[\"style\"];\n }\n\n if (element.tagName === \"a\") {\n const target = readStringProperty(properties, \"target\");\n if (target && !isAllowedEditorLinkTarget(target)) {\n delete properties[\"target\"];\n }\n if (properties[\"target\"] === \"_blank\") {\n properties[\"rel\"] = [\"noopener\", \"noreferrer\"];\n }\n }\n\n const src = readStringProperty(properties, \"src\");\n if (\n /^data:/i.test(src.trim()) &&\n (element.tagName !== \"img\" || !isAllowedEditorDataImageUri(src))\n ) {\n delete properties[\"src\"];\n }\n\n const nextAncestors = [...ancestors, element];\n element.children = element.children.map((child) => {\n if (child.type !== \"element\") return child;\n sanitizeElement(child, nextAncestors);\n return child.tagName === \"table\" &&\n !hasTableContainer(nextAncestors) &&\n !hasTableAncestor(nextAncestors)\n ? wrapTable(child)\n : child;\n });\n};\n\nexport const applyEditorHastPolicy = (tree: Root) => {\n tree.children = tree.children.map((child) => {\n if (child.type !== \"element\") return child;\n sanitizeElement(child, []);\n return child.tagName === \"table\" ? wrapTable(child) : child;\n });\n};\n"],"mappings":"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","names":[]}