Bug 1026999 - Mobile ID - SIM change scenario is not working. r=jedp

This commit is contained in:
Fernando Jiménez 2014-07-08 19:57:43 +02:00
parent c3910fefee
commit 878f922292
2 changed files with 193 additions and 31 deletions

View File

@ -36,9 +36,10 @@ this.MobileIdentityCredentialsStore.prototype = {
* We will be storing objects like:
* {
* msisdn: <string> (key),
* iccId: <string> (index),
* iccId: <string> (index, optional),
* deviceIccIds: <array>,
* origin: <array> (index),
* msisdnSessionToken: <string>
* msisdnSessionToken: <string>,
* }
*/
let objectStore = aDb.createObjectStore(CREDENTIALS_STORE_NAME, {
@ -49,9 +50,9 @@ this.MobileIdentityCredentialsStore.prototype = {
objectStore.createIndex("origin", "origin", { unique: true, multiEntry: true });
},
add: function(aIccId, aMsisdn, aOrigin, aSessionToken) {
add: function(aIccId, aMsisdn, aOrigin, aSessionToken, aDeviceIccIds) {
log.debug("put " + aIccId + ", " + aMsisdn + ", " + aOrigin + ", " +
aSessionToken);
aSessionToken + ", " + aDeviceIccIds);
if (!aOrigin || !aSessionToken) {
return Promise.reject(ERROR_INTERNAL_DB_ERROR);
}
@ -82,7 +83,8 @@ this.MobileIdentityCredentialsStore.prototype = {
iccId: aIccId,
msisdn: aMsisdn,
origin: [aOrigin],
sessionToken: aSessionToken
sessionToken: aSessionToken,
deviceIccIds: aDeviceIccIds
};
aStore.add(record);
}
@ -169,5 +171,87 @@ this.MobileIdentityCredentialsStore.prototype = {
deferred.reject
);
return deferred.promise;
},
removeValue: function(aMsisdn, aKey, aValue) {
log.debug("Removing " + aKey + " with value " + aValue);
if (!aMsisdn || !aKey) {
return Promise.reject();
}
let deferred = Promise.defer();
this.newTxn(
"readwrite",
CREDENTIALS_STORE_NAME,
(aTxn, aStore) => {
let range = IDBKeyRange.only(aMsisdn);
let cursorReq = aStore.openCursor(range);
cursorReq.onsuccess = function(aEvent) {
let cursor = aEvent.target.result;
let record;
if (!cursor || !cursor.value) {
return Promise.resolve();
}
record = cursor.value;
if (!record[aKey]) {
return Promise.reject();
}
if (aValue) {
let index = record[aKey].indexOf(aValue);
if (index != -1) {
record[aKey].splice(index, 1);
}
} else {
record[aKey] = undefined;
}
log.debug("Removal done ${}", record);
cursor.update(record);
deferred.resolve();
};
cursorReq.onerror = function(aEvent) {
log.error(aEvent.target.error);
deferred.reject(ERROR_INTERNAL_DB_ERROR);
};
}, null, deferred.reject);
return deferred.promise;
},
removeOrigin: function(aMsisdn, aOrigin) {
log.debug("removeOrigin " + aMsisdn + " " + aOrigin);
return this.removeValue(aMsisdn, "origin", aOrigin);
},
setDeviceIccIds: function(aMsisdn, aDeviceIccIds) {
log.debug("Setting icc ids " + aDeviceIccIds + " for " + aMsisdn);
if (!aMsisdn) {
return Promise.reject();
}
let deferred = Promise.defer();
this.newTxn(
"readwrite",
CREDENTIALS_STORE_NAME,
(aTxn, aStore) => {
let range = IDBKeyRange.only(aMsisdn);
let cursorReq = aStore.openCursor(range);
cursorReq.onsuccess = function(aEvent) {
let cursor = aEvent.target.result;
let record;
if (!cursor || !cursor.value) {
return Promise.resolve();
}
record = cursor.value;
record.deviceIccIds = aDeviceIccIds;
cursor.update(record);
deferred.resolve();
};
cursorReq.onerror = function(aEvent) {
log.error(aEvent.target.error);
deferred.reject(ERROR_INTERNAL_DB_ERROR);
};
}, null, deferred.reject);
return deferred.promise;
}
};

View File

@ -69,7 +69,6 @@ let MobileIdentityManager = {
Services.obs.addObserver(this, "xpcom-shutdown", false);
ppmm.addMessageListener(GET_ASSERTION_IPC_MSG, this);
this.messageManagers = {};
// TODO: Store keyPairs and certificates in disk. Bug 1021605.
this.keyPairs = {};
this.certificates = {};
},
@ -153,6 +152,26 @@ let MobileIdentityManager = {
return null;
},
get iccIds() {
#ifdef MOZ_B2G_RIL
if (this._iccIds) {
return this._iccIds;
}
this._iccIds = [];
if (!this.iccInfo) {
return this._iccIds;
}
for (let i = 0; i < this.iccInfo.length; i++) {
this._iccIds.push(this.iccInfo[i].iccId);
}
return this._iccIds;
#endif
return null;
},
get credStore() {
if (!this._credStore) {
this._credStore = new MobileIdentityCredentialsStore();
@ -597,7 +616,7 @@ let MobileIdentityManager = {
phoneInfo = new MobileIdentityUIGluePhoneInfo(
aCreds.msisdn,
null, // operator
null, // service ID
undefined, // service ID
!!aCreds.iccId, // external
true // primary
);
@ -623,7 +642,7 @@ let MobileIdentityManager = {
let creds = this.iccInfo[promptResult.serviceId].credentials;
if (creds) {
this.credStore.add(creds.iccId, creds.msisdn, aPrincipal.origin,
creds.sessionToken);
creds.sessionToken, this.iccIds);
return creds;
}
}
@ -636,7 +655,7 @@ let MobileIdentityManager = {
(creds) => {
if (creds) {
this.credStore.add(creds.iccId, creds.msisdn, aPrincipal.origin,
creds.sessionToken);
creds.sessionToken, this.iccIds);
return creds;
}
// Otherwise, we need to verify the new number selected by the
@ -648,6 +667,35 @@ let MobileIdentityManager = {
);
},
/*********************************************************
* Credentials check
*********************************************************/
checkNewCredentials: function(aOldCreds, aNewCreds, aOrigin) {
// If there were previous credentials and the user changed her
// choice, we need to remove the origin from the old credentials.
if (aNewCreds.msisdn != aOldCreds.msisdn) {
return this.credStore.removeOrigin(aOldCreds.msisdn,
aOrigin)
.then(
() => {
return aNewCreds;
}
);
} else {
// Otherwise, we update the status of the SIM cards in the device
// so we know that the user decided not to take the chance to change
// her selection. We won't bother her again until a new SIM card
// change is detected.
return this.credStore.setDeviceIccIds(aOldCreds.msisdn, this.iccIds)
.then(
() => {
return aOldCreds;
}
);
}
},
/*********************************************************
* Assertion generation
********************************************************/
@ -685,7 +733,8 @@ let MobileIdentityManager = {
this.credStore.add(aCredentials.iccId,
aCredentials.msisdn,
aOrigin,
aCredentials.sessionToken)
aCredentials.sessionToken,
this.iccIds)
.then(
() => {
deferred.resolve(assertion);
@ -721,31 +770,60 @@ let MobileIdentityManager = {
return;
}
// Even if we already have credentials for this origin, the consumer of
// the API might want to force the identity selection dialog.
// Even if we already have credentials for this origin, the consumer
// of the API might want to force the identity selection dialog.
if (aOptions.forceSelection) {
return this.promptAndVerify(principal, manifestURL, creds);
}
// It is possible that the ICC associated with the stored
// credentials is not present in the device anymore, so we ask the
// user if she still wants to use it anyway or if she prefers to use
// another phone number.
// If the credentials are associated with an external SIM or there is
// no SIM in the device, we just return the credentials.
if (this.iccInfo && creds.iccId) {
for (let i = 0; i < this.iccInfo.length; i++) {
if (this.iccInfo[i].iccId == creds.iccId) {
return creds;
return this.promptAndVerify(principal, manifestURL, creds)
.then(
(newCreds) => {
return this.checkNewCredentials(creds, newCreds,
principal.origin);
}
}
// At this point we know that the SIM associated with the credentials
// is not present in the device any more, so we need to ask the user
// what to do.
return this.promptAndVerify(principal, manifestURL, creds);
);
}
return creds;
// SIM change scenario.
// It is possible that the SIM cards inserted in the device at the
// moment of the previous verification where we obtained the credentials
// has changed. In that case, we need to let the user knowabout this
// situation. Otherwise, we just return the credentials.
log.debug("Looking for SIM changes. Credentials ICCS ${creds} " +
"Device ICCS ${device}", { creds: creds.deviceIccIds,
device: this.iccIds });
let simChanged = (creds.deviceIccIds == null && this.iccIds != null) ||
(creds.deviceIccIds != null && this.iccIds == null);
if (!simChanged &&
creds.deviceIccIds != null &&
this.IccIds != null) {
simChanged = creds.deviceIccIds.length != this.iccIds.length;
}
if (!simChanged &&
creds.deviceIccIds != null &&
this.IccIds != null) {
let intersection = creds.deviceIccIds.filter((n) => {
return this.iccIds.indexOf(n) != -1;
});
simChanged = intersection.length != creds.deviceIccIds.length ||
intersection.length != this.iccIds.length;
}
if (!simChanged) {
return creds;
}
// At this point we know that the SIM associated with the credentials
// is not present in the device any more or a new SIM has been detected,
// so we need to ask the user what to do.
return this.promptAndVerify(principal, manifestURL, creds)
.then(
(newCreds) => {
return this.checkNewCredentials(creds, newCreds,
principal.origin);
}
);
}
)
.then(