summaryrefslogtreecommitdiffstats
path: root/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js
blob: 64ddb1fd1de7d2266b69d438697eae38591b41b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

// Tests for FxAccounts, storage and the master password.

// Stop us hitting the real auth server.
Services.prefs.setCharPref("identity.fxaccounts.auth.uri", "http://localhost");
// See verbose logging from FxAccounts.jsm
Services.prefs.setCharPref("identity.fxaccounts.loglevel", "Trace");

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FxAccounts.jsm");
Cu.import("resource://gre/modules/FxAccountsClient.jsm");
Cu.import("resource://gre/modules/FxAccountsCommon.js");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://services-common/utils.js");
Cu.import("resource://gre/modules/FxAccountsCommon.js");

// Use a backstage pass to get at our LoginManagerStorage object, so we can
// mock the prototype.
var {LoginManagerStorage} = Cu.import("resource://gre/modules/FxAccountsStorage.jsm", {});
var isLoggedIn = true;
LoginManagerStorage.prototype.__defineGetter__("_isLoggedIn", () => isLoggedIn);

function setLoginMgrLoggedInState(loggedIn) {
  isLoggedIn = loggedIn;
}


initTestLogging("Trace");

function run_test() {
  run_next_test();
}

function getLoginMgrData() {
  let logins = Services.logins.findLogins({}, FXA_PWDMGR_HOST, null, FXA_PWDMGR_REALM);
  if (logins.length == 0) {
    return null;
  }
  Assert.equal(logins.length, 1, "only 1 login available");
  return logins[0];
}

function createFxAccounts() {
  return new FxAccounts({
    _getDeviceName() {
      return "mock device name";
    },
    fxaPushService: {
      registerPushEndpoint() {
        return new Promise((resolve) => {
          resolve({
            endpoint: "http://mochi.test:8888"
          });
        });
      },
    }
  });
}

add_task(function* test_simple() {
  let fxa = createFxAccounts();

  let creds = {
    uid: "abcd",
    email: "test@example.com",
    sessionToken: "sessionToken",
    kA: "the kA value",
    kB: "the kB value",
    verified: true
  };
  yield fxa.setSignedInUser(creds);

  // This should have stored stuff in both the .json file in the profile
  // dir, and the login dir.
  let path = OS.Path.join(OS.Constants.Path.profileDir, "signedInUser.json");
  let data = yield CommonUtils.readJSON(path);

  Assert.strictEqual(data.accountData.email, creds.email, "correct email in the clear text");
  Assert.strictEqual(data.accountData.sessionToken, creds.sessionToken, "correct sessionToken in the clear text");
  Assert.strictEqual(data.accountData.verified, creds.verified, "correct verified flag");

  Assert.ok(!("kA" in data.accountData), "kA not stored in clear text");
  Assert.ok(!("kB" in data.accountData), "kB not stored in clear text");

  let login = getLoginMgrData();
  Assert.strictEqual(login.username, creds.uid, "uid used for username");
  let loginData = JSON.parse(login.password);
  Assert.strictEqual(loginData.version, data.version, "same version flag in both places");
  Assert.strictEqual(loginData.accountData.kA, creds.kA, "correct kA in the login mgr");
  Assert.strictEqual(loginData.accountData.kB, creds.kB, "correct kB in the login mgr");

  Assert.ok(!("email" in loginData), "email not stored in the login mgr json");
  Assert.ok(!("sessionToken" in loginData), "sessionToken not stored in the login mgr json");
  Assert.ok(!("verified" in loginData), "verified not stored in the login mgr json");

  yield fxa.signOut(/* localOnly = */ true);
  Assert.strictEqual(getLoginMgrData(), null, "login mgr data deleted on logout");
});

add_task(function* test_MPLocked() {
  let fxa = createFxAccounts();

  let creds = {
    uid: "abcd",
    email: "test@example.com",
    sessionToken: "sessionToken",
    kA: "the kA value",
    kB: "the kB value",
    verified: true
  };

  Assert.strictEqual(getLoginMgrData(), null, "no login mgr at the start");
  // tell the storage that the MP is locked.
  setLoginMgrLoggedInState(false);
  yield fxa.setSignedInUser(creds);

  // This should have stored stuff in the .json, and the login manager stuff
  // will not exist.
  let path = OS.Path.join(OS.Constants.Path.profileDir, "signedInUser.json");
  let data = yield CommonUtils.readJSON(path);

  Assert.strictEqual(data.accountData.email, creds.email, "correct email in the clear text");
  Assert.strictEqual(data.accountData.sessionToken, creds.sessionToken, "correct sessionToken in the clear text");
  Assert.strictEqual(data.accountData.verified, creds.verified, "correct verified flag");

  Assert.ok(!("kA" in data.accountData), "kA not stored in clear text");
  Assert.ok(!("kB" in data.accountData), "kB not stored in clear text");

  Assert.strictEqual(getLoginMgrData(), null, "login mgr data doesn't exist");
  yield fxa.signOut(/* localOnly = */ true)
});


add_task(function* test_consistentWithMPEdgeCases() {
  setLoginMgrLoggedInState(true);

  let fxa = createFxAccounts();

  let creds1 = {
    uid: "uid1",
    email: "test@example.com",
    sessionToken: "sessionToken",
    kA: "the kA value",
    kB: "the kB value",
    verified: true
  };

  let creds2 = {
    uid: "uid2",
    email: "test2@example.com",
    sessionToken: "sessionToken2",
    kA: "the kA value2",
    kB: "the kB value2",
    verified: false,
  };

  // Log a user in while MP is unlocked.
  yield fxa.setSignedInUser(creds1);

  // tell the storage that the MP is locked - this will prevent logout from
  // being able to clear the data.
  setLoginMgrLoggedInState(false);

  // now set the second credentials.
  yield fxa.setSignedInUser(creds2);

  // We should still have creds1 data in the login manager.
  let login = getLoginMgrData();
  Assert.strictEqual(login.username, creds1.uid);
  // and that we do have the first kA in the login manager.
  Assert.strictEqual(JSON.parse(login.password).accountData.kA, creds1.kA,
                     "stale data still in login mgr");

  // Make a new FxA instance (otherwise the values in memory will be used)
  // and we want the login manager to be unlocked.
  setLoginMgrLoggedInState(true);
  fxa = createFxAccounts();

  let accountData = yield fxa.getSignedInUser();
  Assert.strictEqual(accountData.email, creds2.email);
  // we should have no kA at all.
  Assert.strictEqual(accountData.kA, undefined, "stale kA wasn't used");
  yield fxa.signOut(/* localOnly = */ true)
});

// A test for the fact we will accept either a UID or email when looking in
// the login manager.
add_task(function* test_uidMigration() {
  setLoginMgrLoggedInState(true);
  Assert.strictEqual(getLoginMgrData(), null, "expect no logins at the start");

  // create the login entry using email as a key.
  let contents = {kA: "kA"};

  let loginInfo = new Components.Constructor(
   "@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init");
  let login = new loginInfo(FXA_PWDMGR_HOST,
                            null, // aFormSubmitURL,
                            FXA_PWDMGR_REALM, // aHttpRealm,
                            "foo@bar.com", // aUsername
                            JSON.stringify(contents), // aPassword
                            "", // aUsernameField
                            "");// aPasswordField
  Services.logins.addLogin(login);

  // ensure we read it.
  let storage = new LoginManagerStorage();
  let got = yield storage.get("uid", "foo@bar.com");
  Assert.deepEqual(got, contents);
});