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