@budibase/bbui 3.45.0 → 3.47.0

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@budibase/bbui",
3
3
  "description": "A UI solution used in the different Budibase projects.",
4
- "version": "v3.45.0",
4
+ "version": "v3.47.0",
5
5
  "license": "MPL-2.0",
6
6
  "module": "dist/bbui.mjs",
7
7
  "exports": {
@@ -21,7 +21,7 @@
21
21
  "@sveltejs/vite-plugin-svelte": "^6.1.3",
22
22
  "@types/sanitize-html": "^2.13.0",
23
23
  "vite-plugin-css-injected-by-js": "3.5.2",
24
- "vitest": "^4.1.8"
24
+ "vitest": "^5.0.0"
25
25
  },
26
26
  "keywords": [
27
27
  "svelte"
@@ -108,5 +108,5 @@
108
108
  }
109
109
  }
110
110
  },
111
- "gitHead": "39146fbea58fca5022556582a42e57a794fdf8ad"
111
+ "gitHead": "adfff86585b1d393941175f58cbe74f2005616b4"
112
112
  }
@@ -0,0 +1,43 @@
1
+ import { describe, expect, it } from "vitest"
2
+
3
+ import { renderMarkdown } from "./renderMarkdown"
4
+
5
+ describe("renderMarkdown", () => {
6
+ it("preserves safe HTML used for email layouts", () => {
7
+ const html = renderMarkdown(
8
+ '<div style="color:red;padding:4px"><span>Alert</span><table width="600" cellpadding="4"><tr><td colspan="2">Body</td></tr></table></div>'
9
+ )
10
+
11
+ expect(html).toBe(
12
+ '<div style="color:red;padding:4px"><span>Alert</span><table width="600" cellpadding="4"><tr><td colspan="2">Body</td></tr></table></div>'
13
+ )
14
+ })
15
+
16
+ it("blocks the stored XSS advisory payload", () => {
17
+ const html = renderMarkdown(
18
+ '<iframe srcdoc="<script src=https://example.com/payload.mjs></script>"></iframe>'
19
+ )
20
+
21
+ expect(html).toBe("")
22
+ })
23
+
24
+ it("removes executable attributes, URLs, and styles", () => {
25
+ const html = renderMarkdown(
26
+ '<div class="spectrum-Modal" onclick="alert(1)" style="color:red;position:fixed;background-image:url(https://example.com/pixel)"><img src="https://example.com/image.png" onerror="alert(1)"><a href="javascript:alert(1)">Link</a></div>'
27
+ )
28
+
29
+ expect(html).toBe(
30
+ '<div style="color:red"><img src="https://example.com/image.png" /><a>Link</a></div>'
31
+ )
32
+ })
33
+
34
+ it("removes unsafe values from allowed style properties", () => {
35
+ const html = renderMarkdown(
36
+ '<div style="color:url(https://example.com/x);width:expression(alert(1));padding:4px">Direct</div><div style="color:u\\72l(https://example.com/x);width:e\\78pression(alert(1));font-family:u/**/rl(https://example.com/x);padding:4px">Obfuscated</div>'
37
+ )
38
+
39
+ expect(html).toBe(
40
+ '<div style="padding:4px">Direct</div><div style="padding:4px">Obfuscated</div>'
41
+ )
42
+ })
43
+ })
@@ -28,8 +28,81 @@ const MARKDOWN_TAGS = [
28
28
  "thead",
29
29
  "tr",
30
30
  "ul",
31
+ "div",
32
+ "span",
31
33
  ]
32
34
 
35
+ const MARKDOWN_ATTRIBUTES = {
36
+ "*": [
37
+ "align",
38
+ "bgcolor",
39
+ "dir",
40
+ "height",
41
+ "lang",
42
+ "role",
43
+ "style",
44
+ "valign",
45
+ "width",
46
+ ],
47
+ a: ["href", "title"],
48
+ img: ["alt", "src", "title"],
49
+ li: ["value"],
50
+ ol: ["reversed", "start", "type"],
51
+ table: ["border", "cellpadding", "cellspacing"],
52
+ td: ["colspan", "headers", "nowrap", "rowspan"],
53
+ th: ["colspan", "headers", "nowrap", "rowspan", "scope"],
54
+ }
55
+
56
+ const SAFE_STYLE_VALUE =
57
+ /^(?![\s\S]*(?:\\|\/\*|(?:expression|url)\s*\())[\s\S]*$/i
58
+ const MARKDOWN_STYLE_PROPERTIES = [
59
+ "background-color",
60
+ "border",
61
+ "border-bottom",
62
+ "border-collapse",
63
+ "border-color",
64
+ "border-left",
65
+ "border-right",
66
+ "border-spacing",
67
+ "border-style",
68
+ "border-top",
69
+ "border-width",
70
+ "color",
71
+ "display",
72
+ "font",
73
+ "font-family",
74
+ "font-size",
75
+ "font-style",
76
+ "font-weight",
77
+ "height",
78
+ "letter-spacing",
79
+ "line-height",
80
+ "margin",
81
+ "margin-bottom",
82
+ "margin-left",
83
+ "margin-right",
84
+ "margin-top",
85
+ "max-height",
86
+ "max-width",
87
+ "min-height",
88
+ "min-width",
89
+ "padding",
90
+ "padding-bottom",
91
+ "padding-left",
92
+ "padding-right",
93
+ "padding-top",
94
+ "text-align",
95
+ "text-decoration",
96
+ "vertical-align",
97
+ "width",
98
+ ]
99
+
100
+ const MARKDOWN_STYLES = {
101
+ "*": Object.fromEntries(
102
+ MARKDOWN_STYLE_PROPERTIES.map(property => [property, [SAFE_STYLE_VALUE]])
103
+ ),
104
+ }
105
+
33
106
  export const renderMarkdown = (markdown: string | undefined) => {
34
107
  if (!markdown) {
35
108
  return ""
@@ -39,10 +112,8 @@ export const renderMarkdown = (markdown: string | undefined) => {
39
112
 
40
113
  return sanitizeHtml(html, {
41
114
  allowedTags: MARKDOWN_TAGS,
42
- allowedAttributes: {
43
- a: ["href", "title"],
44
- img: ["alt", "src", "title"],
45
- },
115
+ allowedAttributes: MARKDOWN_ATTRIBUTES,
116
+ allowedStyles: MARKDOWN_STYLES,
46
117
  allowedSchemes: ["http", "https", "mailto", "tel"],
47
118
  allowedSchemesByTag: {
48
119
  img: ["http", "https"],
@@ -31,6 +31,7 @@
31
31
  export let secondaryButtonWarning: boolean = false
32
32
  export let custom: boolean = false
33
33
  export let disableCancelOnConfirm: boolean = false
34
+ export let compact: boolean = false
34
35
 
35
36
  const { hide, cancel } = getContext(Context.Modal)
36
37
 
@@ -72,6 +73,7 @@
72
73
  class:spectrum-Dialog--extraLarge={size === "XL"}
73
74
  class:no-grid={custom}
74
75
  class:noDivider={!showDivider}
76
+ class:compact
75
77
  style="position: relative;"
76
78
  role="dialog"
77
79
  tabindex="-1"
@@ -183,6 +185,10 @@
183
185
  border-bottom: 2px solid var(--spectrum-global-color-gray-200);
184
186
  }
185
187
 
188
+ .spectrum-Dialog.compact {
189
+ --spectrum-dialog-confirm-padding: 24px;
190
+ }
191
+
186
192
  .spectrum-Dialog-heading {
187
193
  font-size: 24px;
188
194
  }
@@ -1,25 +0,0 @@
1
- //#region \0rolldown/runtime.js
2
- var e = Object.create, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, r = Object.getOwnPropertyNames, i = Object.getPrototypeOf, a = Object.prototype.hasOwnProperty, o = (e, t) => () => (e && (t = e(e = 0)), t), s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), c = (e, n) => {
3
- let r = {};
4
- for (var i in e) t(r, i, {
5
- get: e[i],
6
- enumerable: !0
7
- });
8
- return n || t(r, Symbol.toStringTag, { value: "Module" }), r;
9
- }, l = (e, i, o, s) => {
10
- if (i && typeof i == "object" || typeof i == "function") for (var c = r(i), l = 0, u = c.length, d; l < u; l++) d = c[l], !a.call(e, d) && d !== o && t(e, d, {
11
- get: ((e) => i[e]).bind(null, d),
12
- enumerable: !(s = n(i, d)) || s.enumerable
13
- });
14
- return e;
15
- }, u = (n, r, a) => (a = n == null ? {} : e(i(n)), l(r || !n || !n.__esModule ? t(a, "default", {
16
- value: n,
17
- enumerable: !0
18
- }) : a, n)), d = (e) => a.call(e, "module.exports") ? e["module.exports"] : l(t({}, "__esModule", { value: !0 }), e), f = /* @__PURE__ */ ((e) => typeof require < "u" ? require : typeof Proxy < "u" ? new Proxy(e, { get: (e, t) => (typeof require < "u" ? require : e)[t] }) : e)(function(e) {
19
- if (typeof require < "u") return require.apply(this, arguments);
20
- throw Error("Calling `require` for \"" + e + "\" in an environment that doesn't expose the `require` function. See https://rolldown.rs/in-depth/bundling-cjs#require-external-modules for more details.");
21
- }), p = /* @__PURE__ */ s(((e, t) => {
22
- t.exports = {};
23
- }));
24
- //#endregion
25
- export { f as a, c as i, s as n, d as o, o as r, u as s, p as t };