WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 1b28b50

Browse files
committed
wip
1 parent 5e53032 commit 1b28b50

File tree

2 files changed

+98
-56
lines changed

2 files changed

+98
-56
lines changed

packages/csp/src/parser.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,8 @@ class Evaluator {
653653
if (node.name in scope) {
654654
const value = scope[node.name];
655655

656+
this.checkForDangerousValues(value)
657+
656658
// If it's a function and we're accessing it directly (not calling it),
657659
// bind it to scope to preserve 'this' context for later calls
658660
if (typeof value === 'function') {
@@ -710,12 +712,9 @@ class Evaluator {
710712
prop = node.callee.property.name
711713
}
712714

713-
let func;
714-
if (this.checkForDangerousKeywords(prop)) {
715-
func = undefined
716-
} else {
717-
func = obj[prop];
718-
}
715+
this.checkForDangerousKeywords(prop)
716+
717+
let func = obj[prop];
719718

720719
if (typeof func !== 'function') {
721720
throw new Error('Value is not a function');
@@ -831,7 +830,15 @@ class Evaluator {
831830
: this.evaluate({ node: node.alternate, scope, context, forceBindingRootScopeToFunctions });
832831

833832
case 'AssignmentExpression':
834-
throw new Error('Assignments are prohibited');
833+
const value = this.evaluate({ node: node.right, scope, context, forceBindingRootScopeToFunctions });
834+
835+
if (node.left.type === 'Identifier') {
836+
scope[node.left.name] = value;
837+
return value;
838+
} else if (node.left.type === 'MemberExpression') {
839+
throw new Error('Object assignments are prohibited')
840+
}
841+
throw new Error('Invalid assignment target');
835842

836843
case 'ArrayExpression':
837844
return node.elements.map(el => this.evaluate({ node: el, scope, context, forceBindingRootScopeToFunctions }));
Lines changed: 84 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,200 @@
1-
import { should } from 'chai'
2-
import { haveText, html, test } from '../../utils'
1+
import { haveText, html, notContain, notExist, notHaveAttribute, test } from '../../utils'
32

43
test.csp('supports regular syntax',
54
[html`
65
<div x-data="{ value: 0, user: { name: 'John' } }">
76
<span x-text="value"></span>
87
<h1 x-text="user.name"></h1>
9-
<button @click="value++">Increment</button>
8+
<button @click="value = 2">Increment</button>
109
</div>
1110
`],
1211
({ get }) => {
1312
get('h1').should(haveText('John'))
1413
get('button').click()
15-
get('span').should(haveText('1'))
14+
get('span').should(haveText('2'))
1615
}
1716
)
1817

1918
test.csp('throws when accessing a global',
2019
[html`
21-
<button x-on:click="document"></button>
20+
<button x-data x-on:click="document.write('evil')"></button>
2221
`],
2322
(cy) => {
24-
cy.on('uncaught:exception', ({message}) => should(message).contain('Undefined variable: document'))
23+
cy.on('uncaught:exception', ({message}) => message.includes('Undefined variable: document') ? false : true)
2524
cy.get('button').click()
25+
cy.get('body').should(notContain('evil'))
2626
}
2727
)
2828

2929
test.csp('throws when accessing a global via property',
3030
[html`
31-
<button x-on:click="$el.ownerDocument"></button>
31+
<button x-data x-on:click="$el.ownerDocument.write('evil')"></button>
3232
`],
3333
(cy) => {
34-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing global variables is prohibited'))
34+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing global variables is prohibited') ? false : true)
3535
cy.get('button').click()
36-
},
36+
cy.get('body').should(notContain('evil'))
37+
}
3738
)
3839

39-
test.csp('throws when accessing a global via property',
40+
test.csp('throws when accessing a global via computed property',
4041
[html`
41-
<button x-on:click="$el['ownerDocument']"></button>
42+
<button x-data x-on:click="$el['ownerDocument'].write('evil')"></button>
4243
`],
4344
(cy) => {
44-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing global variables is prohibited'))
45+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing global variables is prohibited') ? false : true)
4546
cy.get('button').click()
47+
cy.get('body').should(notContain('evil'))
4648
},
4749
)
4850

49-
test.csp('throws when accessing a global via property',
51+
test.csp('throws when accessing a global via function',
5052
[html`
51-
<button x-on:click="$el.getRootNode()"></button>
53+
<button x-data x-on:click="$el.getRootNode().write('evil')"></button>
5254
`],
5355
(cy) => {
54-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing global variables is prohibited'))
56+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing global variables is prohibited') ? false : true)
5557
cy.get('button').click()
58+
cy.get('body').should(notContain('evil'))
5659
},
5760
)
5861

59-
test.csp('throws when parsing an assignment',
62+
test.csp('throws when parsing a property assignment',
6063
[html`
61-
<button x-on:click="value = 0"></button>
64+
<button x-data x-on:click="$el.innerHTML = 'evil'"></button>
6265
`],
6366
(cy) => {
64-
cy.on('uncaught:exception', ({message}) => should(message).contain('Assignments are prohibited'))
67+
cy.on('uncaught:exception', ({message}) => message.includes('Object assignments are prohibited') ? false : true)
6568
cy.get('button').click()
69+
cy.get('button').should(notContain('evil'))
6670
},
6771
)
6872

69-
test.csp('throws when parsing an assignment',
73+
test.csp('throws when accessing blacklisted properties',
7074
[html`
71-
<button x-on:click="$el.insertAdjacentHTML('beforeend', '<iframe></iframe>')"></button>
75+
<button x-data x-on:click="$el.insertAdjacentHTML('beforeend', '<div id=evil></div>')"></button>
7276
`],
7377
(cy) => {
74-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing "insertAdjacentHTML" is prohibited'))
78+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing "insertAdjacentHTML" is prohibited') ? false : true)
7579
cy.get('button').click()
80+
cy.get('#evil').should(notExist())
7681
},
7782
)
7883

7984
test.csp('throws when accessing an iframe',
8085
[html`
81-
<button x-on:click="$refs.foo"></button>
82-
<iframe x-ref="foo"></iframe>
86+
<div x-data>
87+
<button x-on:click="$refs.foo.setAttribute('srcdoc', 'dangerous')"></button>
88+
<iframe x-ref="foo"></iframe>
89+
</div>
8390
`],
8491
(cy) => {
85-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing iframes and scripts is prohibited'))
92+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing iframes and scripts is prohibited') ? false : true)
8693
cy.get('button').click()
94+
cy.get('iframe').should(notHaveAttribute('srcdoc', 'dangerous'))
8795
},
8896
)
8997

9098
test.csp('throws when accessing an iframe via computed property',
9199
[html`
92-
<button x-on:click="$refs['foo']"></button>
93-
<iframe x-ref="foo"></iframe>
100+
<div x-data>
101+
<button x-on:click="$refs['foo'].setAttribute('srcdoc', 'dangerous')"></button>
102+
<iframe x-ref="foo"></iframe>
103+
</div>
94104
`],
95105
(cy) => {
96-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing iframes and scripts is prohibited'))
106+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing iframes and scripts is prohibited') ? false : true)
97107
cy.get('button').click()
108+
cy.get('iframe').should(notHaveAttribute('srcdoc', 'dangerous'))
98109
},
99110
)
100111

101112
test.csp('throws when accessing an iframe via function',
102113
[html`
103-
<button x-on:click="$refs.parentElement.querySelector('iframe')"></button>
104-
<iframe x-ref="foo"></iframe>
114+
<div x-data>
115+
<button x-on:click="$el.parentElement.querySelector('iframe').setAttribute('srcdoc', 'dangerous')"></button>
116+
<iframe x-ref="foo"></iframe>
117+
</div>
105118
`],
106119
(cy) => {
107-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing iframes and scripts is prohibited'))
120+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing iframes and scripts is prohibited') ? false : true)
108121
cy.get('button').click()
122+
cy.get('iframe').should(notHaveAttribute('srcdoc', 'dangerous'))
109123
},
110124
)
111125

112126
test.csp('throws when evaluating on an iframe',
113127
[html`
114-
<iframe x-on:click="$el.setAttribute('srcdoc', '')"></iframe>
128+
<div x-data="{ show: false }">
129+
<button x-data x-on:click="show = true"></button>
130+
<template x-if="show">
131+
<iframe x-init="$el.setAttribute('srcdoc', 'dangerous')"></iframe>
132+
</template>
133+
</div>
115134
`],
116135
(cy) => {
117-
cy.on('uncaught:exception', ({message}) => should(message).contain('Evaluating expressions on an iframe is prohibited'))
118-
cy.get('iframe').click()
136+
cy.on('uncaught:exception', ({message}) => message.includes('Evaluating expressions on an iframe is prohibited') ? false : true)
137+
cy.get('button').click()
138+
cy.get('iframe').should(notHaveAttribute('srcdoc', 'dangerous'))
119139
},
120140
)
121141

122142
test.csp('throws when accessing a script',
123143
[html`
124-
<button x-on:click="$refs.foo"></button>
125-
<script x-ref="foo"></script>
144+
<div x-data>
145+
<button x-on:click="$refs.foo.setAttribute('src', 'evil')"></button>
146+
<script id="script" x-ref="foo"></script>
147+
</div>
126148
`],
127149
(cy) => {
128-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing iframes and scripts is prohibited'))
150+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing iframes and scripts is prohibited') ? false : true)
129151
cy.get('button').click()
152+
cy.get('#script').should(notHaveAttribute('src', 'evil'))
130153
},
131154
)
132155

133156
test.csp('throws when accessing a script via computed property',
134157
[html`
135-
<button x-on:click="$refs['foo']"></button>
136-
<script x-ref="foo"></script>
158+
<div x-data>
159+
<button x-on:click="$refs['foo'].setAttribute('src', 'evil')"></button>
160+
<script id="script" x-ref="foo"></script>
161+
</div>
137162
`],
138163
(cy) => {
139-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing iframes and scripts is prohibited'))
164+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing iframes and scripts is prohibited') ? false : true)
140165
cy.get('button').click()
166+
cy.get('#script').should(notHaveAttribute('src', 'evil'))
141167
},
142168
)
143169

144170
test.csp('throws when accessing a script via function',
145171
[html`
146-
<button x-on:click="$refs.parentElement.querySelector('script')"></button>
147-
<script x-ref="foo"></script>
172+
<div x-data>
173+
<button x-on:click="$el.parentElement.querySelector('script').setAttribute('src', 'evil')"></button>
174+
<script id="script" x-ref="foo"></script>
175+
</div>
148176
`],
149177
(cy) => {
150-
cy.on('uncaught:exception', ({message}) => should(message).contain('Accessing iframes and scripts is prohibited'))
178+
cy.on('uncaught:exception', ({message}) => message.includes('Accessing iframes and scripts is prohibited') ? false : true)
151179
cy.get('button').click()
180+
cy.get('#script').should(notHaveAttribute('src', 'evil'))
152181
},
153182
)
154183

155184
test.csp('throws when evaluating on a script',
156185
[html`
157-
<button x-on:click="$dispatch('script')"></button>
158-
<script x-on:script="$el.setAttribute('srcdoc', '')"></script>
159-
`],
186+
<div x-data="{ show: false }">
187+
<button x-on:click="show = true"></button>
188+
<template x-if="show">
189+
<script id="script" x-init="$el.setAttribute('src', 'evil')"></script>
190+
</template>
191+
</div>
192+
`,
193+
],
160194
(cy) => {
161-
cy.on('uncaught:exception', ({message}) => should(message).contain('Evaluating expressions on a script is prohibited'))
195+
cy.on('uncaught:exception', ({message}) => message.includes('Evaluating expressions on a script is prohibited') ? false : true)
162196
cy.get('button').click()
197+
cy.get('#script').should(notHaveAttribute('src', 'evil'))
163198
},
164199
)
165200

@@ -168,12 +203,12 @@ test.csp('throws when using x-html directive',
168203
<div x-data="{ show: false }">
169204
<button x-on:click="show = true"></button>
170205
<template x-if="show">
171-
<div x-html=""></div>
206+
<div x-html="evil"></div>
172207
</template>
173208
</div>
174209
`],
175210
(cy) => {
176-
// cy.on('uncaught:exception', ({message}) => should(message).contain('Using the x-html directive is prohibited'))
177-
cy.get('button').click()
211+
cy.on('uncaught:exception', ({message}) => message.includes('Using the x-html directive is prohibited') ? false : true)
212+
cy.get('body').should(notContain('evil'))
178213
},
179214
)

0 commit comments

Comments
 (0)