mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 871445 - patch 10 - DataStore: indexedDB permissions, r=ehsan
This commit is contained in:
parent
462224589b
commit
376ecbb43f
@ -284,6 +284,7 @@ this.DOMApplicationRegistry = {
|
||||
// Create or Update the DataStore for this app
|
||||
this._readManifests([{ id: aId }], (function(aResult) {
|
||||
this.updateDataStore(this.webapps[aId].localId,
|
||||
this.webapps[aId].origin,
|
||||
this.webapps[aId].manifestURL,
|
||||
aResult[0].manifest);
|
||||
}).bind(this));
|
||||
@ -530,12 +531,17 @@ this.DOMApplicationRegistry = {
|
||||
}
|
||||
this.updateOfflineCacheForApp(id);
|
||||
this.updatePermissionsForApp(id);
|
||||
this.updateDataStoreForApp(id);
|
||||
}
|
||||
// Need to update the persisted list of apps since
|
||||
// installPreinstalledApp() removes the ones failing to install.
|
||||
this._saveApps();
|
||||
}
|
||||
|
||||
// DataStores must be initialized at startup.
|
||||
for (let id in this.webapps) {
|
||||
this.updateDataStoreForApp(id);
|
||||
}
|
||||
|
||||
this.registerAppsHandlers(runUpdate);
|
||||
}).bind(this);
|
||||
|
||||
@ -552,14 +558,15 @@ this.DOMApplicationRegistry = {
|
||||
}).bind(this));
|
||||
},
|
||||
|
||||
updateDataStore: function(aId, aManifestURL, aManifest) {
|
||||
updateDataStore: function(aId, aOrigin, aManifestURL, aManifest) {
|
||||
if ('datastores-owned' in aManifest) {
|
||||
for (let name in aManifest['datastores-owned']) {
|
||||
let readonly = "access" in aManifest['datastores-owned'][name]
|
||||
? aManifest['datastores-owned'][name].access == 'readonly'
|
||||
: false;
|
||||
|
||||
dataStoreService.installDataStore(aId, name, aManifestURL, readonly);
|
||||
dataStoreService.installDataStore(aId, name, aOrigin, aManifestURL,
|
||||
readonly);
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,9 +576,8 @@ this.DOMApplicationRegistry = {
|
||||
!aManifest['datastores-access'][name].readonly
|
||||
? false : true;
|
||||
|
||||
// The first release is always in readonly mode.
|
||||
dataStoreService.installAccessDataStore(aId, name, aManifestURL,
|
||||
/* readonly */ true);
|
||||
dataStoreService.installAccessDataStore(aId, name, aOrigin,
|
||||
aManifestURL, readonly);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1434,7 +1440,8 @@ this.DOMApplicationRegistry = {
|
||||
manifestURL: app.manifestURL },
|
||||
true);
|
||||
}
|
||||
this.updateDataStore(this.webapps[id].localId, app.manifestURL, aData);
|
||||
this.updateDataStore(this.webapps[id].localId, app.origin,
|
||||
app.manifestURL, aData);
|
||||
this.broadcastMessage("Webapps:PackageEvent",
|
||||
{ type: "applied",
|
||||
manifestURL: app.manifestURL,
|
||||
@ -1640,7 +1647,8 @@ this.DOMApplicationRegistry = {
|
||||
}, true);
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[id].localId, app.manifestURL, app.manifest);
|
||||
this.updateDataStore(this.webapps[id].localId, app.origin,
|
||||
app.manifestURL, app.manifest);
|
||||
|
||||
app.name = manifest.name;
|
||||
app.csp = manifest.csp || "";
|
||||
@ -2142,8 +2150,8 @@ this.DOMApplicationRegistry = {
|
||||
true);
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[aId].localId, appObject.manifestURL,
|
||||
aManifest);
|
||||
this.updateDataStore(this.webapps[aId].localId, appObject.origin,
|
||||
appObject.manifestURL, aManifest);
|
||||
|
||||
debug("About to fire Webapps:PackageEvent 'installed'");
|
||||
this.broadcastMessage("Webapps:PackageEvent",
|
||||
@ -2248,8 +2256,8 @@ this.DOMApplicationRegistry = {
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
this.updateDataStore(this.webapps[id].localId, this.webapps[id].manifestURL,
|
||||
jsonManifest);
|
||||
this.updateDataStore(this.webapps[id].localId, this.webapps[id].origin,
|
||||
this.webapps[id].manifestURL, jsonManifest);
|
||||
}
|
||||
|
||||
["installState", "downloadAvailable",
|
||||
|
@ -103,7 +103,7 @@ this.DataStore.prototype = {
|
||||
let wId = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (wId == self._innerWindowID) {
|
||||
cpmm.removeMessageListener("DataStore:Changed:Return:OK", self);
|
||||
self._db.delete();
|
||||
self._db.close();
|
||||
}
|
||||
}, "inner-window-destroyed", false);
|
||||
|
||||
@ -278,26 +278,18 @@ this.DataStore.prototype = {
|
||||
retrieveRevisionId: function(aSuccessCb) {
|
||||
let self = this;
|
||||
this._db.revisionTxn(
|
||||
'readwrite',
|
||||
'readonly',
|
||||
function(aTxn, aRevisionStore) {
|
||||
debug("RetrieveRevisionId transaction success");
|
||||
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
if (!cursor) {
|
||||
// If the revision doesn't exist, let's create the first one.
|
||||
self.addRevision(aRevisionStore, 0, REVISION_VOID,
|
||||
function(aRevisionId) {
|
||||
self._revisionId = aRevisionId;
|
||||
aSuccessCb();
|
||||
}
|
||||
);
|
||||
return;
|
||||
if (cursor) {
|
||||
self._revisionId = cursor.value.revisionId;
|
||||
}
|
||||
|
||||
self._revisionId = cursor.value.revisionId;
|
||||
aSuccessCb();
|
||||
aSuccessCb(self._revisionId);
|
||||
};
|
||||
}
|
||||
);
|
||||
@ -475,7 +467,7 @@ this.DataStore.prototype = {
|
||||
removedIds: {}
|
||||
};
|
||||
|
||||
let request = aStore.mozGetAll(self._window.IDBKeyRange.lowerBound(aInternalRevisionId, true));
|
||||
let request = aStore.mozGetAll(IDBKeyRange.lowerBound(aInternalRevisionId, true));
|
||||
request.onsuccess = function(aEvent) {
|
||||
for (let i = 0; i < aEvent.target.result.length; ++i) {
|
||||
let data = aEvent.target.result[i];
|
||||
|
@ -12,6 +12,9 @@ function debug(s) {
|
||||
//dump('DEBUG DataStoreChangeNotifier: ' + s + '\n');
|
||||
}
|
||||
|
||||
// DataStoreServiceInternal should not be converted into a lazy getter as it
|
||||
// runs code during initialization.
|
||||
Cu.import('resource://gre/modules/DataStoreServiceInternal.jsm');
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
|
@ -39,8 +39,8 @@ DataStoreDB.prototype = {
|
||||
store.createIndex(DATASTOREDB_REVISION_INDEX, 'revisionId', { unique: true });
|
||||
},
|
||||
|
||||
init: function(aOrigin, aName) {
|
||||
let dbName = aOrigin + '_' + aName;
|
||||
init: function(aOwner, aName) {
|
||||
let dbName = aName + '|' + aOwner;
|
||||
this.initDBHelper(dbName, DATASTOREDB_VERSION,
|
||||
[DATASTOREDB_OBJECTSTORE_NAME, DATASTOREDB_REVISION]);
|
||||
},
|
||||
|
@ -17,6 +17,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
Cu.import('resource://gre/modules/DataStore.jsm');
|
||||
Cu.import("resource://gre/modules/DataStoreDB.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
@ -27,13 +28,26 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "permissionManager",
|
||||
"@mozilla.org/permissionmanager;1",
|
||||
"nsIPermissionManager");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "secMan",
|
||||
"@mozilla.org/scriptsecuritymanager;1",
|
||||
"nsIScriptSecurityManager");
|
||||
|
||||
/* DataStoreService */
|
||||
|
||||
const DATASTORESERVICE_CID = Components.ID('{d193d0e2-c677-4a7b-bb0a-19155b470f2e}');
|
||||
const REVISION_VOID = "void";
|
||||
|
||||
function DataStoreService() {
|
||||
debug('DataStoreService Constructor');
|
||||
|
||||
this.inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
if (this.inParent) {
|
||||
let obs = Services.obs;
|
||||
if (!obs) {
|
||||
debug("DataStore Error: observer-service is null!");
|
||||
@ -41,23 +55,27 @@ function DataStoreService() {
|
||||
}
|
||||
|
||||
obs.addObserver(this, 'webapps-clear-data', false);
|
||||
|
||||
let inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
if (inParent) {
|
||||
ppmm.addMessageListener("DataStore:Get", this);
|
||||
}
|
||||
|
||||
let self = this;
|
||||
cpmm.addMessageListener("datastore-first-revision-created",
|
||||
function(aMsg) { self.receiveMessage(aMsg); });
|
||||
}
|
||||
|
||||
DataStoreService.prototype = {
|
||||
inParent: false,
|
||||
|
||||
// Hash of DataStores
|
||||
stores: {},
|
||||
accessStores: {},
|
||||
pendingRequests: {},
|
||||
|
||||
installDataStore: function(aAppId, aName, aOwner, aReadOnly) {
|
||||
installDataStore: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
debug('installDataStore - appId: ' + aAppId + ', aName: ' +
|
||||
aName + ', aOwner:' + aOwner + ', aReadOnly: ' +
|
||||
aReadOnly);
|
||||
aName + ', aOrigin: ' + aOrigin + ', aOwner:' + aOwner +
|
||||
', aReadOnly: ' + aReadOnly);
|
||||
|
||||
this.checkIfInParent();
|
||||
|
||||
if (aName in this.stores && aAppId in this.stores[aName]) {
|
||||
debug('This should not happen');
|
||||
@ -68,13 +86,21 @@ DataStoreService.prototype = {
|
||||
this.stores[aName] = {};
|
||||
}
|
||||
|
||||
this.stores[aName][aAppId] = { owner: aOwner, readOnly: aReadOnly };
|
||||
// A DataStore is enabled when it has a first valid revision.
|
||||
this.stores[aName][aAppId] = { origin: aOrigin, owner: aOwner,
|
||||
readOnly: aReadOnly, enabled: false };
|
||||
|
||||
this.addPermissions(aAppId, aName, aOrigin, aOwner, aReadOnly);
|
||||
|
||||
this.createFirstRevisionId(aAppId, aName, aOwner);
|
||||
},
|
||||
|
||||
installAccessDataStore: function(aAppId, aName, aOwner, aReadOnly) {
|
||||
debug('installDataStore - appId: ' + aAppId + ', aName: ' +
|
||||
aName + ', aOwner:' + aOwner + ', aReadOnly: ' +
|
||||
aReadOnly);
|
||||
installAccessDataStore: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
debug('installAccessDataStore - appId: ' + aAppId + ', aName: ' +
|
||||
aName + ', aOrigin: ' + aOrigin + ', aOwner:' + aOwner +
|
||||
', aReadOnly: ' + aReadOnly);
|
||||
|
||||
this.checkIfInParent();
|
||||
|
||||
if (aName in this.accessStores && aAppId in this.accessStores[aName]) {
|
||||
debug('This should not happen');
|
||||
@ -85,56 +111,231 @@ DataStoreService.prototype = {
|
||||
this.accessStores[aName] = {};
|
||||
}
|
||||
|
||||
this.accessStores[aName][aAppId] = { owner: aOwner, readOnly: aReadOnly };
|
||||
this.accessStores[aName][aAppId] = { origin: aOrigin, owner: aOwner,
|
||||
readOnly: aReadOnly };
|
||||
this.addAccessPermissions(aAppId, aName, aOrigin, aOwner, aReadOnly);
|
||||
},
|
||||
|
||||
checkIfInParent: function() {
|
||||
if (!this.inParent) {
|
||||
throw "DataStore can execute this operation just in the parent process";
|
||||
}
|
||||
},
|
||||
|
||||
createFirstRevisionId: function(aAppId, aName, aOwner) {
|
||||
debug("createFirstRevisionId database: " + aName);
|
||||
|
||||
let self = this;
|
||||
let db = new DataStoreDB();
|
||||
db.init(aOwner, aName);
|
||||
db.revisionTxn(
|
||||
'readwrite',
|
||||
function(aTxn, aRevisionStore) {
|
||||
debug("createFirstRevisionId - transaction success");
|
||||
|
||||
let request = aRevisionStore.openCursor(null, 'prev');
|
||||
request.onsuccess = function(aEvent) {
|
||||
let cursor = aEvent.target.result;
|
||||
if (!cursor) {
|
||||
// If the revision doesn't exist, let's create the first one.
|
||||
db.addRevision(aRevisionStore, 0, REVISION_VOID, function() {
|
||||
debug("First revision created.");
|
||||
if (aName in self.stores && aAppId in self.stores[aName]) {
|
||||
self.stores[aName][aAppId].enabled = true;
|
||||
ppmm.broadcastAsyncMessage('datastore-first-revision-created',
|
||||
{ name: aName, owner: aOwner });
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
addPermissions: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
// When a new DataStore is installed, the permissions must be set for the
|
||||
// owner app.
|
||||
let permission = "indexedDB-chrome-" + aName + '|' + aOwner;
|
||||
this.resetPermissions(aAppId, aOrigin, aOwner, permission, aReadOnly);
|
||||
|
||||
// For any app that wants to have access to this DataStore we add the
|
||||
// permissions.
|
||||
if (aName in this.accessStores) {
|
||||
for (let appId in this.accessStores[aName]) {
|
||||
// ReadOnly is decided by the owner first.
|
||||
let readOnly = aReadOnly || this.accessStores[aName][appId].readOnly;
|
||||
this.resetPermissions(appId, this.accessStores[aName][appId].origin,
|
||||
this.accessStores[aName][appId].owner,
|
||||
permission, readOnly);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
addAccessPermissions: function(aAppId, aName, aOrigin, aOwner, aReadOnly) {
|
||||
// When an app wants to have access to a DataStore, the permissions must be
|
||||
// set.
|
||||
if (!(aName in this.stores)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let appId in this.stores[aName]) {
|
||||
let permission = "indexedDB-chrome-" + aName + '|' + this.stores[aName][appId].owner;
|
||||
// The ReadOnly is decied by the owenr first.
|
||||
let readOnly = this.stores[aName][appId].readOnly || aReadOnly;
|
||||
this.resetPermissions(aAppId, aOrigin, aOwner, permission, readOnly);
|
||||
}
|
||||
},
|
||||
|
||||
resetPermissions: function(aAppId, aOrigin, aOwner, aPermission, aReadOnly) {
|
||||
debug("ResetPermissions - appId: " + aAppId + " - origin: " + aOrigin +
|
||||
" - owner: " + aOwner + " - permissions: " + aPermission +
|
||||
" - readOnly: " + aReadOnly);
|
||||
|
||||
let uri = Services.io.newURI(aOrigin, null, null);
|
||||
let principal = secMan.getAppCodebasePrincipal(uri, aAppId, false);
|
||||
|
||||
let result = permissionManager.testExactPermissionFromPrincipal(principal,
|
||||
aPermission + '-write');
|
||||
|
||||
if (aReadOnly && result == Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Write permission removed");
|
||||
permissionManager.removeFromPrincipal(principal, aPermission + '-write');
|
||||
} else if (!aReadOnly && result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Write permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission + '-write',
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
result = permissionManager.testExactPermissionFromPrincipal(principal,
|
||||
aPermission + '-read');
|
||||
if (result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Read permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission + '-read',
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
|
||||
result = permissionManager.testExactPermissionFromPrincipal(principal, aPermission);
|
||||
if (result != Ci.nsIPermissionManager.ALLOW_ACTION) {
|
||||
debug("Generic permission added");
|
||||
permissionManager.addFromPrincipal(principal, aPermission,
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
}
|
||||
},
|
||||
|
||||
getDataStores: function(aWindow, aName) {
|
||||
debug('getDataStores - aName: ' + aName);
|
||||
|
||||
// This method can be called in the child so we need to send a request to
|
||||
// the parent and create DataStore object here.
|
||||
|
||||
let self = this;
|
||||
return new aWindow.Promise(function(resolve, reject) {
|
||||
new DataStoreServiceChild(aWindow, aName, resolve);
|
||||
// If this request comes from the main process, we have access to the
|
||||
// window, so we can skip the ipc communication.
|
||||
if (self.inParent) {
|
||||
let stores = self.getDataStoresInfo(aName, aWindow.document.nodePrincipal.appId);
|
||||
self.getDataStoreCreate(aWindow, resolve, stores);
|
||||
} else {
|
||||
// This method can be called in the child so we need to send a request
|
||||
// to the parent and create DataStore object here.
|
||||
new DataStoreServiceChild(aWindow, aName, function(aStores) {
|
||||
debug("DataStoreServiceChild callback!");
|
||||
self.getDataStoreCreate(aWindow, resolve, aStores);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
if (aMessage.name != 'DataStore:Get') {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = aMessage.data;
|
||||
|
||||
// This is a security issue and it will be fixed by Bug 916091
|
||||
let appId = msg.appId;
|
||||
getDataStoresInfo: function(aName, aAppId) {
|
||||
debug('GetDataStoresInfo');
|
||||
|
||||
let results = [];
|
||||
|
||||
if (msg.name in this.stores) {
|
||||
if (appId in this.stores[msg.name]) {
|
||||
results.push({ store: this.stores[msg.name][appId],
|
||||
readOnly: false });
|
||||
if (aName in this.stores) {
|
||||
if (aAppId in this.stores[aName]) {
|
||||
results.push({ name: aName,
|
||||
owner: this.stores[aName][aAppId].owner,
|
||||
readOnly: false,
|
||||
enabled: this.stores[aName][aAppId].enabled });
|
||||
}
|
||||
|
||||
for (var i in this.stores[msg.name]) {
|
||||
if (i == appId) {
|
||||
for (var i in this.stores[aName]) {
|
||||
if (i == aAppId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let access = this.getDataStoreAccess(msg.name, appId);
|
||||
let access = this.getDataStoreAccess(aName, aAppId);
|
||||
if (!access) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let readOnly = this.stores[msg.name][i].readOnly || access.readOnly;
|
||||
results.push({ store: this.stores[msg.name][i],
|
||||
readOnly: readOnly });
|
||||
let readOnly = this.stores[aName][i].readOnly || access.readOnly;
|
||||
results.push({ name: aName,
|
||||
owner: this.stores[aName][i].owner,
|
||||
readOnly: readOnly,
|
||||
enabled: this.stores[aName][i].enabled });
|
||||
}
|
||||
}
|
||||
|
||||
msg.stores = results;
|
||||
aMessage.target.sendAsyncMessage("DataStore:Get:Return", msg);
|
||||
return results;
|
||||
},
|
||||
|
||||
getDataStoreCreate: function(aWindow, aResolve, aStores) {
|
||||
debug("GetDataStoreCreate");
|
||||
|
||||
let results = [];
|
||||
|
||||
if (!aStores.length) {
|
||||
aResolve(results);
|
||||
return;
|
||||
}
|
||||
|
||||
let pendingDataStores = [];
|
||||
|
||||
for (let i = 0; i < aStores.length; ++i) {
|
||||
if (!aStores[i].enabled) {
|
||||
pendingDataStores.push(aStores[i].owner);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pendingDataStores.length) {
|
||||
this.getDataStoreResolve(aWindow, aResolve, aStores);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(aStores[0].name in this.pendingRequests)) {
|
||||
this.pendingRequests[aStores[0].name] = [];
|
||||
}
|
||||
|
||||
this.pendingRequests[aStores[0].name].push({ window: aWindow,
|
||||
resolve: aResolve,
|
||||
stores: aStores,
|
||||
pendingDataStores: pendingDataStores });
|
||||
},
|
||||
|
||||
getDataStoreResolve: function(aWindow, aResolve, aStores) {
|
||||
debug("GetDataStoreResolve");
|
||||
|
||||
let callbackPending = aStores.length;
|
||||
let results = [];
|
||||
|
||||
if (!callbackPending) {
|
||||
aResolve(results);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < aStores.length; ++i) {
|
||||
let obj = new DataStore(aWindow, aStores[i].name,
|
||||
aStores[i].owner, aStores[i].readOnly);
|
||||
let exposedObj = aWindow.DataStore._create(aWindow, obj);
|
||||
results.push(exposedObj);
|
||||
|
||||
obj.retrieveRevisionId(
|
||||
function() {
|
||||
--callbackPending;
|
||||
if (!callbackPending) {
|
||||
aResolve(results);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
getDataStoreAccess: function(aName, aAppId) {
|
||||
@ -162,6 +363,7 @@ DataStoreService.prototype = {
|
||||
|
||||
for (let key in this.stores) {
|
||||
if (params.appId in this.stores[key]) {
|
||||
this.deleteDatabase(key, this.stores[key][params.appId].owner);
|
||||
delete this.stores[key][params.appId];
|
||||
}
|
||||
|
||||
@ -171,6 +373,43 @@ DataStoreService.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
deleteDatabase: function(aName, aOwner) {
|
||||
debug("delete database: " + aName);
|
||||
|
||||
let db = new DataStoreDB();
|
||||
db.init(aOwner, aName);
|
||||
db.delete();
|
||||
},
|
||||
|
||||
receiveMessage: function(aMsg) {
|
||||
debug("receiveMessage");
|
||||
let data = aMsg.json;
|
||||
|
||||
if (!(data.name in this.pendingRequests)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.pendingRequests[data.name].length;) {
|
||||
let pos = this.pendingRequests[data.name][i].pendingDataStores.indexOf(data.owner);
|
||||
if (pos != -1) {
|
||||
this.pendingRequests[data.name][i].pendingDataStores.splice(pos, 1);
|
||||
if (!this.pendingRequests[data.name][i].pendingDataStores.length) {
|
||||
this.getDataStoreResolve(this.pendingRequests[data.name][i].window,
|
||||
this.pendingRequests[data.name][i].resolve,
|
||||
this.pendingRequests[data.name][i].stores);
|
||||
this.pendingRequests[data.name].splice(i, 1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (!this.pendingRequests[data.name].length) {
|
||||
delete this.pendingRequests[data.name];
|
||||
}
|
||||
},
|
||||
|
||||
classID : DATASTORESERVICE_CID,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataStoreService,
|
||||
Ci.nsIObserver]),
|
||||
@ -184,18 +423,17 @@ DataStoreService.prototype = {
|
||||
|
||||
/* DataStoreServiceChild */
|
||||
|
||||
function DataStoreServiceChild(aWindow, aName, aResolve) {
|
||||
function DataStoreServiceChild(aWindow, aName, aCallback) {
|
||||
debug("DataStoreServiceChild created");
|
||||
this.init(aWindow, aName, aResolve);
|
||||
this.init(aWindow, aName, aCallback);
|
||||
}
|
||||
|
||||
DataStoreServiceChild.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
init: function(aWindow, aName, aResolve) {
|
||||
this._window = aWindow;
|
||||
this._name = aName;
|
||||
this._resolve = aResolve;
|
||||
init: function(aWindow, aName, aCallback) {
|
||||
debug("DataStoreServiceChild init");
|
||||
this._callback = aCallback;
|
||||
|
||||
this.initDOMRequestHelper(aWindow, [ "DataStore:Get:Return" ]);
|
||||
|
||||
@ -205,35 +443,12 @@ DataStoreServiceChild.prototype = {
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("DataStoreServiceChild receiveMessage");
|
||||
if (aMessage.name != 'DataStore:Get:Return') {
|
||||
return;
|
||||
}
|
||||
let msg = aMessage.data;
|
||||
let self = this;
|
||||
|
||||
let callbackPending = msg.stores.length;
|
||||
let results = [];
|
||||
|
||||
if (!callbackPending) {
|
||||
this._resolve(results);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < msg.stores.length; ++i) {
|
||||
let obj = new DataStore(this._window, this._name,
|
||||
msg.stores[i].owner, msg.stores[i].readOnly);
|
||||
let exposedObj = this._window.DataStore._create(this._window, obj);
|
||||
results.push(exposedObj);
|
||||
|
||||
obj.retrieveRevisionId(
|
||||
function() {
|
||||
--callbackPending;
|
||||
if (!callbackPending) {
|
||||
self._resolve(results);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
this._callback(aMessage.data.stores);
|
||||
}
|
||||
}
|
||||
|
||||
|
51
dom/datastore/DataStoreServiceInternal.jsm
Normal file
51
dom/datastore/DataStoreServiceInternal.jsm
Normal file
@ -0,0 +1,51 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict"
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DataStoreServiceInternal"];
|
||||
|
||||
function debug(s) {
|
||||
// dump('DEBUG DataStoreServiceInternal: ' + s + '\n');
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageBroadcaster");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "dataStoreService",
|
||||
"@mozilla.org/datastore-service;1",
|
||||
"nsIDataStoreService");
|
||||
|
||||
this.DataStoreServiceInternal = {
|
||||
init: function() {
|
||||
debug("init");
|
||||
|
||||
let inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
|
||||
.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
if (inParent) {
|
||||
ppmm.addMessageListener("DataStore:Get", this);
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
debug("receiveMessage");
|
||||
|
||||
if (aMessage.name != 'DataStore:Get') {
|
||||
return;
|
||||
}
|
||||
|
||||
let msg = aMessage.data;
|
||||
|
||||
// This is a security issue and it will be fixed by Bug 916091
|
||||
msg.stores = dataStoreService.getDataStoresInfo(msg.name, msg.appId);
|
||||
aMessage.target.sendAsyncMessage("DataStore:Get:Return", msg);
|
||||
}
|
||||
}
|
||||
|
||||
DataStoreServiceInternal.init();
|
@ -23,4 +23,5 @@ EXTRA_JS_MODULES += [
|
||||
'DataStore.jsm',
|
||||
'DataStoreChangeNotifier.jsm',
|
||||
'DataStoreDB.jsm',
|
||||
'DataStoreServiceInternal.jsm',
|
||||
]
|
||||
|
@ -7,19 +7,29 @@
|
||||
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, uuid(d193d0e2-c677-4a7b-bb0a-19155b470f2e)]
|
||||
[scriptable, uuid(bd02d09c-41ab-47b7-9319-57aa8e5059b0)]
|
||||
interface nsIDataStoreService : nsISupports
|
||||
{
|
||||
void installDataStore(in unsigned long appId,
|
||||
in DOMString name,
|
||||
in DOMString originURL,
|
||||
in DOMString manifestURL,
|
||||
in boolean readOnly);
|
||||
|
||||
void installAccessDataStore(in unsigned long appId,
|
||||
in DOMString name,
|
||||
in DOMString originURL,
|
||||
in DOMString manifestURL,
|
||||
in boolean readOnly);
|
||||
|
||||
nsISupports getDataStores(in nsIDOMWindow window,
|
||||
in DOMString name);
|
||||
|
||||
// This is an array of objects composed by:
|
||||
// - readOnly: boolean
|
||||
// - name: DOMString
|
||||
// - owner: DOMString
|
||||
// - enabled: true/false - true if this dataStore is ready to be used.
|
||||
jsval getDataStoresInfo(in DOMString name,
|
||||
in unsigned long appId);
|
||||
};
|
||||
|
@ -10,7 +10,9 @@
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
@ -23,7 +25,8 @@
|
||||
{ "type": "embed-apps", "allow": 1, "context": document },
|
||||
{ "type": "webapps-manage", "allow": 1, "context": document }],
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true]]}, function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true],
|
||||
["dom.promise.enabled", true]]}, function() {
|
||||
gGenerator.next(); });
|
||||
});
|
||||
|
||||
@ -46,6 +49,7 @@
|
||||
}, cbError);
|
||||
yield undefined;
|
||||
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
|
@ -84,6 +84,7 @@
|
||||
},
|
||||
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
runTest();
|
||||
},
|
||||
@ -117,7 +118,10 @@
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
</script>
|
||||
|
@ -84,6 +84,7 @@
|
||||
},
|
||||
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
runTest();
|
||||
},
|
||||
@ -117,7 +118,10 @@
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
</script>
|
||||
|
@ -129,6 +129,7 @@
|
||||
|
||||
// Enabling mozBrowser
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.mozBrowserFramesEnabled", true]]}, runTest);
|
||||
},
|
||||
|
||||
@ -170,7 +171,10 @@
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
</script>
|
||||
|
@ -88,6 +88,7 @@
|
||||
},
|
||||
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
runTest();
|
||||
},
|
||||
@ -121,7 +122,10 @@
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
</script>
|
||||
|
@ -30,6 +30,7 @@
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
|
||||
SpecialPowers.autoConfirmAppInstall(continueTest);
|
||||
@ -94,11 +95,13 @@
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true]]}, function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true]]}, runTest);
|
||||
});
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true],
|
||||
["dom.datastore.enabled", true]]}, runTest);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -94,6 +94,7 @@
|
||||
|
||||
// Enabling mozBrowser
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.mozBrowserFramesEnabled", true]]}, runTest);
|
||||
},
|
||||
|
||||
@ -126,7 +127,10 @@
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
</script>
|
||||
|
@ -35,5 +35,9 @@
|
||||
"description": "Mochitests"
|
||||
}
|
||||
},
|
||||
"datastores-access" : {
|
||||
"foo" : { "readonly": false },
|
||||
"bar" : { "readonly": false }
|
||||
},
|
||||
"default_locale": "en-US"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user