[22497] | 1 | /* |
---|
| 2 | * XPCOM component for the MIT Athena Firefox extension. |
---|
| 3 | */ |
---|
| 4 | |
---|
[25519] | 5 | // XPCOM component scaffolding |
---|
| 6 | |
---|
| 7 | const SERVICE_NAME="Athena Service"; |
---|
| 8 | const SERVICE_ID="{2276de48-911b-4acd-8b16-ef017b3eecad}"; |
---|
| 9 | const SERVICE_CONTRACT_ID = "@mit.edu/athena-service;1"; |
---|
| 10 | const SERVICE_CONSTRUCTOR=AthenaService; |
---|
| 11 | |
---|
| 12 | const SERVICE_CID = Components.ID(SERVICE_ID); |
---|
| 13 | |
---|
| 14 | Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); |
---|
| 15 | |
---|
[22497] | 16 | // Class constructor |
---|
| 17 | function AthenaService() |
---|
| 18 | { |
---|
| 19 | } |
---|
| 20 | |
---|
| 21 | // Class definition |
---|
| 22 | AthenaService.prototype = { |
---|
| 23 | |
---|
[25519] | 24 | // classDescription and contractID needed for Gecko 1.9 only |
---|
| 25 | classDescription: SERVICE_NAME, |
---|
| 26 | classID: SERVICE_CID, |
---|
| 27 | contractID: SERVICE_CONTRACT_ID, |
---|
| 28 | QueryInterface: XPCOMUtils.generateQI([Components.interfaces.nsIObserver]), |
---|
[22497] | 29 | properties: null, |
---|
| 30 | |
---|
[25519] | 31 | // Needed for Gecko 1.9 only. categories are specified in |
---|
| 32 | // chrome.manifest for Gecko 2.0 |
---|
| 33 | _xpcom_categories: [ { category: "app-startup", service: true } ], |
---|
[22497] | 34 | |
---|
| 35 | // nsIObserver implementation |
---|
| 36 | observe: function(subject, topic, data) |
---|
| 37 | { |
---|
[25519] | 38 | const propertiesURI = "chrome://athena/content/athena.properties"; |
---|
[22497] | 39 | switch (topic) { |
---|
| 40 | case "app-startup": |
---|
| 41 | // Set up to receive notifications when the profile changes |
---|
| 42 | // (including when it is set at startup) and at XPCOM shutdown. |
---|
[25519] | 43 | // Only used in Gecko 1.9 |
---|
[22497] | 44 | var observerService = |
---|
| 45 | Components.classes['@mozilla.org/observer-service;1'] |
---|
| 46 | .getService(Components.interfaces.nsIObserverService); |
---|
| 47 | observerService.addObserver(this, "profile-after-change", false); |
---|
| 48 | observerService.addObserver(this, "xpcom-shutdown", false); |
---|
| 49 | |
---|
| 50 | break; |
---|
| 51 | |
---|
| 52 | case "xpcom-shutdown": |
---|
| 53 | // The application is exiting. Remove observers added in |
---|
| 54 | // "app-startup". |
---|
[25519] | 55 | // Only used in Gecko 1.9 |
---|
[22497] | 56 | var observerService = |
---|
| 57 | Components.classes['@mozilla.org/observer-service;1'] |
---|
| 58 | .getService(Components.interfaces.nsIObserverService); |
---|
| 59 | observerService.removeObserver(this, "xpcom-shutdown"); |
---|
| 60 | observerService.removeObserver(this, "profile-after-change"); |
---|
| 61 | break; |
---|
| 62 | |
---|
| 63 | case "profile-after-change": |
---|
| 64 | // This is called when the profile is set at startup, and when |
---|
| 65 | // a profile change is requested. Perform our customizations. |
---|
[25519] | 66 | var stringBundleService = |
---|
| 67 | Components.classes["@mozilla.org/intl/stringbundle;1"] |
---|
| 68 | .getService(Components.interfaces.nsIStringBundleService); |
---|
| 69 | properties = stringBundleService.createBundle(propertiesURI); |
---|
[22497] | 70 | this.customize(); |
---|
| 71 | break; |
---|
| 72 | |
---|
| 73 | default: |
---|
| 74 | throw Components.Exception("Unknown topic: " + topic); |
---|
| 75 | } |
---|
| 76 | }, |
---|
| 77 | |
---|
| 78 | customize: function() |
---|
| 79 | { |
---|
| 80 | this.setLocalDiskCache(); |
---|
| 81 | this.addCert(); |
---|
| 82 | }, |
---|
| 83 | |
---|
| 84 | // If the profile directory is in AFS, set the disk cache to be on |
---|
| 85 | // local disk (by a default preference). |
---|
| 86 | setLocalDiskCache: function() |
---|
| 87 | { |
---|
| 88 | // We will test if the normalized profile directory path begins with |
---|
| 89 | // "/afs/". |
---|
| 90 | const AFSPathRE = /^\/afs\//; |
---|
| 91 | var prefbranch = |
---|
| 92 | Components.classes["@mozilla.org/preferences-service;1"] |
---|
| 93 | .getService(Components.interfaces.nsIPrefBranch); |
---|
[25519] | 94 | |
---|
[22497] | 95 | // Get the profile directory. |
---|
| 96 | var profileDirectory; |
---|
| 97 | try { |
---|
| 98 | profileDirectory = |
---|
| 99 | Components.classes["@mozilla.org/file/directory_service;1"] |
---|
| 100 | .getService(Components.interfaces.nsIProperties) |
---|
| 101 | .get("ProfD", Components.interfaces.nsIFile); |
---|
| 102 | } catch(e) { |
---|
| 103 | Components.utils.reportError(e); |
---|
| 104 | return; |
---|
| 105 | } |
---|
| 106 | |
---|
| 107 | // Resolve symlinks. |
---|
| 108 | profileDirectory.normalize(); |
---|
| 109 | |
---|
| 110 | if (AFSPathRE.test(profileDirectory.path)) { |
---|
| 111 | // The profile dir is in AFS. Set the default cache directory |
---|
| 112 | // to be under /var/tmp. Generate a unique directory name based |
---|
| 113 | // on the user name and profile directory leaf. |
---|
| 114 | const parentDir = "/var/tmp"; |
---|
| 115 | var parent = Components.classes["@mozilla.org/file/local;1"] |
---|
| 116 | .createInstance(Components.interfaces.nsILocalFile); |
---|
| 117 | parent.initWithPath(parentDir); |
---|
| 118 | if (parent.isDirectory()) { |
---|
| 119 | var userInfo = |
---|
| 120 | Components.classes["@mozilla.org/userinfo;1"] |
---|
| 121 | .getService(Components.interfaces.nsIUserInfo); |
---|
| 122 | var userName = userInfo.username; |
---|
| 123 | if (userName && userName.length) { |
---|
| 124 | var localCacheDir = parentDir + "/Mozilla-Firefox-" + userName |
---|
| 125 | + "/" + profileDirectory.leafName; |
---|
| 126 | var pref = |
---|
| 127 | Components.classes["@mozilla.org/preferences;1"] |
---|
| 128 | .getService(Components.interfaces.nsIPref); |
---|
| 129 | pref.SetDefaultCharPref("browser.cache.disk.parent_directory", |
---|
| 130 | localCacheDir); |
---|
| 131 | } |
---|
| 132 | } |
---|
| 133 | } |
---|
| 134 | }, |
---|
| 135 | |
---|
| 136 | addCert: function() |
---|
| 137 | { |
---|
| 138 | var certDB = |
---|
| 139 | Components.classes["@mozilla.org/security/x509certdb;1"] |
---|
| 140 | .getService(Components.interfaces.nsIX509CertDB2); |
---|
| 141 | |
---|
| 142 | // Loop over all certficates specified in the properties file. |
---|
| 143 | for (var i = 1; ; i++) { |
---|
| 144 | try { |
---|
| 145 | certName = properties.GetStringFromName("Cert" + i); |
---|
| 146 | } catch(e) { |
---|
| 147 | // End of list. |
---|
| 148 | break; |
---|
| 149 | } |
---|
| 150 | // Treat any null setting as the end of list. |
---|
| 151 | if (!(certName && certName.length)) |
---|
| 152 | break; |
---|
| 153 | |
---|
| 154 | // Set up to read the certificate. |
---|
| 155 | var ioService = |
---|
| 156 | Components.classes["@mozilla.org/network/io-service;1"] |
---|
| 157 | .getService(Components.interfaces.nsIIOService); |
---|
| 158 | var channel = ioService.newChannel("chrome://athena/content/" + |
---|
| 159 | certName, |
---|
| 160 | null, null); |
---|
| 161 | var input = channel.open(); |
---|
| 162 | var stream = |
---|
| 163 | Components.classes["@mozilla.org/scriptableinputstream;1"] |
---|
| 164 | .getService(Components.interfaces.nsIScriptableInputStream); |
---|
| 165 | stream.init(input); |
---|
| 166 | |
---|
| 167 | // Read the certificate as a Base 64 string; remove header/trailer |
---|
| 168 | // and newlines. |
---|
| 169 | var certBase64 = stream.read(input.available()); |
---|
| 170 | stream.close(); |
---|
| 171 | input.close(); |
---|
| 172 | certBase64 = certBase64.replace(/-----BEGIN CERTIFICATE-----/, ""); |
---|
| 173 | certBase64 = certBase64.replace(/-----END CERTIFICATE-----/, ""); |
---|
| 174 | certBase64 = certBase64.replace(/[\r\n]/g, ""); |
---|
| 175 | |
---|
| 176 | // Get the trust setting for this cert; default is to trust |
---|
| 177 | // for all purposes. Note that there is a bug in firefox 1.5.0.2 |
---|
| 178 | // where the addCertFromBase64() method ignores the trust setting |
---|
| 179 | // passed to it. See: |
---|
| 180 | // https://bugzilla.mozilla.org/show_bug.cgi?id=333767 |
---|
| 181 | try { |
---|
| 182 | certTrust = properties.GetStringFromName("CertTrust" + i); |
---|
| 183 | } |
---|
| 184 | catch(e) { |
---|
| 185 | certTrust = "C,C,C"; |
---|
| 186 | } |
---|
| 187 | |
---|
| 188 | // Add the cert to the database. Note that the addCertFromBase64() |
---|
| 189 | // implementation currently checks whether the cert already exists; |
---|
| 190 | // there does not seem to be a good way to check for that here. |
---|
| 191 | certDB.addCertFromBase64(certBase64, certTrust, ""); |
---|
| 192 | } |
---|
| 193 | }, |
---|
| 194 | |
---|
| 195 | // For debugging |
---|
| 196 | get wrappedJSObject() { |
---|
| 197 | return this; |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | } |
---|
| 201 | |
---|
[25519] | 202 | if (XPCOMUtils.generateNSGetFactory) { |
---|
| 203 | // Gecko 2.0 (FF 4 and higher) |
---|
| 204 | var NSGetFactory = XPCOMUtils.generateNSGetFactory([AthenaService]); |
---|
| 205 | } else { |
---|
| 206 | // Gecko 1.9 (FF 3) |
---|
| 207 | var NSGetModule = XPCOMUtils.generateNSGetModule([AthenaService]); |
---|
[22497] | 208 | } |
---|
[25519] | 209 | |
---|