Bumping manifests a=b2g-bump
[gecko.git] / services / mobileid / MobileIdentityCredentialsStore.jsm
blob1a57cc9769953061c2ce1d58c5e9064abb14a507
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
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 this.EXPORTED_SYMBOLS = ["MobileIdentityCredentialsStore"];
9 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
11 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
12 Cu.import("resource://gre/modules/MobileIdentityCommon.jsm");
13 Cu.import("resource://gre/modules/Promise.jsm");
15 const CREDENTIALS_DB_NAME     = "mobile-id-credentials";
16 const CREDENTIALS_DB_VERSION  = 1;
17 const CREDENTIALS_STORE_NAME  = "credentials-store";
19 this.MobileIdentityCredentialsStore = function() {
22 this.MobileIdentityCredentialsStore.prototype = {
24   __proto__: IndexedDBHelper.prototype,
26   init: function() {
27     log.debug("MobileIdentityCredentialsStore init");
28     this.initDBHelper(CREDENTIALS_DB_NAME,
29                       CREDENTIALS_DB_VERSION,
30                       [CREDENTIALS_STORE_NAME]);
31   },
33   upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) {
34     log.debug("upgradeSchema");
35     /**
36      * We will be storing objects like:
37      *  {
38      *    msisdn: <string> (key),
39      *    iccId: <string> (index, optional),
40      *    deviceIccIds: <array>,
41      *    origin: <array> (index),
42      *    msisdnSessionToken: <string>,
43      *  }
44      */
45     let objectStore = aDb.createObjectStore(CREDENTIALS_STORE_NAME, {
46       keyPath: "msisdn"
47     });
49     objectStore.createIndex("iccId", "iccId", { unique: true });
50     objectStore.createIndex("origin", "origin", { unique: true, multiEntry: true });
51   },
53   add: function(aIccId, aMsisdn, aOrigin, aSessionToken, aDeviceIccIds) {
54     log.debug("put " + aIccId + ", " + aMsisdn + ", " + aOrigin + ", " +
55               aSessionToken + ", " + aDeviceIccIds);
56     if (!aOrigin || !aSessionToken) {
57       return Promise.reject(ERROR_INTERNAL_DB_ERROR);
58     }
60     let deferred = Promise.defer();
62     // We first try get an existing record for the given MSISDN.
63     this.newTxn(
64       "readwrite",
65       CREDENTIALS_STORE_NAME,
66       (aTxn, aStore) => {
67         let range = IDBKeyRange.only(aMsisdn);
68         let cursorReq = aStore.openCursor(range);
69         cursorReq.onsuccess = function(aEvent) {
70           let cursor = aEvent.target.result;
71           let record;
72           // If we already have a record of this MSISDN, we add the origin to
73           // the list of allowed origins.
74           if (cursor && cursor.value) {
75             record = cursor.value;
76             if (record.origin.indexOf(aOrigin) == -1) {
77               record.origin.push(aOrigin);
78             }
79             cursor.update(record);
80           } else {
81             // Otherwise, we store a new record.
82             record = {
83               iccId: aIccId,
84               msisdn: aMsisdn,
85               origin: [aOrigin],
86               sessionToken: aSessionToken,
87               deviceIccIds: aDeviceIccIds
88             };
89             aStore.add(record);
90           }
91           deferred.resolve();
92         };
93         cursorReq.onerror = function(aEvent) {
94           log.error(aEvent.target.error);
95           deferred.reject(ERROR_INTERNAL_DB_ERROR);
96         };
97       }, null, deferred.reject);
99     return deferred.promise;
100   },
102   getByMsisdn: function(aMsisdn) {
103     log.debug("getByMsisdn " + aMsisdn);
104     if (!aMsisdn) {
105       return Promise.resolve(null);
106     }
108     let deferred = Promise.defer();
109     this.newTxn(
110       "readonly",
111       CREDENTIALS_STORE_NAME,
112       (aTxn, aStore) => {
113         aStore.get(aMsisdn).onsuccess = function(aEvent) {
114           aTxn.result = aEvent.target.result;
115         };
116       },
117       function(result) {
118         deferred.resolve(result);
119       },
120       deferred.reject
121     );
122     return deferred.promise;
123   },
125   getByIndex: function(aIndex, aValue) {
126     log.debug("getByIndex " + aIndex + ", " + aValue);
127     if (!aValue || !aIndex) {
128       return Promise.resolve(null);
129     }
131     let deferred = Promise.defer();
132     this.newTxn(
133       "readonly",
134       CREDENTIALS_STORE_NAME,
135       (aTxn, aStore) => {
136         let index = aStore.index(aIndex);
137         index.get(aValue).onsuccess = function(aEvent) {
138           aTxn.result = aEvent.target.result;
139         };
140       },
141       function(result) {
142         deferred.resolve(result);
143       },
144       deferred.reject
145     );
146     return deferred.promise;
147   },
149   getByOrigin: function(aOrigin) {
150     return this.getByIndex("origin", aOrigin);
151   },
153   getByIccId: function(aIccId) {
154     return this.getByIndex("iccId", aIccId);
155   },
157   delete: function(aMsisdn) {
158     log.debug("delete " + aMsisdn);
159     if (!aMsisdn) {
160       return Promise.resolve();
161     }
163     let deferred = Promise.defer();
164     this.newTxn(
165       "readwrite",
166       CREDENTIALS_STORE_NAME,
167       (aTxn, aStore) => {
168         aStore.delete(aMsisdn);
169       },
170       deferred.resolve,
171       deferred.reject
172     );
173     return deferred.promise;
174   },
176   removeValue: function(aMsisdn, aKey, aValue) {
177     log.debug("Removing " + aKey + " with value " + aValue);
178     if (!aMsisdn || !aKey) {
179       return Promise.reject();
180     }
182     let deferred = Promise.defer();
183     this.newTxn(
184       "readwrite",
185       CREDENTIALS_STORE_NAME,
186       (aTxn, aStore) => {
187         let range = IDBKeyRange.only(aMsisdn);
188         let cursorReq = aStore.openCursor(range);
189         cursorReq.onsuccess = function(aEvent) {
190           let cursor = aEvent.target.result;
191           let record;
192           if (!cursor || !cursor.value) {
193             return Promise.resolve();
194           }
195           record = cursor.value;
196           if (!record[aKey]) {
197             return Promise.reject();
198           }
199           if (aValue) {
200             let index = record[aKey].indexOf(aValue);
201             if (index != -1) {
202               record[aKey].splice(index, 1);
203             }
204           } else {
205             record[aKey] = undefined;
206           }
207           log.debug("Removal done ${}", record);
208           cursor.update(record);
209           deferred.resolve();
210         };
211         cursorReq.onerror = function(aEvent) {
212           log.error(aEvent.target.error);
213           deferred.reject(ERROR_INTERNAL_DB_ERROR);
214         };
215       }, null, deferred.reject);
217     return deferred.promise;
218   },
220   removeOrigin: function(aMsisdn, aOrigin) {
221     log.debug("removeOrigin " + aMsisdn + " " + aOrigin);
222     return this.removeValue(aMsisdn, "origin", aOrigin);
223   },
225   setDeviceIccIds: function(aMsisdn, aDeviceIccIds) {
226     log.debug("Setting icc ids " + aDeviceIccIds + " for " + aMsisdn);
227     if (!aMsisdn) {
228       return Promise.reject();
229     }
231     let deferred = Promise.defer();
232     this.newTxn(
233       "readwrite",
234       CREDENTIALS_STORE_NAME,
235       (aTxn, aStore) => {
236         let range = IDBKeyRange.only(aMsisdn);
237         let cursorReq = aStore.openCursor(range);
238         cursorReq.onsuccess = function(aEvent) {
239           let cursor = aEvent.target.result;
240           let record;
241           if (!cursor || !cursor.value) {
242             return Promise.resolve();
243           }
244           record = cursor.value;
245           record.deviceIccIds = aDeviceIccIds;
246           cursor.update(record);
247           deferred.resolve();
248         };
249         cursorReq.onerror = function(aEvent) {
250           log.error(aEvent.target.error);
251           deferred.reject(ERROR_INTERNAL_DB_ERROR);
252         };
253       }, null, deferred.reject);
255     return deferred.promise;
256   }