Bug 871445 - patch 10 - DataStore: indexedDB permissions, r=ehsan

This commit is contained in:
Andrea Marchesini 2013-10-02 13:27:23 -04:00
parent 462224589b
commit 376ecbb43f
16 changed files with 427 additions and 116 deletions

View File

@ -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",

View File

@ -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];

View File

@ -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");

View File

@ -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]);
},

View File

@ -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);
}
}

View 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();

View File

@ -23,4 +23,5 @@ EXTRA_JS_MODULES += [
'DataStore.jsm',
'DataStoreChangeNotifier.jsm',
'DataStoreDB.jsm',
'DataStoreServiceInternal.jsm',
]

View File

@ -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);
};

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -35,5 +35,9 @@
"description": "Mochitests"
}
},
"datastores-access" : {
"foo" : { "readonly": false },
"bar" : { "readonly": false }
},
"default_locale": "en-US"
}