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.

171 lines
5.0 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 (type === 6 || !context || !/^https?$/.test(location.scheme)) {
  80. return this.ACCEPT;
  81. }
  82. let win = (context.ownerDocument || context).defaultView;
  83. if (!win) {
  84. return this.ACCEPT;
  85. }
  86. let result = getMessager(win).sendSyncMessage(this.requestMessageName, {
  87. url: location.spec,
  88. type: type,
  89. tabId: -1,
  90. frameId: win === win.top ? 0 : 1,
  91. parentFrameId: win === win.top ? -1 : 0
  92. })[0];
  93. return result === true ? this.REJECT : this.ACCEPT;
  94. }/*,
  95. shouldProcess: function() {
  96. return this.ACCEPT;
  97. }*/
  98. };
  99. let docObserver = {
  100. contentBaseURI: 'chrome://' + appName + '/content/js/',
  101. initContext: function(win, sandbox) {
  102. let messager = getMessager(win);
  103. if (sandbox) {
  104. win = Components.utils.Sandbox([win], {
  105. sandboxPrototype: win,
  106. wantComponents: false,
  107. wantXHRConstructor: false
  108. });
  109. win.self = win;
  110. }
  111. win.sendAsyncMessage = messager.sendAsyncMessage;
  112. win.addMessageListener = messager.ublock_addMessageListener;
  113. win.removeMessageListener = messager.ublock_removeMessageListener;
  114. return win;
  115. },
  116. register: function() {
  117. Services.obs.addObserver(this, 'document-element-inserted', false);
  118. },
  119. unregister: function() {
  120. Services.obs.removeObserver(this, 'document-element-inserted');
  121. },
  122. observe: function(doc) {
  123. let win = doc.defaultView;
  124. if (!win) {
  125. return;
  126. }
  127. if (!/^https?:$/.test(win.location.protocol)) {
  128. if (win.location.protocol === 'chrome:'
  129. && win.location.host === appName) {
  130. this.initContext(win);
  131. }
  132. return;
  133. }
  134. let lss = Services.scriptloader.loadSubScript;
  135. win = this.initContext(win, true);
  136. lss(this.contentBaseURI + 'vapi-client.js', win);
  137. lss(this.contentBaseURI + 'contentscript-start.js', win);
  138. let docReady = function(e) {
  139. this.removeEventListener(e.type, docReady, true);
  140. lss(docObserver.contentBaseURI + 'contentscript-end.js', win);
  141. };
  142. doc.addEventListener('DOMContentLoaded', docReady, true);
  143. }
  144. };
  145. contentPolicy.register();
  146. docObserver.register();