Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ |
michael@0 | 3 | |
michael@0 | 4 | const Cc = Components.classes; |
michael@0 | 5 | const Ci = Components.interfaces; |
michael@0 | 6 | const Cu = Components.utils; |
michael@0 | 7 | const Cr = Components.results; |
michael@0 | 8 | |
michael@0 | 9 | Cu.import("resource://testing-common/httpd.js"); |
michael@0 | 10 | |
michael@0 | 11 | // XXX until bug 937114 is fixed |
michael@0 | 12 | Cu.importGlobalProperties(["atob"]); |
michael@0 | 13 | |
michael@0 | 14 | // The following boilerplate makes sure that XPCom calls |
michael@0 | 15 | // that use the profile directory work. |
michael@0 | 16 | |
michael@0 | 17 | Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
michael@0 | 18 | Cu.import("resource://gre/modules/Services.jsm"); |
michael@0 | 19 | |
michael@0 | 20 | XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto", |
michael@0 | 21 | "resource://gre/modules/identity/jwcrypto.jsm"); |
michael@0 | 22 | |
michael@0 | 23 | XPCOMUtils.defineLazyModuleGetter(this, "IDService", |
michael@0 | 24 | "resource://gre/modules/identity/Identity.jsm", |
michael@0 | 25 | "IdentityService"); |
michael@0 | 26 | |
michael@0 | 27 | XPCOMUtils.defineLazyModuleGetter(this, |
michael@0 | 28 | "IdentityStore", |
michael@0 | 29 | "resource://gre/modules/identity/IdentityStore.jsm"); |
michael@0 | 30 | |
michael@0 | 31 | XPCOMUtils.defineLazyModuleGetter(this, |
michael@0 | 32 | "Logger", |
michael@0 | 33 | "resource://gre/modules/identity/LogUtils.jsm"); |
michael@0 | 34 | |
michael@0 | 35 | XPCOMUtils.defineLazyServiceGetter(this, |
michael@0 | 36 | "uuidGenerator", |
michael@0 | 37 | "@mozilla.org/uuid-generator;1", |
michael@0 | 38 | "nsIUUIDGenerator"); |
michael@0 | 39 | |
michael@0 | 40 | const TEST_MESSAGE_MANAGER = "Mr McFeeley"; |
michael@0 | 41 | const TEST_URL = "https://myfavoritebacon.com"; |
michael@0 | 42 | const TEST_URL2 = "https://myfavoritebaconinacan.com"; |
michael@0 | 43 | const TEST_USER = "user@mozilla.com"; |
michael@0 | 44 | const TEST_PRIVKEY = "fake-privkey"; |
michael@0 | 45 | const TEST_CERT = "fake-cert"; |
michael@0 | 46 | const TEST_ASSERTION = "fake-assertion"; |
michael@0 | 47 | const TEST_IDPPARAMS = { |
michael@0 | 48 | domain: "myfavoriteflan.com", |
michael@0 | 49 | authentication: "/foo/authenticate.html", |
michael@0 | 50 | provisioning: "/foo/provision.html" |
michael@0 | 51 | }; |
michael@0 | 52 | |
michael@0 | 53 | // The following are utility functions for Identity testing |
michael@0 | 54 | |
michael@0 | 55 | function log(...aMessageArgs) { |
michael@0 | 56 | Logger.log.apply(Logger, ["test"].concat(aMessageArgs)); |
michael@0 | 57 | } |
michael@0 | 58 | |
michael@0 | 59 | function get_idstore() { |
michael@0 | 60 | return IdentityStore; |
michael@0 | 61 | } |
michael@0 | 62 | |
michael@0 | 63 | function partial(fn) { |
michael@0 | 64 | let args = Array.prototype.slice.call(arguments, 1); |
michael@0 | 65 | return function() { |
michael@0 | 66 | return fn.apply(this, args.concat(Array.prototype.slice.call(arguments))); |
michael@0 | 67 | }; |
michael@0 | 68 | } |
michael@0 | 69 | |
michael@0 | 70 | function uuid() { |
michael@0 | 71 | return uuidGenerator.generateUUID().toString(); |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | function base64UrlDecode(s) { |
michael@0 | 75 | s = s.replace(/-/g, "+"); |
michael@0 | 76 | s = s.replace(/_/g, "/"); |
michael@0 | 77 | |
michael@0 | 78 | // Replace padding if it was stripped by the sender. |
michael@0 | 79 | // See http://tools.ietf.org/html/rfc4648#section-4 |
michael@0 | 80 | switch (s.length % 4) { |
michael@0 | 81 | case 0: |
michael@0 | 82 | break; // No pad chars in this case |
michael@0 | 83 | case 2: |
michael@0 | 84 | s += "=="; |
michael@0 | 85 | break; // Two pad chars |
michael@0 | 86 | case 3: |
michael@0 | 87 | s += "="; |
michael@0 | 88 | break; // One pad char |
michael@0 | 89 | default: |
michael@0 | 90 | throw new InputException("Illegal base64url string!"); |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | // With correct padding restored, apply the standard base64 decoder |
michael@0 | 94 | return atob(s); |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | // create a mock "doc" object, which the Identity Service |
michael@0 | 98 | // uses as a pointer back into the doc object |
michael@0 | 99 | function mock_doc(aIdentity, aOrigin, aDoFunc) { |
michael@0 | 100 | let mockedDoc = {}; |
michael@0 | 101 | mockedDoc.id = uuid(); |
michael@0 | 102 | mockedDoc.loggedInUser = aIdentity; |
michael@0 | 103 | mockedDoc.origin = aOrigin; |
michael@0 | 104 | mockedDoc["do"] = aDoFunc; |
michael@0 | 105 | mockedDoc._mm = TEST_MESSAGE_MANAGER; |
michael@0 | 106 | mockedDoc.doReady = partial(aDoFunc, "ready"); |
michael@0 | 107 | mockedDoc.doLogin = partial(aDoFunc, "login"); |
michael@0 | 108 | mockedDoc.doLogout = partial(aDoFunc, "logout"); |
michael@0 | 109 | mockedDoc.doError = partial(aDoFunc, "error"); |
michael@0 | 110 | mockedDoc.doCancel = partial(aDoFunc, "cancel"); |
michael@0 | 111 | mockedDoc.doCoffee = partial(aDoFunc, "coffee"); |
michael@0 | 112 | mockedDoc.childProcessShutdown = partial(aDoFunc, "child-process-shutdown"); |
michael@0 | 113 | |
michael@0 | 114 | mockedDoc.RP = mockedDoc; |
michael@0 | 115 | |
michael@0 | 116 | return mockedDoc; |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | function mock_fxa_rp(aIdentity, aOrigin, aDoFunc) { |
michael@0 | 120 | let mockedDoc = {}; |
michael@0 | 121 | mockedDoc.id = uuid(); |
michael@0 | 122 | mockedDoc.emailHint = aIdentity; |
michael@0 | 123 | mockedDoc.origin = aOrigin; |
michael@0 | 124 | mockedDoc.wantIssuer = "firefox-accounts"; |
michael@0 | 125 | mockedDoc._mm = TEST_MESSAGE_MANAGER; |
michael@0 | 126 | |
michael@0 | 127 | mockedDoc.doReady = partial(aDoFunc, "ready"); |
michael@0 | 128 | mockedDoc.doLogin = partial(aDoFunc, "login"); |
michael@0 | 129 | mockedDoc.doLogout = partial(aDoFunc, "logout"); |
michael@0 | 130 | mockedDoc.doError = partial(aDoFunc, "error"); |
michael@0 | 131 | mockedDoc.doCancel = partial(aDoFunc, "cancel"); |
michael@0 | 132 | mockedDoc.childProcessShutdown = partial(aDoFunc, "child-process-shutdown"); |
michael@0 | 133 | |
michael@0 | 134 | mockedDoc.RP = mockedDoc; |
michael@0 | 135 | |
michael@0 | 136 | return mockedDoc; |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | // mimicking callback funtionality for ease of testing |
michael@0 | 140 | // this observer auto-removes itself after the observe function |
michael@0 | 141 | // is called, so this is meant to observe only ONE event. |
michael@0 | 142 | function makeObserver(aObserveTopic, aObserveFunc) { |
michael@0 | 143 | let observer = { |
michael@0 | 144 | // nsISupports provides type management in C++ |
michael@0 | 145 | // nsIObserver is to be an observer |
michael@0 | 146 | QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]), |
michael@0 | 147 | |
michael@0 | 148 | observe: function (aSubject, aTopic, aData) { |
michael@0 | 149 | if (aTopic == aObserveTopic) { |
michael@0 | 150 | aObserveFunc(aSubject, aTopic, aData); |
michael@0 | 151 | Services.obs.removeObserver(observer, aObserveTopic); |
michael@0 | 152 | } |
michael@0 | 153 | } |
michael@0 | 154 | }; |
michael@0 | 155 | |
michael@0 | 156 | Services.obs.addObserver(observer, aObserveTopic, false); |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | // set up the ID service with an identity with keypair and all |
michael@0 | 160 | // when ready, invoke callback with the identity |
michael@0 | 161 | function setup_test_identity(identity, cert, cb) { |
michael@0 | 162 | // set up the store so that we're supposed to be logged in |
michael@0 | 163 | let store = get_idstore(); |
michael@0 | 164 | |
michael@0 | 165 | function keyGenerated(err, kpo) { |
michael@0 | 166 | store.addIdentity(identity, kpo, cert); |
michael@0 | 167 | cb(); |
michael@0 | 168 | }; |
michael@0 | 169 | |
michael@0 | 170 | jwcrypto.generateKeyPair("DS160", keyGenerated); |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | // takes a list of functions and returns a function that |
michael@0 | 174 | // when called the first time, calls the first func, |
michael@0 | 175 | // then the next time the second, etc. |
michael@0 | 176 | function call_sequentially() { |
michael@0 | 177 | let numCalls = 0; |
michael@0 | 178 | let funcs = arguments; |
michael@0 | 179 | |
michael@0 | 180 | return function() { |
michael@0 | 181 | if (!funcs[numCalls]) { |
michael@0 | 182 | let argString = Array.prototype.slice.call(arguments).join(","); |
michael@0 | 183 | do_throw("Too many calls: " + argString); |
michael@0 | 184 | return; |
michael@0 | 185 | } |
michael@0 | 186 | funcs[numCalls].apply(funcs[numCalls],arguments); |
michael@0 | 187 | numCalls += 1; |
michael@0 | 188 | }; |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | /* |
michael@0 | 192 | * Setup a provisioning workflow with appropriate callbacks |
michael@0 | 193 | * |
michael@0 | 194 | * identity is the email we're provisioning. |
michael@0 | 195 | * |
michael@0 | 196 | * afterSetupCallback is required. |
michael@0 | 197 | * |
michael@0 | 198 | * doneProvisioningCallback is optional, if the caller |
michael@0 | 199 | * wants to be notified when the whole provisioning workflow is done |
michael@0 | 200 | * |
michael@0 | 201 | * frameCallbacks is optional, contains the callbacks that the sandbox |
michael@0 | 202 | * frame would provide in response to DOM calls. |
michael@0 | 203 | */ |
michael@0 | 204 | function setup_provisioning(identity, afterSetupCallback, doneProvisioningCallback, callerCallbacks) { |
michael@0 | 205 | IDService.reset(); |
michael@0 | 206 | |
michael@0 | 207 | let provId = uuid(); |
michael@0 | 208 | IDService.IDP._provisionFlows[provId] = { |
michael@0 | 209 | identity : identity, |
michael@0 | 210 | idpParams: TEST_IDPPARAMS, |
michael@0 | 211 | callback: function(err) { |
michael@0 | 212 | if (doneProvisioningCallback) |
michael@0 | 213 | doneProvisioningCallback(err); |
michael@0 | 214 | }, |
michael@0 | 215 | sandbox: { |
michael@0 | 216 | // Emulate the free() method on the iframe sandbox |
michael@0 | 217 | free: function() {} |
michael@0 | 218 | } |
michael@0 | 219 | }; |
michael@0 | 220 | |
michael@0 | 221 | let caller = {}; |
michael@0 | 222 | caller.id = provId; |
michael@0 | 223 | caller.doBeginProvisioningCallback = function(id, duration_s) { |
michael@0 | 224 | if (callerCallbacks && callerCallbacks.beginProvisioningCallback) |
michael@0 | 225 | callerCallbacks.beginProvisioningCallback(id, duration_s); |
michael@0 | 226 | }; |
michael@0 | 227 | caller.doGenKeyPairCallback = function(pk) { |
michael@0 | 228 | if (callerCallbacks && callerCallbacks.genKeyPairCallback) |
michael@0 | 229 | callerCallbacks.genKeyPairCallback(pk); |
michael@0 | 230 | }; |
michael@0 | 231 | |
michael@0 | 232 | afterSetupCallback(caller); |
michael@0 | 233 | } |
michael@0 | 234 | |
michael@0 | 235 | // Switch debug messages on by default |
michael@0 | 236 | let initialPrefDebugValue = false; |
michael@0 | 237 | try { |
michael@0 | 238 | initialPrefDebugValue = Services.prefs.getBoolPref("toolkit.identity.debug"); |
michael@0 | 239 | } catch(noPref) {} |
michael@0 | 240 | Services.prefs.setBoolPref("toolkit.identity.debug", true); |
michael@0 | 241 | |
michael@0 | 242 | // Switch on firefox accounts |
michael@0 | 243 | let initialPrefFXAValue = false; |
michael@0 | 244 | try { |
michael@0 | 245 | initialPrefFXAValue = Services.prefs.getBoolPref("identity.fxaccounts.enabled"); |
michael@0 | 246 | } catch(noPref) {} |
michael@0 | 247 | Services.prefs.setBoolPref("identity.fxaccounts.enabled", true); |
michael@0 | 248 | |
michael@0 | 249 | // after execution, restore prefs |
michael@0 | 250 | do_register_cleanup(function() { |
michael@0 | 251 | log("restoring prefs to their initial values"); |
michael@0 | 252 | Services.prefs.setBoolPref("toolkit.identity.debug", initialPrefDebugValue); |
michael@0 | 253 | Services.prefs.setBoolPref("identity.fxaccounts.enabled", initialPrefFXAValue); |
michael@0 | 254 | }); |
michael@0 | 255 | |
michael@0 | 256 |