You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

173 lines
5.1 KiB

  1. /* global Services, Components, XPCOMUtils */
  2. 'use strict';
  3. this.EXPORTED_SYMBOLS = ['contentPolicy', 'docObserver'];
  4. Components.utils['import']('resource://gre/modules/Services.jsm');
  5. Components.utils['import']('resource://gre/modules/XPCOMUtils.jsm');
  6. const Ci = Components.interfaces;
  7. let appName;
  8. try { throw new Error; } catch (ex) {
  9. appName = ex.fileName.match(/:\/\/([^\/]+)/)[1];
  10. }
  11. let getMessager = function(win) {
  12. try {
  13. // e10s
  14. return win
  15. .QueryInterface(Ci.nsIInterfaceRequestor)
  16. .getInterface(Ci.nsIWebNavigation)
  17. .QueryInterface(Ci.nsIDocShellTreeItem)
  18. .rootTreeItem
  19. .QueryInterface(Ci.nsIInterfaceRequestor)
  20. .getInterface(Ci.nsIContentFrameMessageManager);
  21. } catch (ex) {
  22. return win
  23. .QueryInterface(Ci.nsIInterfaceRequestor)
  24. .getInterface(Ci.nsIWebNavigation)
  25. .QueryInterface(Ci.nsIDocShell)
  26. .QueryInterface(Ci.nsIInterfaceRequestor)
  27. .getInterface(Ci.nsIContentFrameMessageManager);
  28. }
  29. };
  30. let contentPolicy = {
  31. classDescription: 'ContentPolicy implementation',
  32. classID: Components.ID('{e6d173c8-8dbf-4189-a6fd-189e8acffd27}'),
  33. contractID: '@' + appName + '/content-policy;1',
  34. ACCEPT: Ci.nsIContentPolicy.ACCEPT,
  35. REJECT: Ci.nsIContentPolicy.REJECT_REQUEST,
  36. requestMessageName: appName + ':onBeforeRequest',
  37. get componentRegistrar() {
  38. return Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
  39. },
  40. get categoryManager() {
  41. return Components.classes['@mozilla.org/categorymanager;1']
  42. .getService(Ci.nsICategoryManager);
  43. },
  44. QueryInterface: XPCOMUtils.generateQI([
  45. Ci.nsIFactory,
  46. Ci.nsIContentPolicy,
  47. Ci.nsISupportsWeakReference
  48. ]),
  49. createInstance: function(outer, iid) {
  50. if (outer) {
  51. throw Components.results.NS_ERROR_NO_AGGREGATION;
  52. }
  53. return this.QueryInterface(iid);
  54. },
  55. register: function() {
  56. this.componentRegistrar.registerFactory(
  57. this.classID,
  58. this.classDescription,
  59. this.contractID,
  60. this
  61. );
  62. this.categoryManager.addCategoryEntry(
  63. 'content-policy',
  64. this.contractID,
  65. this.contractID,
  66. false,
  67. true
  68. );
  69. },
  70. unregister: function() {
  71. this.componentRegistrar.unregisterFactory(this.classID, this);
  72. this.categoryManager.deleteCategoryEntry(
  73. 'content-policy',
  74. this.contractID,
  75. false
  76. );
  77. },
  78. shouldLoad: function(type, location, origin, context) {
  79. if (!context || !/^https?$/.test(location.scheme)) {
  80. return this.ACCEPT;
  81. }
  82. let win = type === 6
  83. ? context.contentWindow
  84. : (context.ownerDocument || context).defaultView;
  85. if (!win) {
  86. return this.ACCEPT;
  87. }
  88. let result = getMessager(win).sendSyncMessage(this.requestMessageName, {
  89. url: location.spec,
  90. type: type,
  91. tabId: -1,
  92. frameId: type === 6 ? -1 : (win === win.top ? 0 : 1),
  93. parentFrameId: win === win.top ? -1 : 0
  94. })[0];
  95. return result === true ? this.REJECT : this.ACCEPT;
  96. }/*,
  97. shouldProcess: function() {
  98. return this.ACCEPT;
  99. }*/
  100. };
  101. let docObserver = {
  102. contentBaseURI: 'chrome://' + appName + '/content/js/',
  103. initContext: function(win, sandbox) {
  104. let messager = getMessager(win);
  105. if (sandbox) {
  106. win = Components.utils.Sandbox([win], {
  107. sandboxPrototype: win,
  108. wantComponents: false,
  109. wantXHRConstructor: false
  110. });
  111. win.self = win;
  112. }
  113. win.sendAsyncMessage = messager.sendAsyncMessage;
  114. win.addMessageListener = messager.ublock_addMessageListener;
  115. win.removeMessageListener = messager.ublock_removeMessageListener;
  116. return win;
  117. },
  118. register: function() {
  119. Services.obs.addObserver(this, 'document-element-inserted', false);
  120. },
  121. unregister: function() {
  122. Services.obs.removeObserver(this, 'document-element-inserted');
  123. },
  124. observe: function(doc) {
  125. let win = doc.defaultView;
  126. if (!win) {
  127. return;
  128. }
  129. if (!/^https?:$/.test(win.location.protocol)) {
  130. if (win.location.protocol === 'chrome:'
  131. && win.location.host === appName) {
  132. this.initContext(win);
  133. }
  134. return;
  135. }
  136. let lss = Services.scriptloader.loadSubScript;
  137. win = this.initContext(win, true);
  138. lss(this.contentBaseURI + 'vapi-client.js', win);
  139. lss(this.contentBaseURI + 'contentscript-start.js', win);
  140. let docReady = function(e) {
  141. this.removeEventListener(e.type, docReady, true);
  142. lss(docObserver.contentBaseURI + 'contentscript-end.js', win);
  143. };
  144. doc.addEventListener('DOMContentLoaded', docReady, true);
  145. }
  146. };
  147. contentPolicy.register();
  148. docObserver.register();