Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: inject.preload.js

Issue 29607555: Issue 6030 - Ensure RTCPeerConnection exists before wrapping it (Closed)
Left Patch Set: Created Nov. 14, 2017, 10:34 a.m.
Right Patch Set: Wrap WebRTC wrapping code in the if block Created Nov. 14, 2017, 11:32 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 /* 219 /*
220 * RTCPeerConnection wrapper 220 * RTCPeerConnection wrapper
221 * 221 *
222 * The webRequest API in Chrome does not yet allow the blocking of 222 * The webRequest API in Chrome does not yet allow the blocking of
223 * WebRTC connections. 223 * WebRTC connections.
224 * See https://bugs.chromium.org/p/chromium/issues/detail?id=707683 224 * See https://bugs.chromium.org/p/chromium/issues/detail?id=707683
225 */ 225 */
226 let RealRTCPeerConnection = window.RTCPeerConnection || 226 let RealRTCPeerConnection = window.RTCPeerConnection ||
227 window.webkitRTCPeerConnection; 227 window.webkitRTCPeerConnection;
228 228
229 // Firefox has the option (media.peerconnection.enabled) to disable WebRTC 229 // Firefox has the option (media.peerconnection.enabled) to disable WebRTC
Manish Jethani 2017/11/14 10:57:56 Wouldn't it be better to wrap the entire code for
Wladimir Palant 2017/11/14 11:12:49 I agree. While I'm normally not a big fan of incre
kzar 2017/11/14 11:36:35 Done.
230 // in which case RealRTCPeerConnection is undefined. Note: This logic assumes 230 // in which case RealRTCPeerConnection is undefined.
231 // that the WebRTC wrapping code comes last in the injected function! 231 if (typeof RealRTCPeerConnection != "undefined")
232 if (typeof RealRTCPeerConnection == "undefined") 232 {
233 return; 233 let closeRTCPeerConnection = Function.prototype.call.bind(
234 234 RealRTCPeerConnection.prototype.close
235 let closeRTCPeerConnection = Function.prototype.call.bind( 235 );
236 RealRTCPeerConnection.prototype.close 236 let RealArray = Array;
237 ); 237 let RealString = String;
238 let RealArray = Array; 238 let {create: createObject, defineProperty} = Object;
239 let RealString = String; 239
240 let {create: createObject, defineProperty} = Object; 240 let normalizeUrl = url =>
kzar 2017/11/14 11:36:35 This change - and several like it below - are nece
241 241 {
242 function normalizeUrl(url) 242 if (typeof url != "undefined")
243 { 243 return RealString(url);
244 if (typeof url != "undefined") 244 };
245 return RealString(url); 245
246 } 246 let safeCopyArray = (originalArray, transform) =>
247 247 {
248 function safeCopyArray(originalArray, transform) 248 if (originalArray == null || typeof originalArray != "object")
249 { 249 return originalArray;
250 if (originalArray == null || typeof originalArray != "object") 250
251 return originalArray; 251 let safeArray = RealArray(originalArray.length);
252 252 for (let i = 0; i < safeArray.length; i++)
253 let safeArray = RealArray(originalArray.length); 253 {
254 for (let i = 0; i < safeArray.length; i++) 254 defineProperty(safeArray, i, {
255 { 255 configurable: false, enumerable: false, writable: false,
256 defineProperty(safeArray, i, { 256 value: transform(originalArray[i])
257 configurable: false, enumerable: false, writable: false,
258 value: transform(originalArray[i])
259 });
260 }
261 defineProperty(safeArray, "length", {
262 configurable: false, enumerable: false, writable: false,
263 value: safeArray.length
264 });
265 return safeArray;
266 }
267
268 // It would be much easier to use the .getConfiguration method to obtain
269 // the normalized and safe configuration from the RTCPeerConnection
270 // instance. Unfortunately its not implemented as of Chrome unstable 59.
271 // See https://www.chromestatus.com/feature/5271355306016768
272 function protectConfiguration(configuration)
273 {
274 if (configuration == null || typeof configuration != "object")
275 return configuration;
276
277 let iceServers = safeCopyArray(
278 configuration.iceServers,
279 iceServer =>
280 {
281 let {url, urls} = iceServer;
282
283 // RTCPeerConnection doesn't iterate through pseudo Arrays of urls.
284 if (typeof urls != "undefined" && !(urls instanceof RealArray))
285 urls = [urls];
286
287 return createObject(iceServer, {
288 url: {
289 configurable: false, enumerable: false, writable: false,
290 value: normalizeUrl(url)
291 },
292 urls: {
293 configurable: false, enumerable: false, writable: false,
294 value: safeCopyArray(urls, normalizeUrl)
295 }
296 }); 257 });
297 } 258 }
298 ); 259 defineProperty(safeArray, "length", {
299
300 return createObject(configuration, {
301 iceServers: {
302 configurable: false, enumerable: false, writable: false, 260 configurable: false, enumerable: false, writable: false,
303 value: iceServers 261 value: safeArray.length
304 } 262 });
305 }); 263 return safeArray;
306 } 264 };
307 265
308 function checkUrl(peerconnection, url) 266 // It would be much easier to use the .getConfiguration method to obtain
309 { 267 // the normalized and safe configuration from the RTCPeerConnection
310 checkRequest("webrtc", url, blocked => 268 // instance. Unfortunately its not implemented as of Chrome unstable 59.
311 { 269 // See https://www.chromestatus.com/feature/5271355306016768
312 if (blocked) 270 let protectConfiguration = configuration =>
313 { 271 {
314 // Calling .close() throws if already closed. 272 if (configuration == null || typeof configuration != "object")
315 try 273 return configuration;
274
275 let iceServers = safeCopyArray(
276 configuration.iceServers,
277 iceServer =>
316 { 278 {
317 closeRTCPeerConnection(peerconnection); 279 let {url, urls} = iceServer;
280
281 // RTCPeerConnection doesn't iterate through pseudo Arrays of urls.
282 if (typeof urls != "undefined" && !(urls instanceof RealArray))
283 urls = [urls];
284
285 return createObject(iceServer, {
286 url: {
287 configurable: false, enumerable: false, writable: false,
288 value: normalizeUrl(url)
289 },
290 urls: {
291 configurable: false, enumerable: false, writable: false,
292 value: safeCopyArray(urls, normalizeUrl)
293 }
294 });
318 } 295 }
319 catch (e) {} 296 );
320 } 297
321 }); 298 return createObject(configuration, {
322 } 299 iceServers: {
323 300 configurable: false, enumerable: false, writable: false,
324 function checkConfiguration(peerconnection, configuration) 301 value: iceServers
325 { 302 }
326 if (configuration && configuration.iceServers) 303 });
327 { 304 };
328 for (let i = 0; i < configuration.iceServers.length; i++) 305
329 { 306 let checkUrl = (peerconnection, url) =>
330 let iceServer = configuration.iceServers[i]; 307 {
331 if (iceServer) 308 checkRequest("webrtc", url, blocked =>
309 {
310 if (blocked)
332 { 311 {
333 if (iceServer.url) 312 // Calling .close() throws if already closed.
334 checkUrl(peerconnection, iceServer.url); 313 try
335
336 if (iceServer.urls)
337 { 314 {
338 for (let j = 0; j < iceServer.urls.length; j++) 315 closeRTCPeerConnection(peerconnection);
339 checkUrl(peerconnection, iceServer.urls[j]); 316 }
317 catch (e) {}
318 }
319 });
320 };
321
322 let checkConfiguration = (peerconnection, configuration) =>
323 {
324 if (configuration && configuration.iceServers)
325 {
326 for (let i = 0; i < configuration.iceServers.length; i++)
327 {
328 let iceServer = configuration.iceServers[i];
329 if (iceServer)
330 {
331 if (iceServer.url)
332 checkUrl(peerconnection, iceServer.url);
333
334 if (iceServer.urls)
335 {
336 for (let j = 0; j < iceServer.urls.length; j++)
337 checkUrl(peerconnection, iceServer.urls[j]);
338 }
340 } 339 }
341 } 340 }
342 } 341 }
342 };
343
344 // Chrome unstable (tested with 59) has already implemented
345 // setConfiguration, so we need to wrap that if it exists too.
346 // https://www.chromestatus.com/feature/5596193748942848
347 if (RealRTCPeerConnection.prototype.setConfiguration)
348 {
349 let realSetConfiguration = Function.prototype.call.bind(
350 RealRTCPeerConnection.prototype.setConfiguration
351 );
352
353 RealRTCPeerConnection.prototype.setConfiguration = function(configuration)
354 {
355 configuration = protectConfiguration(configuration);
356
357 // Call the real method first, so that validates the configuration for
358 // us. Also we might as well since checkRequest is asynchronous anyway.
359 realSetConfiguration(this, configuration);
360 checkConfiguration(this, configuration);
361 };
343 } 362 }
344 } 363
345 364 let WrappedRTCPeerConnection = function(...args)
346 // Chrome unstable (tested with 59) has already implemented 365 {
347 // setConfiguration, so we need to wrap that if it exists too. 366 if (!(this instanceof WrappedRTCPeerConnection))
348 // https://www.chromestatus.com/feature/5596193748942848 367 return RealRTCPeerConnection();
349 if (RealRTCPeerConnection.prototype.setConfiguration) 368
350 { 369 let configuration = protectConfiguration(args[0]);
351 let realSetConfiguration = Function.prototype.call.bind( 370
352 RealRTCPeerConnection.prototype.setConfiguration 371 // Since the old webkitRTCPeerConnection constructor takes an optional
353 ); 372 // second argument we need to take care to pass that through. Necessary
354 373 // for older versions of Chrome such as 49.
355 RealRTCPeerConnection.prototype.setConfiguration = function(configuration) 374 let constraints = undefined;
356 { 375 if (args.length > 1)
357 configuration = protectConfiguration(configuration); 376 constraints = args[1];
358 377
359 // Call the real method first, so that validates the configuration for 378 let peerconnection = new RealRTCPeerConnection(configuration,
360 // us. Also we might as well since checkRequest is asynchronous anyway. 379 constraints);
361 realSetConfiguration(this, configuration); 380 checkConfiguration(peerconnection, configuration);
362 checkConfiguration(this, configuration); 381 return peerconnection;
363 }; 382 };
364 } 383
365 384 WrappedRTCPeerConnection.prototype = RealRTCPeerConnection.prototype;
366 function WrappedRTCPeerConnection(...args) 385
367 { 386 let boundWrappedRTCPeerConnection = WrappedRTCPeerConnection.bind();
368 if (!(this instanceof WrappedRTCPeerConnection)) 387 copyProperties(RealRTCPeerConnection, boundWrappedRTCPeerConnection,
369 return RealRTCPeerConnection(); 388 ["generateCertificate", "name", "prototype"]);
370 389 RealRTCPeerConnection.prototype.constructor = boundWrappedRTCPeerConnection;
371 let configuration = protectConfiguration(args[0]); 390
372 391 if ("RTCPeerConnection" in window)
373 // Since the old webkitRTCPeerConnection constructor takes an optional 392 window.RTCPeerConnection = boundWrappedRTCPeerConnection;
374 // second argument we need to take care to pass that through. Necessary 393 if ("webkitRTCPeerConnection" in window)
375 // for older versions of Chrome such as 49. 394 window.webkitRTCPeerConnection = boundWrappedRTCPeerConnection;
376 let constraints = undefined; 395 }
377 if (args.length > 1)
378 constraints = args[1];
379
380 let peerconnection = new RealRTCPeerConnection(configuration, constraints);
381 checkConfiguration(peerconnection, configuration);
382 return peerconnection;
383 }
384
385 WrappedRTCPeerConnection.prototype = RealRTCPeerConnection.prototype;
386
387 let boundWrappedRTCPeerConnection = WrappedRTCPeerConnection.bind();
388 copyProperties(RealRTCPeerConnection, boundWrappedRTCPeerConnection,
389 ["generateCertificate", "name", "prototype"]);
390 RealRTCPeerConnection.prototype.constructor = boundWrappedRTCPeerConnection;
391
392 if ("RTCPeerConnection" in window)
393 window.RTCPeerConnection = boundWrappedRTCPeerConnection;
394 if ("webkitRTCPeerConnection" in window)
395 window.webkitRTCPeerConnection = boundWrappedRTCPeerConnection;
396 } 396 }
397 397
398 if (document instanceof HTMLDocument) 398 if (document instanceof HTMLDocument)
399 { 399 {
400 let sandbox = window.frameElement && 400 let sandbox = window.frameElement &&
401 window.frameElement.getAttribute("sandbox"); 401 window.frameElement.getAttribute("sandbox");
402 402
403 if (typeof sandbox != "string" || /(^|\s)allow-scripts(\s|$)/i.test(sandbox)) 403 if (typeof sandbox != "string" || /(^|\s)allow-scripts(\s|$)/i.test(sandbox))
404 { 404 {
405 let script = document.createElement("script"); 405 let script = document.createElement("script");
406 script.type = "application/javascript"; 406 script.type = "application/javascript";
407 script.async = false; 407 script.async = false;
408 script.textContent = "(" + injected + ")('" + randomEventName + "');"; 408 script.textContent = "(" + injected + ")('" + randomEventName + "');";
409 document.documentElement.appendChild(script); 409 document.documentElement.appendChild(script);
410 document.documentElement.removeChild(script); 410 document.documentElement.removeChild(script);
411 } 411 }
412 } 412 }
LEFTRIGHT
« no previous file | no next file » | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
This is Rietveld