services/sync/modules-testing/utils.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 "use strict";
michael@0 6
michael@0 7 this.EXPORTED_SYMBOLS = [
michael@0 8 "btoa", // It comes from a module import.
michael@0 9 "encryptPayload",
michael@0 10 "ensureLegacyIdentityManager",
michael@0 11 "setBasicCredentials",
michael@0 12 "makeIdentityConfig",
michael@0 13 "configureFxAccountIdentity",
michael@0 14 "configureIdentity",
michael@0 15 "SyncTestingInfrastructure",
michael@0 16 "waitForZeroTimer",
michael@0 17 "Promise", // from a module import
michael@0 18 "add_identity_test",
michael@0 19 ];
michael@0 20
michael@0 21 const {utils: Cu} = Components;
michael@0 22
michael@0 23 Cu.import("resource://services-sync/status.js");
michael@0 24 Cu.import("resource://services-sync/identity.js");
michael@0 25 Cu.import("resource://services-common/utils.js");
michael@0 26 Cu.import("resource://services-crypto/utils.js");
michael@0 27 Cu.import("resource://services-sync/util.js");
michael@0 28 Cu.import("resource://services-sync/browserid_identity.js");
michael@0 29 Cu.import("resource://testing-common/services-common/logging.js");
michael@0 30 Cu.import("resource://testing-common/services/sync/fakeservices.js");
michael@0 31 Cu.import("resource://gre/modules/FxAccounts.jsm");
michael@0 32 Cu.import("resource://gre/modules/FxAccountsCommon.js");
michael@0 33 Cu.import("resource://gre/modules/Promise.jsm");
michael@0 34
michael@0 35 /**
michael@0 36 * First wait >100ms (nsITimers can take up to that much time to fire, so
michael@0 37 * we can account for the timer in delayedAutoconnect) and then two event
michael@0 38 * loop ticks (to account for the Utils.nextTick() in autoConnect).
michael@0 39 */
michael@0 40 this.waitForZeroTimer = function waitForZeroTimer(callback) {
michael@0 41 let ticks = 2;
michael@0 42 function wait() {
michael@0 43 if (ticks) {
michael@0 44 ticks -= 1;
michael@0 45 CommonUtils.nextTick(wait);
michael@0 46 return;
michael@0 47 }
michael@0 48 callback();
michael@0 49 }
michael@0 50 CommonUtils.namedTimer(wait, 150, {}, "timer");
michael@0 51 }
michael@0 52
michael@0 53 /**
michael@0 54 * Ensure Sync is configured with the "legacy" identity provider.
michael@0 55 */
michael@0 56 this.ensureLegacyIdentityManager = function() {
michael@0 57 let ns = {};
michael@0 58 Cu.import("resource://services-sync/service.js", ns);
michael@0 59
michael@0 60 Status.__authManager = ns.Service.identity = new IdentityManager();
michael@0 61 ns.Service._clusterManager = ns.Service.identity.createClusterManager(ns.Service);
michael@0 62 }
michael@0 63
michael@0 64 this.setBasicCredentials =
michael@0 65 function setBasicCredentials(username, password, syncKey) {
michael@0 66 let ns = {};
michael@0 67 Cu.import("resource://services-sync/service.js", ns);
michael@0 68
michael@0 69 let auth = ns.Service.identity;
michael@0 70 auth.username = username;
michael@0 71 auth.basicPassword = password;
michael@0 72 auth.syncKey = syncKey;
michael@0 73 }
michael@0 74
michael@0 75 // Return an identity configuration suitable for testing with our identity
michael@0 76 // providers. |overrides| can specify overrides for any default values.
michael@0 77 this.makeIdentityConfig = function(overrides) {
michael@0 78 // first setup the defaults.
michael@0 79 let result = {
michael@0 80 // Username used in both fxaccount and sync identity configs.
michael@0 81 username: "foo",
michael@0 82 // fxaccount specific credentials.
michael@0 83 fxaccount: {
michael@0 84 user: {
michael@0 85 assertion: 'assertion',
michael@0 86 email: 'email',
michael@0 87 kA: 'kA',
michael@0 88 kB: 'kB',
michael@0 89 sessionToken: 'sessionToken',
michael@0 90 uid: 'user_uid',
michael@0 91 verified: true,
michael@0 92 },
michael@0 93 token: {
michael@0 94 endpoint: Svc.Prefs.get("tokenServerURI"),
michael@0 95 duration: 300,
michael@0 96 id: "id",
michael@0 97 key: "key",
michael@0 98 // uid will be set to the username.
michael@0 99 }
michael@0 100 },
michael@0 101 sync: {
michael@0 102 // username will come from the top-level username
michael@0 103 password: "whatever",
michael@0 104 syncKey: "abcdeabcdeabcdeabcdeabcdea",
michael@0 105 }
michael@0 106 };
michael@0 107
michael@0 108 // Now handle any specified overrides.
michael@0 109 if (overrides) {
michael@0 110 if (overrides.username) {
michael@0 111 result.username = overrides.username;
michael@0 112 }
michael@0 113 if (overrides.sync) {
michael@0 114 // TODO: allow just some attributes to be specified
michael@0 115 result.sync = overrides.sync;
michael@0 116 }
michael@0 117 if (overrides.fxaccount) {
michael@0 118 // TODO: allow just some attributes to be specified
michael@0 119 result.fxaccount = overrides.fxaccount;
michael@0 120 }
michael@0 121 }
michael@0 122 return result;
michael@0 123 }
michael@0 124
michael@0 125 // Configure an instance of an FxAccount identity provider with the specified
michael@0 126 // config (or the default config if not specified).
michael@0 127 this.configureFxAccountIdentity = function(authService,
michael@0 128 config = makeIdentityConfig()) {
michael@0 129 let MockInternal = {};
michael@0 130 let fxa = new FxAccounts(MockInternal);
michael@0 131
michael@0 132 // until we get better test infrastructure for bid_identity, we set the
michael@0 133 // signedin user's "email" to the username, simply as many tests rely on this.
michael@0 134 config.fxaccount.user.email = config.username;
michael@0 135 fxa.internal.currentAccountState.signedInUser = {
michael@0 136 version: DATA_FORMAT_VERSION,
michael@0 137 accountData: config.fxaccount.user
michael@0 138 };
michael@0 139 fxa.internal.currentAccountState.getCertificate = function(data, keyPair, mustBeValidUntil) {
michael@0 140 this.cert = {
michael@0 141 validUntil: fxa.internal.now() + CERT_LIFETIME,
michael@0 142 cert: "certificate",
michael@0 143 };
michael@0 144 return Promise.resolve(this.cert.cert);
michael@0 145 };
michael@0 146
michael@0 147 let mockTSC = { // TokenServerClient
michael@0 148 getTokenFromBrowserIDAssertion: function(uri, assertion, cb) {
michael@0 149 config.fxaccount.token.uid = config.username;
michael@0 150 cb(null, config.fxaccount.token);
michael@0 151 },
michael@0 152 };
michael@0 153 authService._fxaService = fxa;
michael@0 154 authService._tokenServerClient = mockTSC;
michael@0 155 // Set the "account" of the browserId manager to be the "email" of the
michael@0 156 // logged in user of the mockFXA service.
michael@0 157 authService._signedInUser = fxa.internal.currentAccountState.signedInUser.accountData;
michael@0 158 authService._account = config.fxaccount.user.email;
michael@0 159 }
michael@0 160
michael@0 161 this.configureIdentity = function(identityOverrides) {
michael@0 162 let config = makeIdentityConfig(identityOverrides);
michael@0 163 let ns = {};
michael@0 164 Cu.import("resource://services-sync/service.js", ns);
michael@0 165
michael@0 166 if (ns.Service.identity instanceof BrowserIDManager) {
michael@0 167 // do the FxAccounts thang...
michael@0 168 configureFxAccountIdentity(ns.Service.identity, config);
michael@0 169 return ns.Service.identity.initializeWithCurrentIdentity().then(() => {
michael@0 170 // need to wait until this identity manager is readyToAuthenticate.
michael@0 171 return ns.Service.identity.whenReadyToAuthenticate.promise;
michael@0 172 });
michael@0 173 }
michael@0 174 // old style identity provider.
michael@0 175 setBasicCredentials(config.username, config.sync.password, config.sync.syncKey);
michael@0 176 let deferred = Promise.defer();
michael@0 177 deferred.resolve();
michael@0 178 return deferred.promise;
michael@0 179 }
michael@0 180
michael@0 181 this.SyncTestingInfrastructure = function (server, username, password, syncKey) {
michael@0 182 let ns = {};
michael@0 183 Cu.import("resource://services-sync/service.js", ns);
michael@0 184
michael@0 185 ensureLegacyIdentityManager();
michael@0 186 let config = makeIdentityConfig();
michael@0 187 // XXX - hacks for the sync identity provider.
michael@0 188 if (username)
michael@0 189 config.username = username;
michael@0 190 if (password)
michael@0 191 config.sync.password = password;
michael@0 192 if (syncKey)
michael@0 193 config.sync.syncKey = syncKey;
michael@0 194 let cb = Async.makeSpinningCallback();
michael@0 195 configureIdentity(config).then(cb, cb);
michael@0 196 cb.wait();
michael@0 197
michael@0 198 let i = server.identity;
michael@0 199 let uri = i.primaryScheme + "://" + i.primaryHost + ":" +
michael@0 200 i.primaryPort + "/";
michael@0 201
michael@0 202 ns.Service.serverURL = uri;
michael@0 203 ns.Service.clusterURL = uri;
michael@0 204
michael@0 205 this.logStats = initTestLogging();
michael@0 206 this.fakeFilesystem = new FakeFilesystemService({});
michael@0 207 this.fakeGUIDService = new FakeGUIDService();
michael@0 208 this.fakeCryptoService = new FakeCryptoService();
michael@0 209 }
michael@0 210
michael@0 211 /**
michael@0 212 * Turn WBO cleartext into fake "encrypted" payload as it goes over the wire.
michael@0 213 */
michael@0 214 this.encryptPayload = function encryptPayload(cleartext) {
michael@0 215 if (typeof cleartext == "object") {
michael@0 216 cleartext = JSON.stringify(cleartext);
michael@0 217 }
michael@0 218
michael@0 219 return {
michael@0 220 ciphertext: cleartext, // ciphertext == cleartext with fake crypto
michael@0 221 IV: "irrelevant",
michael@0 222 hmac: fakeSHA256HMAC(cleartext, CryptoUtils.makeHMACKey("")),
michael@0 223 };
michael@0 224 }
michael@0 225
michael@0 226 // This helper can be used instead of 'add_test' or 'add_task' to run the
michael@0 227 // specified test function twice - once with the old-style sync identity
michael@0 228 // manager and once with the new-style BrowserID identity manager, to ensure
michael@0 229 // it works in both cases.
michael@0 230 //
michael@0 231 // * The test itself should be passed as 'test' - ie, test code will generally
michael@0 232 // pass |this|.
michael@0 233 // * The test function is a regular test function - although note that it must
michael@0 234 // be a generator - async operations should yield them, and run_next_test
michael@0 235 // mustn't be called.
michael@0 236 this.add_identity_test = function(test, testFunction) {
michael@0 237 function note(what) {
michael@0 238 let msg = "running test " + testFunction.name + " with " + what + " identity manager";
michael@0 239 test._log("test_info",
michael@0 240 {_message: "TEST-INFO | | " + msg + "\n"});
michael@0 241 }
michael@0 242 let ns = {};
michael@0 243 Cu.import("resource://services-sync/service.js", ns);
michael@0 244 // one task for the "old" identity manager.
michael@0 245 test.add_task(function() {
michael@0 246 note("sync");
michael@0 247 let oldIdentity = Status._authManager;
michael@0 248 ensureLegacyIdentityManager();
michael@0 249 yield testFunction();
michael@0 250 Status.__authManager = ns.Service.identity = oldIdentity;
michael@0 251 });
michael@0 252 // another task for the FxAccounts identity manager.
michael@0 253 test.add_task(function() {
michael@0 254 note("FxAccounts");
michael@0 255 let oldIdentity = Status._authManager;
michael@0 256 Status.__authManager = ns.Service.identity = new BrowserIDManager();
michael@0 257 yield testFunction();
michael@0 258 Status.__authManager = ns.Service.identity = oldIdentity;
michael@0 259 });
michael@0 260 }

mercurial