@json-editor/json-editor 2.15.3 → 2.16.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
@@ -2,7 +2,7 @@
2
2
  "name": "@json-editor/json-editor",
3
3
  "title": "JSONEditor",
4
4
  "description": "JSON Schema based editor",
5
- "version": "2.15.3",
5
+ "version": "2.16.0",
6
6
  "main": "dist/jsoneditor.js",
7
7
  "author": {
8
8
  "name": "Jeremy Dorn",
package/src/editor.js CHANGED
@@ -521,6 +521,20 @@ export class AbstractEditor {
521
521
  }
522
522
  }
523
523
 
524
+ purify (val) {
525
+ if (typeof val !== 'string') {
526
+ return val
527
+ }
528
+
529
+ if (window.DOMPurify) {
530
+ val = window.DOMPurify.sanitize(val)
531
+ } else {
532
+ val = this.cleanText(val)
533
+ }
534
+
535
+ return val
536
+ }
537
+
524
538
  getHeaderText (titleOnly) {
525
539
  if (this.header_text) return this.header_text
526
540
  else if (titleOnly) return this.translateProperty(this.schema.title)
@@ -84,6 +84,7 @@ export class HiddenEditor extends AbstractEditor {
84
84
  * This is overridden in derivative editors
85
85
  */
86
86
  sanitize (value) {
87
+ value = this.purify(value)
87
88
  return value
88
89
  }
89
90
 
@@ -178,6 +178,7 @@ export class MultiSelectEditor extends AbstractEditor {
178
178
  }
179
179
 
180
180
  sanitize (value) {
181
+ value = this.purify(value)
181
182
  if (this.schema.items.type === 'boolean') return !!value
182
183
  else if (this.schema.items.type === 'number') return 1 * value || 0
183
184
  else if (this.schema.items.type === 'integer') return Math.floor(value * 1 || 0)
@@ -18,6 +18,7 @@ export class StringEditor extends AbstractEditor {
18
18
  }
19
19
 
20
20
  setValue (value, initial, fromTemplate) {
21
+ value = this.purify(value)
21
22
  value = this.applyConstFilter(value)
22
23
 
23
24
  if (this.template && !fromTemplate) return
@@ -362,6 +363,7 @@ export class StringEditor extends AbstractEditor {
362
363
  * This is overridden in derivative editors
363
364
  */
364
365
  sanitize (value) {
366
+ value = this.purify(value)
365
367
  return value
366
368
  }
367
369
 
@@ -26,6 +26,7 @@ export class UuidEditor extends StringEditor {
26
26
  }
27
27
 
28
28
  sanitize (value) {
29
+ value = this.purify(value)
29
30
  if (!this.testUuid(value)) value = this.uuid
30
31
  return value
31
32
  }
@@ -0,0 +1,26 @@
1
+ /* global Feature Scenario */
2
+
3
+ Feature('purify')
4
+
5
+ Scenario('Should @purify @optional XSS from direct input', async ({ I }) => {
6
+ I.amOnPage('purify.html')
7
+ I.waitForElement('[name="root[string]"]')
8
+ I.fillField('[name="root[string]"]', 'bla</script><script>alert(1)</script>')
9
+ I.pressKey('Tab')
10
+ I.wait(1)
11
+ I.click('.get-value')
12
+ I.wait(1)
13
+ I.waitForValue('#value', '{"string":"bla"}')
14
+ })
15
+
16
+ Scenario('Should @purify @optional XSS from setValue() via textarea', async ({ I }) => {
17
+ I.amOnPage('purify.html')
18
+ I.waitForElement('#value')
19
+ I.fillField('#value', 'bla</script><script>alert(1)</script>')
20
+ I.pressKey('Tab')
21
+ I.click('.set-value')
22
+ I.wait(2)
23
+ I.click('.get-value')
24
+ I.wait(1)
25
+ I.waitForValue('#value', '{"string":"bla"}')
26
+ })
@@ -0,0 +1,5 @@
1
+ services:
2
+ chrome:
3
+ image: seleniarm/standalone-chromium
4
+ firefox:
5
+ image: seleniarm/standalone-firefox
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8"/>
5
+ <title>Purify</title>
6
+ <script src="https://cdn.jsdelivr.net/npm/dompurify@3.3.1/dist/purify.min.js"></script>
7
+ <script src="../../dist/jsoneditor.js"></script>
8
+ <link rel="stylesheet" id="theme-link" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
9
+ <link rel="stylesheet" id="iconlib-link" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
10
+ </head>
11
+ <body>
12
+
13
+ <div class="container">
14
+ <div id='editor-container'></div>
15
+ <label for="value">Value</label>
16
+ <textarea id="value" class="form-control value" rows="10"></textarea>
17
+ <button class="get-value btn btn-primary">Get Value</button>
18
+ <button class="set-value btn btn-secondary">Set Value</button>
19
+ </div>
20
+
21
+ <script>
22
+ const editorContainer = document.querySelector('#editor-container')
23
+ const value = document.querySelector('#value');
24
+ const schema = {
25
+ "type": "object",
26
+ "title": "Purify",
27
+ "properties": {
28
+ "string": {
29
+ "title": "string (StringEditor)",
30
+ "type": "string"
31
+ }
32
+ }
33
+ }
34
+
35
+ const editor = new JSONEditor(editorContainer, {
36
+ schema: schema,
37
+ theme: 'bootstrap4',
38
+ iconlib: 'fontawesome',
39
+ disable_properties: true,
40
+ disable_collapse: true,
41
+ disable_edit_json: true,
42
+ })
43
+
44
+ const getValueBtn = document.querySelector('.get-value')
45
+ const setValueBtn = document.querySelector('.set-value')
46
+
47
+ editor.on('change', function () {
48
+ value.value = JSON.stringify(editor.getValue())
49
+ })
50
+
51
+ getValueBtn.addEventListener('click', function () {
52
+ value.value = JSON.stringify(editor.getValue())
53
+ })
54
+
55
+ setValueBtn.addEventListener('click', function () {
56
+ try {
57
+ editor.setValue(JSON.parse(value.value))
58
+ } catch (e) {
59
+ editor.setValue({ string: value.value })
60
+ }
61
+ })
62
+ </script>
63
+
64
+ </body>
65
+ </html>
66
+