UNPKG

12.7 kBJavaScriptView Raw
1/*
2 * Copyright (C) 2016 salesforce.com, inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17"use strict";
18
19var util = require('../lib/util.js');
20var objectAssign = require('object-assign');
21
22// This structure follows the same schema of the whitelisting mechanism from SES
23// for ecma intrinsics, more details on ../lib/3rdparty/ses/whiteslit.js
24var SecureDocumentAPI = {
25 document: {
26 toString: true,
27
28 // HTMLDocument
29 location: '*',
30 fgColor: '*',
31 linkColor: '*',
32 vlinkColor: '*',
33 alinkColor: '*',
34 bgColor: '*',
35 clear: true,
36 captureEvents: true,
37 releaseEvents: true,
38
39 // Document
40 URL: '*',
41 activeElement: '*',
42 adoptNode: true,
43 anchors: '*',
44 applets: '*',
45 body: '*',
46 caretRangeFromPoint: true,
47 characterSet: '*',
48 charset: '*',
49 childElementCount: '*',
50 children: '*',
51 close: true,
52 compatMode: '*',
53 contentType: '*',
54 cookie: '*',
55 createAttribute: true,
56 createAttributeNS: true,
57 createCDATASection: true,
58 createComment: true,
59 createDocumentFragment: true,
60 createElement: true,
61 createElementNS: true,
62 createEvent: true,
63 createExpression: true,
64 createNSResolver: true,
65 createNodeIterator: true,
66 createProcessingInstruction: true,
67 createRange: true,
68 createTextNode: true,
69 createTreeWalker: true,
70 defaultView: '*',
71 designMode: '*',
72 dir: '*',
73 doctype: '*',
74 documentElement: '*',
75 documentURI: '*',
76 domain: '*',
77 elementFromPoint: true,
78 elementsFromPoint: true,
79 embeds: '*',
80 evaluate: true,
81 execCommand: true,
82 exitPointerLock: true,
83 firstElementChild: '*',
84 fonts: '*',
85 forms: '*',
86 getElementById: true,
87 getElementsByClassName: true,
88 getElementsByName: true,
89 getElementsByTagName: true,
90 getElementsByTagNameNS: true,
91 getSelection: true,
92 hasFocus: true,
93 head: '*',
94 hidden: '*',
95 images: '*',
96 implementation: '*',
97 importNode: true,
98 inputEncoding: '*',
99 lastElementChild: '*',
100 lastModified: '*',
101 links: '*',
102 onabort: true,
103 onautocomplete: true,
104 onautocompleteerror: true,
105 onbeforecopy: true,
106 onbeforecut: true,
107 onbeforepaste: true,
108 onblur: true,
109 oncancel: true,
110 oncanplay: true,
111 oncanplaythrough: true,
112 onchange: true,
113 onclick: true,
114 onclose: true,
115 oncontextmenu: true,
116 oncopy: true,
117 oncuechange: true,
118 oncut: true,
119 ondblclick: true,
120 ondrag: true,
121 ondragend: true,
122 ondragenter: true,
123 ondragleave: true,
124 ondragover: true,
125 ondragstart: true,
126 ondrop: true,
127 ondurationchange: true,
128 onemptied: true,
129 onended: true,
130 onerror: true,
131 onfocus: true,
132 oninput: true,
133 oninvalid: true,
134 onkeydown: true,
135 onkeypress: true,
136 onkeyup: true,
137 onload: true,
138 onloadeddata: true,
139 onloadedmetadata: true,
140 onloadstart: true,
141 onmousedown: true,
142 onmouseenter: true,
143 onmouseleave: true,
144 onmousemove: true,
145 onmouseout: true,
146 onmouseover: true,
147 onmouseup: true,
148 onmousewheel: true,
149 onpaste: true,
150 onpause: true,
151 onplay: true,
152 onplaying: true,
153 onpointerlockchange: true,
154 onpointerlockerror: true,
155 onprogress: true,
156 onratechange: true,
157 onreadystatechange: true,
158 onreset: true,
159 onresize: true,
160 onscroll: true,
161 onsearch: true,
162 onseeked: true,
163 onseeking: true,
164 onselect: true,
165 onselectionchange: true,
166 onselectstart: true,
167 onshow: true,
168 onstalled: true,
169 onsubmit: true,
170 onsuspend: true,
171 ontimeupdate: true,
172 ontoggle: true,
173 ontouchcancel: true,
174 ontouchend: true,
175 ontouchmove: true,
176 ontouchstart: true,
177 onvolumechange: true,
178 onwaiting: true,
179 onwebkitfullscreenchange: true,
180 onwebkitfullscreenerror: true,
181 onwheel: true,
182 open: true,
183 origin: '*',
184 plugins: '*',
185 pointerLockElement: '*',
186 preferredStylesheetSet: '*',
187 queryCommandEnabled: true,
188 queryCommandIndeterm: true,
189 queryCommandState: true,
190 queryCommandSupported: true,
191 queryCommandValue: true,
192 querySelector: true,
193 querySelectorAll: true,
194 readyState: '*',
195 referrer: '*',
196 registerElement: true,
197 rootElement: '*',
198 scripts: '*',
199 scrollingElement: '*',
200 selectedStylesheetSet: '*',
201 styleSheets: '*',
202 title: '*',
203 visibilityState: '*',
204 webkitCancelFullScreen: true,
205 webkitCurrentFullScreenElement: '*',
206 webkitExitFullscreen: true,
207 webkitFullscreenElement: '*',
208 webkitFullscreenEnabled: '*',
209 webkitHidden: '*',
210 webkitIsFullScreen: '*',
211 webkitVisibilityState: '*',
212 write: true,
213 writeln: true,
214 xmlEncoding: '*',
215 xmlStandalone: '*',
216 xmlVersion: '*'
217 }
218};
219
220objectAssign(SecureDocumentAPI.document, require('../lib/dom/element.js'));
221objectAssign(SecureDocumentAPI.document, require('../lib/dom/global-event-handlers.js'));
222objectAssign(SecureDocumentAPI.document, require('../lib/dom/event-target-methods.js'));
223objectAssign(SecureDocumentAPI.document, require('../lib/dom/node.js'));
224
225module.exports = function(context) {
226 var globalScope;
227
228 return {
229
230 "Program" : function() {
231 globalScope = context.getScope();
232 },
233
234 MemberExpression: function(node) {
235 if (node.parent.type === "MemberExpression") {
236 // ignoring intermediate member expressions
237 return;
238 }
239 var currentScope = context.getScope();
240 var ns = util.buildMemberExpressionNamespace(currentScope, globalScope, node);
241 if (ns.length > 0) {
242 var rootIdentifier = ns[0];
243 if (rootIdentifier.type !== "Identifier" || rootIdentifier.name !== "document" || util.isShadowed(currentScope, globalScope, rootIdentifier)) {
244 return;
245 }
246 var api = SecureDocumentAPI;
247 for (var i = 0; i < ns.length; i++) {
248 var identifier = ns[i];
249 if (identifier.type !== 'Identifier') {
250 context.report(node, "Invalid SecureDocument API, use dot notation instead");
251 return;
252 }
253 var token = identifier.name;
254 var nextIdentifier = ns[i + 1];
255 if (typeof api !== "object") {
256 context.report(node, "Invalid SecureDocument API");
257 return;
258 }
259 if (!api.hasOwnProperty(token)) {
260 context.report(node, "Invalid SecureDocument API");
261 return;
262 }
263 if (api[token] === '*') {
264 // anything from this point on is good
265 return;
266 }
267 if (typeof (api[token]) === 'object' && Object.keys(api[token]).length === 0) {
268 // nothing else to inspect
269 return;
270 }
271 if (api[token] === true && !nextIdentifier) {
272 // function call
273 return;
274 }
275 if (api[token] === true && nextIdentifier && nextIdentifier.type === 'Identifier' && (nextIdentifier.name === 'apply' || nextIdentifier.name === 'call')) {
276 // function call with .apply() or .call() are still valid
277 return;
278 }
279 if (api[token] === false && nextIdentifier === undefined) {
280 return;
281 }
282 api = api[token];
283 }
284 }
285 }
286 };
287
288};
289
290module.exports.schema = [];