@json-editor/json-editor 2.15.2 → 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/CHANGELOG.md +10 -0
- package/CONTRIBUTING.md +10 -0
- package/README.md +11 -0
- package/dist/jsoneditor.js +1 -1
- package/dist/jsoneditor.js.LICENSE.txt +1 -1
- package/dist/nonmin/jsoneditor.js +20 -2
- package/dist/nonmin/jsoneditor.js.map +1 -1
- package/docs/form-submission.html +1 -1
- package/docs/index.html +18 -0
- package/package.json +1 -1
- package/src/editor.js +15 -1
- package/src/editors/hidden.js +1 -0
- package/src/editors/multiselect.js +1 -0
- package/src/editors/string.js +2 -0
- package/src/editors/uuid.js +1 -0
- package/tests/codeceptjs/editors/purify_test.js +26 -0
- package/tests/codeceptjs/issues/issue-gh-1559_test.js +15 -0
- package/tests/docker-compose-local.yml +3 -2
- package/tests/pages/issues/issue-gh-1559.html +68 -0
- package/tests/pages/purify.html +66 -0
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
Try yourself, submit the form and look in the network tab of the developer tool.
|
|
25
25
|
</p>
|
|
26
26
|
<div class="form-group"></div>
|
|
27
|
-
<form
|
|
27
|
+
<form method="get">
|
|
28
28
|
<input id="input" type="hidden" name="json">
|
|
29
29
|
<div id='editor-container'></div>
|
|
30
30
|
<input id="submit" class="btn btn-primary" width="100" type="submit">
|
package/docs/index.html
CHANGED
|
@@ -10,9 +10,27 @@
|
|
|
10
10
|
<script src="./scripts/ajv-validator.js"></script>
|
|
11
11
|
<link rel='stylesheet' id='theme-link'>
|
|
12
12
|
<link rel='stylesheet' id='iconlib-link'>
|
|
13
|
+
<style>
|
|
14
|
+
.maintenance-notice {
|
|
15
|
+
background-color: #fff3cd;
|
|
16
|
+
border: 1px solid #ffeaa7;
|
|
17
|
+
border-radius: 4px;
|
|
18
|
+
padding: 12px 16px;
|
|
19
|
+
margin-bottom: 20px;
|
|
20
|
+
color: #856404;
|
|
21
|
+
}
|
|
22
|
+
.maintenance-notice a {
|
|
23
|
+
color: #533102;
|
|
24
|
+
text-decoration: underline;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
13
27
|
</head>
|
|
14
28
|
<body>
|
|
15
29
|
<div class="container grid-xl" style="padding-top: 15px; padding-bottom: 30px;">
|
|
30
|
+
<div class="maintenance-notice">
|
|
31
|
+
<strong>Maintenance Mode:</strong> This library is in maintenance mode.
|
|
32
|
+
For active development, consider <a href="https://github.com/germanbisurgi/jedison" target="_blank">Jedison</a>.
|
|
33
|
+
</div>
|
|
16
34
|
<div class="row columns md:flex">
|
|
17
35
|
<div class='col-7 col-md-7 w-7/12'>
|
|
18
36
|
<h1>Editor</h1>
|
package/package.json
CHANGED
package/src/editor.js
CHANGED
|
@@ -176,7 +176,7 @@ export class AbstractEditor {
|
|
|
176
176
|
const editor = this.jsoneditor.getEditor(path)
|
|
177
177
|
const value = editor ? editor.getValue() : undefined
|
|
178
178
|
|
|
179
|
-
if (!editor || !editor.dependenciesFulfilled ||
|
|
179
|
+
if (!editor || !editor.dependenciesFulfilled || value === undefined || value === null) {
|
|
180
180
|
this.dependenciesFulfilled = false
|
|
181
181
|
} else if (Array.isArray(choices)) {
|
|
182
182
|
this.dependenciesFulfilled = choices.some(choice => {
|
|
@@ -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)
|
package/src/editors/hidden.js
CHANGED
|
@@ -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)
|
package/src/editors/string.js
CHANGED
|
@@ -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
|
|
package/src/editors/uuid.js
CHANGED
|
@@ -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,15 @@
|
|
|
1
|
+
/* global Feature Scenario */
|
|
2
|
+
|
|
3
|
+
Feature('issues')
|
|
4
|
+
|
|
5
|
+
Scenario('GitHub issue 1559 should remain fixed @issue-1559', async ({ I }) => {
|
|
6
|
+
I.amOnPage('issues/issue-gh-1559.html')
|
|
7
|
+
I.waitForElement('.je-ready')
|
|
8
|
+
I.dontSeeElement('[data-schemapath="root.dependent_on_false"]')
|
|
9
|
+
I.click('[data-schemapath="root.dependent_on_true"] input')
|
|
10
|
+
I.waitForElement('[data-schemapath="root.dependent_on_false"]', 2)
|
|
11
|
+
I.seeElement('[data-schemapath="root.dependent_on_false"]')
|
|
12
|
+
I.click('[data-schemapath="root.dependent_on_true"] input')
|
|
13
|
+
I.waitForInvisible('[data-schemapath="root.dependent_on_false"]', 2)
|
|
14
|
+
I.dontSeeElement('[data-schemapath="root.dependent_on_false"]')
|
|
15
|
+
})
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8"/>
|
|
5
|
+
<title>GitHub Issue 1559 - Dependencies with false values not fulfilled</title>
|
|
6
|
+
<script src="../../../dist/jsoneditor.js"></script>
|
|
7
|
+
<link rel="stylesheet" id="theme-link" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
|
|
8
|
+
<link rel="stylesheet" id="iconlib-link" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
|
|
12
|
+
<div class="container">
|
|
13
|
+
<h1>Test - Dependencies with false values not fulfilled</h1>
|
|
14
|
+
<p>When <code>dependent_on_true</code> is unchecked (false), the <code>dependent_on_false</code> field should appear. This tests GitHub issue #1559 - dependencies with false values not being fulfilled.</p>
|
|
15
|
+
<div id='editor-container'></div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
var editorContainer = document.querySelector('#editor-container')
|
|
20
|
+
var schema = {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"title": "Test configuration",
|
|
23
|
+
"description": "Test configuration for dependencies with false values (GitHub issue #1559)",
|
|
24
|
+
"properties": {
|
|
25
|
+
"master_field": {
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"title": "Master field",
|
|
28
|
+
"format": "checkbox",
|
|
29
|
+
"description": "Master toggle field.",
|
|
30
|
+
"default": true
|
|
31
|
+
},
|
|
32
|
+
"dependent_on_true": {
|
|
33
|
+
"type": "boolean",
|
|
34
|
+
"format": "checkbox",
|
|
35
|
+
"title": "Dependent on true",
|
|
36
|
+
"description": "This field depends on master_field being true.",
|
|
37
|
+
"default": true,
|
|
38
|
+
"options": {
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"master_field": true
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"dependent_on_false": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"format": "password",
|
|
47
|
+
"title": "Dependent on false",
|
|
48
|
+
"description": "This field depends on dependent_on_true being false.",
|
|
49
|
+
"minLength": 1,
|
|
50
|
+
"options": {
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"dependent_on_true": false
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var editor = new JSONEditor(editorContainer, {
|
|
60
|
+
schema: schema,
|
|
61
|
+
theme: 'bootstrap4',
|
|
62
|
+
iconlib: 'fontawesome',
|
|
63
|
+
show_errors: 'always'
|
|
64
|
+
})
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
</body>
|
|
68
|
+
</html>
|
|
@@ -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
|
+
|