|
5 | 5 |
|
6 | 6 | const VERSION = 'phase2-oxc-abi-2'; |
7 | 7 | const BLOCK_CODE = "throw new DOMException('Blocked by ZeroProxy rewrite policy','NotSupportedError');"; |
8 | | - const GLOBALS = new Set(['window', 'self', 'globalThis', 'location', 'document', 'history', 'top', 'parent', 'opener', 'frames', 'eval', 'Function', 'AsyncFunction', 'GeneratorFunction', 'AsyncGeneratorFunction']); |
| 8 | + const GLOBALS = new Set(['window', 'self', 'globalThis', 'location', 'document', 'history', 'top', 'parent', 'opener', 'frames', 'WebSocket', 'eval', 'Function', 'AsyncFunction', 'GeneratorFunction', 'AsyncGeneratorFunction']); |
9 | 9 | const MEMBER_HELPER_PROPS = new Set(['location', 'defaultView', 'contentWindow', 'contentDocument', 'top', 'parent', 'opener', 'frames', 'constructor']); |
10 | 10 | const CALL_HELPER_PROPS = new Set(['assign', 'replace', 'open', 'get', 'getOwnPropertyDescriptor', 'defineProperty']); |
11 | 11 | let parser = null; |
|
159 | 159 | renderedCache.set(node, out); |
160 | 160 | return out; |
161 | 161 | } |
| 162 | + function exprCode(node) { |
| 163 | + if (!node) return ''; |
| 164 | + if (node.type === 'Identifier' || node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression' || node.type === 'ChainExpression') return render(node); |
| 165 | + if (node.type === 'BinaryExpression' || node.type === 'LogicalExpression') return exprCode(node.left) + source.slice(node.left.end, node.right.start) + exprCode(node.right); |
| 166 | + if (node.type === 'ConditionalExpression') return exprCode(node.test) + source.slice(node.test.end, node.consequent.start) + exprCode(node.consequent) + source.slice(node.consequent.end, node.alternate.start) + exprCode(node.alternate); |
| 167 | + if (node.type === 'UnaryExpression' || node.type === 'UpdateExpression') { |
| 168 | + if (node.prefix) return source.slice(node.start, node.argument.start) + exprCode(node.argument); |
| 169 | + return exprCode(node.argument) + source.slice(node.argument.end, node.end); |
| 170 | + } |
| 171 | + return src(node); |
| 172 | + } |
| 173 | + |
| 174 | + function isVirtualWindowExpr(node) { |
| 175 | + if (!node) return false; |
| 176 | + if (node.type === 'ChainExpression') return isVirtualWindowExpr(node.expression); |
| 177 | + if (node.type === 'Identifier') return isGlobalIdentifier(node) && (node.name === 'window' || node.name === 'self' || node.name === 'globalThis' || node.name === 'top' || node.name === 'parent' || node.name === 'opener' || node.name === 'frames'); |
| 178 | + if (node.type !== 'MemberExpression' && node.type !== 'OptionalMemberExpression') return false; |
| 179 | + const name = propName(node.property, node.computed); |
| 180 | + if ((name === 'defaultView' || name === 'contentWindow') && MEMBER_HELPER_PROPS.has(name)) return true; |
| 181 | + return (name === 'window' || name === 'self' || name === 'globalThis' || name === 'top' || name === 'parent' || name === 'opener' || name === 'frames') && isVirtualWindowExpr(node.object); |
| 182 | + } |
| 183 | + |
| 184 | + function isVirtualLocationExpr(node) { |
| 185 | + if (!node) return false; |
| 186 | + if (node.type === 'ChainExpression') return isVirtualLocationExpr(node.expression); |
| 187 | + if (node.type === 'Identifier') return isGlobalIdentifier(node) && node.name === 'location'; |
| 188 | + if (node.type !== 'MemberExpression' && node.type !== 'OptionalMemberExpression') return false; |
| 189 | + const name = propName(node.property, node.computed); |
| 190 | + return name === 'location' && isVirtualWindowExpr(node.object) || node.computed && isVirtualWindowExpr(node.object); |
| 191 | + } |
| 192 | + |
| 193 | + function assignmentSetTarget(node) { |
| 194 | + if (!node) return null; |
| 195 | + if (node.type === 'ChainExpression') return assignmentSetTarget(node.expression); |
| 196 | + if (node.type === 'Identifier' && isGlobalIdentifier(node) && (node.name === 'location' || node.name === 'window')) return { base: 'globalThis', prop: JSON.stringify(node.name) }; |
| 197 | + if (node.type !== 'MemberExpression' && node.type !== 'OptionalMemberExpression') return null; |
| 198 | + const name = propName(node.property, node.computed); |
| 199 | + if (name === 'location' && isVirtualWindowExpr(node.object)) return { base: render(node.object), prop: propCode(node.property, node.computed) }; |
| 200 | + if (name === 'href' && isVirtualLocationExpr(node.object)) return { base: render(node.object), prop: propCode(node.property, node.computed) }; |
| 201 | + if (node.computed && (isVirtualWindowExpr(node.object) || isVirtualLocationExpr(node.object))) return { base: render(node.object), prop: propCode(node.property, node.computed) }; |
| 202 | + return null; |
| 203 | + } |
| 204 | + function argList(args) { |
| 205 | + return (args || []).map(exprCode).join(','); |
| 206 | + } |
| 207 | + |
| 208 | + function constructTarget(node) { |
| 209 | + if (!node) return ''; |
| 210 | + if (node.type === 'ChainExpression') return constructTarget(node.expression); |
| 211 | + if (node.type === 'Identifier' && isGlobalIdentifier(node)) return render(node); |
| 212 | + if ((node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression') && isVirtualWindowExpr(node.object)) return render(node); |
| 213 | + return ''; |
| 214 | + } |
| 215 | + |
162 | 216 |
|
163 | 217 | function enterNode(node, parent, key) { |
164 | 218 | if (!node || typeof node.type !== 'string') return false; |
|
198 | 252 | diagnostics.push({ level: 'warning', message: 'blocked compound assignment touching virtualized browser state', start: node.start, end: node.end }); |
199 | 253 | return true; |
200 | 254 | } |
201 | | - if (node.left && node.left.type === 'Identifier' && isGlobalIdentifier(node.left) && (node.left.name === 'location' || node.left.name === 'window')) { |
202 | | - addReplacement(node, '__zp_set(globalThis,' + JSON.stringify(node.left.name) + ',' + src(node.right) + ')', 100); |
203 | | - return true; |
| 255 | + if (node.operator === '=') { |
| 256 | + const target = assignmentSetTarget(node.left); |
| 257 | + if (target) { |
| 258 | + addReplacement(node, '__zp_set(' + target.base + ',' + target.prop + ',' + exprCode(node.right) + ')', 100); |
| 259 | + return true; |
| 260 | + } |
204 | 261 | } |
205 | 262 | break; |
206 | 263 | } |
|
215 | 272 | case 'CallExpression': |
216 | 273 | case 'NewExpression': { |
217 | 274 | const callee = node.callee; |
| 275 | + const args = argList(node.arguments); |
218 | 276 | if (callee && (callee.type === 'MemberExpression' || callee.type === 'OptionalMemberExpression')) { |
219 | 277 | const name = propName(callee.property, callee.computed); |
220 | 278 | if (CALL_HELPER_PROPS.has(name) || MEMBER_HELPER_PROPS.has(name)) { |
221 | | - const args = (node.arguments || []).map(a => src(a)).join(','); |
222 | 279 | const call = '__zp_call(' + render(callee.object) + ',' + propCode(callee.property, callee.computed) + ',[' + args + '])'; |
223 | 280 | addReplacement(node, node.type === 'NewExpression' ? BLOCK_CODE : call, 90); |
224 | 281 | if (node.type === 'NewExpression') diagnostics.push({ level: 'warning', message: 'blocked construction through virtualized browser state', start: node.start, end: node.end }); |
225 | 282 | return true; |
226 | 283 | } |
227 | 284 | } |
| 285 | + if (node.type === 'NewExpression') { |
| 286 | + const ctor = constructTarget(callee); |
| 287 | + if (ctor) { |
| 288 | + addReplacement(node, '__zp_construct(' + ctor + ',[' + args + '])', 90); |
| 289 | + return true; |
| 290 | + } |
| 291 | + } |
228 | 292 | break; |
229 | 293 | } |
230 | 294 | case 'MemberExpression': |
|
249 | 313 |
|
250 | 314 | function containsDangerousLHS(node) { |
251 | 315 | if (!node) return false; |
252 | | - if (node.type === 'Identifier') return isGlobalIdentifier(node) && (node.name === 'location' || node.name === 'window'); |
253 | | - if (node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression') return MEMBER_HELPER_PROPS.has(propName(node.property, node.computed)) || containsDangerousLHS(node.object); |
| 316 | + if (assignmentSetTarget(node)) return true; |
| 317 | + if (node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression') return containsDangerousLHS(node.object); |
254 | 318 | return false; |
255 | 319 | } |
256 | 320 |
|
|
0 commit comments