11 https_everywhere_blacklist
= {};
14 const CI
= Components
.interfaces
;
15 const CC
= Components
.classes
;
16 const CU
= Components
.utils
;
17 const CR
= Components
.results
;
19 const CP_SHOULDPROCESS
= 4;
21 const SERVICE_CTRID
= "@eff.org/https-everywhere;1";
22 const SERVICE_ID
=Components
.ID("{32c165b4-fe5e-4964-9250-603c410631b4}");
24 const IOS
= CC
["@mozilla.org/network/io-service;1"].getService(CI
.nsIIOService
);
25 const OS
= CC
['@mozilla.org/observer-service;1'].getService(CI
.nsIObserverService
);
26 const LOADER
= CC
["@mozilla.org/moz/jssubscript-loader;1"].getService(CI
.mozIJSSubScriptLoader
);
29 // NoScript uses this blob to include js constructs that stored in the chrome/
30 // directory, but are not attached to the Firefox UI (normally, js located
31 // there is attached to an Overlay and therefore is part of the UI).
33 // Reasons for this: things in components/ directory cannot be split into
34 // separate files; things in chrome/ can be
36 const INCLUDE = function(name
) {
37 if (arguments
.length
> 1)
38 for (var j
= 0, len
= arguments
.length
; j
< len
; j
++)
39 arguments
.callee(arguments
[j
]);
40 else if (!_INCLUDED
[name
]) {
42 LOADER
.loadSubScript("chrome://https-everywhere/content/code/"
44 _INCLUDED
[name
] = true;
46 dump("INCLUDE " + name
+ ": " + e
+ "\n");
51 const WP_STATE_START
= CI
.nsIWebProgressListener
.STATE_START
;
52 const WP_STATE_STOP
= CI
.nsIWebProgressListener
.STATE_STOP
;
53 const WP_STATE_DOC
= CI
.nsIWebProgressListener
.STATE_IS_DOCUMENT
;
54 const WP_STATE_START_DOC
= WP_STATE_START
| WP_STATE_DOC
;
55 const WP_STATE_RESTORING
= CI
.nsIWebProgressListener
.STATE_RESTORING
;
57 const LF_VALIDATE_ALWAYS
= CI
.nsIRequest
.VALIDATE_ALWAYS
;
58 const LF_LOAD_BYPASS_ALL_CACHES
= CI
.nsIRequest
.LOAD_BYPASS_CACHE
| CI
.nsICachingChannel
.LOAD_BYPASS_LOCAL_CACHE
;
61 const NS_BINDING_ABORTED
= 0x804b0002;
62 const NS_BINDING_REDIRECTED
= 0x804b0003;
63 const NS_ERROR_UNKNOWN_HOST
= 0x804b001e;
64 const NS_ERROR_REDIRECT_LOOP
= 0x804b001f;
65 const NS_ERROR_CONNECTION_REFUSED
= 0x804b000e;
66 const NS_ERROR_NOT_AVAILABLE
= 0x804b0111;
68 const LOG_CONTENT_BLOCK
= 1;
69 const LOG_CONTENT_CALL
= 2;
70 const LOG_CONTENT_INTERCEPT
= 4;
71 const LOG_CHROME_WIN
= 8;
72 const LOG_XSS_FILTER
= 16;
73 const LOG_INJECTION_CHECK
= 32;
76 const LOG_LEAKS
= 1024;
77 const LOG_SNIFF
= 2048;
78 const LOG_CLEARCLICK
= 4096;
81 const HTML_NS
= "http://www.w3.org/1999/xhtml";
83 const WHERE_UNTRUSTED
= 1;
84 const WHERE_TRUSTED
= 2;
89 const EARLY_VERSION_CHECK
= !("nsISessionStore" in CI
&& typeof(/ /) === "object");
94 function xpcom_generateQI(iids
) {
96 for each (var iid
in iids
) {
97 checks
.push("CI." + iid
.name
+ ".equals(iid)");
99 var src
= checks
.length
100 ? "if (" + checks
.join(" || ") + ") return this;\n"
102 return new Function("iid", src
+ "throw Components.results.NS_ERROR_NO_INTERFACE;");
105 function xpcom_checkInterfaces(iid
,iids
,ex
) {
106 for (var j
= iids
.length
; j
-- >0;) {
107 if (iid
.equals(iids
[j
])) return true;
112 INCLUDE('IOUtil', 'HTTPSRules', 'HTTPS', 'Thread');
114 function https_everywhereLog(level
, str
) {
117 var econsole
= Components
.classes
["@mozilla.org/consoleservice;1"]
118 .getService(Components
.interfaces
.nsIConsoleService
);
119 econsole
.logStringMessage("HTTPS Everywhere: " +str
);
123 function HTTPSEverywhere() {
124 // Hacks to set up logging in each component
125 HTTPS
.log
= https_everywhereLog
;
126 HTTPSRules
.log
= https_everywhereLog
;
127 RuleWriter
.log
= https_everywhereLog
;
128 this.log
= https_everywhereLog
;
129 this.wrappedJSObject
= this;
130 this.https_rules
= HTTPSRules
;
132 // We need to use observers instead of categories for FF3.0 for these:
133 // https://developer.mozilla.org/en/Observer_Notifications
134 // https://developer.mozilla.org/en/nsIObserverService.
135 // https://developer.mozilla.org/en/nsIObserver
136 var obsService
= CC
["@mozilla.org/observer-service;1"]
137 .getService(Components
.interfaces
.nsIObserverService
);
138 obsService
.addObserver(this, "profile-before-change", false);
139 obsService
.addObserver(this, "profile-after-change", false);
143 // This defines for Mozilla what stuff HTTPSEverywhere will implement.
145 // We need to use both ContentPolicy and Observer, because there are some
146 // things, such as Favicons, who don't get caught by ContentPolicy; we don't
147 // yet know why we don't just use the observer :/
149 // ChannelEventSink seems to be necessary in order to handle redirects (eg
150 // HTTP redirects) correctly.
152 HTTPSEverywhere
.prototype = {
153 QueryInterface: function(iid
) {
154 if (!iid
.equals(CI
.nsIObserver
)
155 && !iid
.equals(CI
.nsISupports
)
156 && !iid
.equals(CI
.nsIContentPolicy
)
157 && !iid
.equals(CI
.nsISupportsWeakReference
)
158 && !iid
.equals(CI
.nsIWebProgressListener
)
159 && !iid
.equals(CI
.nsIChannelEventSink
)) {
160 Components
.returnCode
= CR
.NS_ERROR_NO_INTERFACE
;
161 this.log(INFO
,"Bad QI: "+iid
);
164 this.log(VERB
,"Good QI: "+iid
);
167 wrappedJSObject
: null, // Initialized by constructor
169 getWeakReference: function () {
170 return Components
.utils
.getWeakReference(this);
173 // This function is registered solely to detect favicon loads by virtue
174 // of their failure to pass through this function.
175 onStateChange: function(wp
, req
, stateFlags
, status
) {
176 if (stateFlags
& WP_STATE_START
) {
177 if (req
instanceof CI
.nsIChannel
) {
178 if (req
instanceof CI
.nsIHttpChannel
) {
179 PolicyState
.attach(req
);
185 observe: function(subject
, topic
, data
) {
186 // Top level glue for the nsIObserver API
187 var channel
= subject
;
188 this.log(VERB
,"Got observer topic: "+topic
);
190 if (topic
== "http-on-modify-request") {
191 if (!(channel
instanceof CI
.nsIHttpChannel
)) return;
192 this.log(DBUG
,"Got http-on-modify-request: "+channel
.URI
.spec
);
193 if (channel
.URI
.spec
in https_everywhere_blacklist
) {
194 this.log(DBUG
, "Avoiding blacklisted " + channel
.URI
.spec
);
197 HTTPS
.forceChannel(channel
);
198 } else if (topic
== "app-startup") {
199 this.log(DBUG
,"Got app-startup");
200 OS
.addObserver(this, "http-on-modify-request", false);
201 var dls
= CC
['@mozilla.org/docloaderservice;1']
202 .getService(CI
.nsIWebProgress
);
203 dls
.addProgressListener(this, CI
.nsIWebProgress
.NOTIFY_STATE_REQUEST
);
204 this.log(INFO
,"ChannelReplacement.supported = "+ChannelReplacement
.supported
);
205 } else if (topic
== "profile-before-change") {
206 this.log(INFO
, "Got profile-before-change");
207 var catman
= Components
.classes
["@mozilla.org/categorymanager;1"]
208 .getService(Components
.interfaces
.nsICategoryManager
);
209 catman
.deleteCategoryEntry("net-channel-event-sinks", SERVICE_CTRID
, true);
210 Thread
.hostRunning
= false;
211 } else if (topic
== "profile-after-change") {
212 // This is currently separate from app-startup for hackish historical
213 // reasons; not sure if that's necessary.
214 this.log(DBUG
, "Got profile-after-change");
216 Thread
.hostRunning
= true;
217 var catman
= Components
.classes
["@mozilla.org/categorymanager;1"]
218 .getService(Components
.interfaces
.nsICategoryManager
);
219 // hook on redirections (non persistent, otherwise crashes on 1.8.x)
220 catman
.addCategoryEntry("net-channel-event-sinks", SERVICE_CTRID
,
221 SERVICE_CTRID
, false, true);
226 // nsIChannelEventSink implementation
227 onChannelRedirect: function(oldChannel
, newChannel
, flags
) {
228 const uri
= newChannel
.URI
;
229 this.log(DBUG
,"Got onChannelRedirect.");
230 if (!(newChannel
instanceof CI
.nsIHttpChannel
)) {
231 this.log(DBUG
, newChannel
+ " is not an instance of nsIHttpChannel");
235 HTTPS
.forceChannel(newChannel
);
237 // if (HTTPS.forceURI(uri.clone())) {
238 // if (!HTTPS.replaceChannel(newChannel)) {
239 // // Failed, try to put things back...
240 // this.log(DBUG, "reverting URI, " + oldChannel.URI.spec);
242 // oldChannel.URI.scheme = "http";
243 // newChannel.URI.scheme = "http";
245 // this.log(WARN, "uri windback error " + e);
251 // These implement the nsIContentPolicy API; they allow both yes/no answers
252 // to "should this load?", but also allow us to change the thing.
254 shouldLoad: function(aContentType
, aContentLocation
, aRequestOrigin
, aContext
, aMimeTypeGuess
, aInternalCall
) {
255 if (aContentType
== 11)
256 this.log(DBUG
, "shouldLoad: "+aContentLocation
.spec
);
257 var unwrappedLocation
= IOUtil
.unwrapURL(aContentLocation
);
258 var scheme
= unwrappedLocation
.scheme
;
259 var isHTTP
= /^https?$/.test(scheme
); // s? -> either http or https
261 HTTPS
.forceURI(aContentLocation
, null, aContext
);
265 shouldProcess: function(aContentType
, aContentLocation
, aRequestOrigin
, aContext
, aMimeType
, aExtra
) {
266 return this.shouldLoad(aContentType
, aContentLocation
, aRequestOrigin
, aContext
, aMimeType
, CP_SHOULDPROCESS
);
269 get_prefs: function() {
270 // get our preferences branch object
271 // FIXME: Ugly hack stolen from https
272 var branch_name
= "extensions.https_everywhere.";
274 var o_branch
= false;
276 this.log(1, "called get_prefbranch()");
277 o_prefs
= Components
.classes
["@mozilla.org/preferences-service;1"]
278 .getService(Components
.interfaces
.nsIPrefService
);
281 this.log(WARN
, "Failed to get preferences-service!");
285 o_branch
= o_prefs
.getBranch(branch_name
);
288 this.log(WARN
, "Failed to get prefs branch!");
301 var HTTPSInstance
= null;
304 // nsIFactory interface implementation
305 createInstance: function(outer
, iid
) {
307 Components
.returnCode
= CR
.NS_ERROR_NO_AGGREGATION
;
311 if (!iid
.equals(Components
.interfaces
.nsIContentPolicy
) &&
312 !iid
.equals(Components
.interfaces
.nsIChannelEventSink
) &&
313 !iid
.equals(Components
.interfaces
.nsISupports
)) {
314 Components
.returnCode
= CR
.NS_ERROR_NO_INTERFACE
;
319 HTTPSInstance
= new HTTPSEverywhere();
321 return HTTPSInstance
;
324 // nsISupports interface implementation
325 QueryInterface: function(iid
) {
326 if (iid
.equals(Components
.interfaces
.nsISupports
) ||
327 iid
.equals(Components
.interfaces
.nsIModule
) ||
328 iid
.equals(Components
.interfaces
.nsIFactory
))
331 Components
.returnCode
= CR
.NS_ERROR_NO_INTERFACE
;
341 registerSelf: function(compMgr
, fileSpec
, location
, type
) {
342 compMgr
= compMgr
.QueryInterface(Components
.interfaces
.nsIComponentRegistrar
);
343 compMgr
.registerFactoryLocation(SERVICE_ID
,
346 fileSpec
, location
, type
);
348 var catman
= Components
.classes
["@mozilla.org/categorymanager;1"]
349 .getService(Components
.interfaces
.nsICategoryManager
);
350 catman
.addCategoryEntry("app-startup", SERVICE_CTRID
,
351 SERVICE_CTRID
, true, true);
352 catman
.addCategoryEntry("content-policy", SERVICE_CTRID
,
353 SERVICE_CTRID
, true, true);
357 unregisterSelf: function(compMgr
, fileSpec
, location
) {
358 compMgr
= compMgr
.QueryInterface(Components
.interfaces
.nsIComponentRegistrar
);
360 compMgr
.unregisterFactoryLocation(SERVICE_ID
, fileSpec
);
362 var catman
= Components
.classes
["@mozilla.org/categorymanager;1"]
363 .getService(Components
.interfaces
.nsICategoryManager
);
364 catman
.deleteCategoryEntry("app-startup", SERVICE_CTRID
, true);
365 catman
.deleteCategoryEntry("content-policy", SERVICE_CTRID
, true);
368 getClassObject: function(compMgr
, cid
, iid
) {
369 if (cid
.equals(SERVICE_ID
))
372 Components
.returnCode
= CR
.NS_ERROR_NOT_REGISTERED
;
376 canUnload: function(compMgr
) {
381 function NSGetModule(comMgr
, fileSpec
) {