Bug 758269 - Install permissions from manifest to Permission Manager r=fabrice

This commit is contained in:
David Dahl 2012-09-26 17:22:54 -05:00
parent 048397253f
commit 3873a0bfd0
13 changed files with 815 additions and 29 deletions

View File

@ -25,4 +25,8 @@ EXTRA_PP_JS_MODULES += \
AppsUtils.jsm \
$(NULL)
EXTRA_JS_MODULES += \
PermissionsTable.jsm \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,175 @@
/* 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 Ci = Components.interfaces;
var EXPORTED_SYMBOLS = ["PermissionsTable",
"UNKNOWN_ACTION",
"ALLOW_ACTION",
"DENY_ACTION",
"PROMPT_ACTION",
"AllPossiblePermissions",
"mapSuffixes",
];
const UNKNOWN_ACTION = Ci.nsIPermissionManager.UNKNOWN_ACTION;
const ALLOW_ACTION = Ci.nsIPermissionManager.ALLOW_ACTION;
const DENY_ACTION = Ci.nsIPermissionManager.DENY_ACTION;
const PROMPT_ACTION = Ci.nsIPermissionManager.PROMPT_ACTION;
/**
* Converts ['read', 'write'] to ['contacts-read', 'contacts-write'], etc...
* @param string aPermName
* @param Array aSuffixes
* @returns Array
**/
function mapSuffixes(aPermName, aSuffixes)
{
return aSuffixes.map(function(suf) { return aPermName + "-" + suf; });
}
// Permissions Matrix: https://docs.google.com/spreadsheet/ccc?key=0Akyz_Bqjgf5pdENVekxYRjBTX0dCXzItMnRyUU1RQ0E#gid=0
// Permissions that are implicit:
// battery-status, idle, network-information, vibration,
// device-capabilities, webapps-manage, web-activities
const PermissionsTable = { "resource-lock": {
app: ALLOW_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
geolocation: {
app: PROMPT_ACTION,
privileged: PROMPT_ACTION,
certified: ALLOW_ACTION
},
camera: {
app: DENY_ACTION,
privileged: PROMPT_ACTION,
certified: ALLOW_ACTION
},
alarm: {
app: ALLOW_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"network-tcp": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
contacts: {
app: DENY_ACTION,
privileged: PROMPT_ACTION,
certified: ALLOW_ACTION,
access: ["read",
"write",
"create"
]
},
"device-storage:apps": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"device-storage:pictures": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"device-storage:videos": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"device-storage:music": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
sms: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
telephony: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
browser: {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
bluetooth: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
wifi: {
app: DENY_ACTION,
privileged: PROMPT_ACTION,
certified: ALLOW_ACTION
},
keyboard: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
mobileconnection: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
power: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
push: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
settings: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION,
access: ["read",
"write"
],
},
permissions: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
fmradio: {
app: ALLOW_ACTION, // Matrix indicates '?'
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
attention: {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
};
// Sometimes all permissions (fully expanded) need to be iterated through
let AllPossiblePermissions = [];
for (let permName in PermissionsTable) {
if (PermissionsTable[permName].access) {
AllPossiblePermissions =
AllPossiblePermissions.concat(mapSuffixes(permName,
PermissionsTable[permName].access));
}
else {
AllPossiblePermissions.push(permName);
}
}

View File

@ -111,13 +111,16 @@ WebappsRegistry.prototype = {
manifest = JSON.parse(xhr.responseText, installOrigin);
} catch (e) {
Services.DOMRequest.fireError(request, "MANIFEST_PARSE_ERROR");
Cu.reportError("Error installing app from: " + installOrigin + ": " + "MANIFEST_PARSE_ERROR");
return;
}
if (!AppsUtils.checkManifest(manifest, installOrigin)) {
Services.DOMRequest.fireError(request, "INVALID_MANIFEST");
Cu.reportError("Error installing app from: " + installOrigin + ": " + "INVALID_MANIFEST");
} else if (!this.checkAppStatus(manifest)) {
Services.DOMRequest.fireError(request, "INVALID_SECURITY_LEVEL");
Cu.reportError("Error installing app, '" + manifest.name + "': " + "INVALID_SECURITY_LEVEL");
} else {
let receipts = (aParams && aParams.receipts && Array.isArray(aParams.receipts)) ? aParams.receipts : [];
let categories = (aParams && aParams.categories && Array.isArray(aParams.categories)) ? aParams.categories : [];
@ -133,11 +136,13 @@ WebappsRegistry.prototype = {
}
} else {
Services.DOMRequest.fireError(request, "MANIFEST_URL_ERROR");
Cu.reportError("Error installing app from: " + installOrigin + ": " + "MANIFEST_URL_ERROR");
}
}).bind(this), false);
xhr.addEventListener("error", (function() {
Services.DOMRequest.fireError(request, "NETWORK_ERROR");
Cu.reportError("Error installing app from: " + installOrigin + ": " + "NETWORK_ERROR");
}).bind(this), false);
xhr.send(null);

View File

@ -4,6 +4,10 @@
"use strict";
function debug(aMsg) {
// dump("-*- Webapps.jsm: " + aMsg + "\n");
}
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -16,14 +20,33 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import('resource://gre/modules/ActivitiesService.jsm');
Cu.import("resource://gre/modules/AppsUtils.jsm");
Cu.import("resource://gre/modules/PermissionsTable.jsm");
const WEBAPP_RUNTIME = Services.appinfo.ID == "webapprt@mozilla.org";
// Permission access flags
const READONLY = "readonly";
const CREATEONLY = "createonly";
const READCREATE = "readcreate";
const READWRITE = "readwrite";
const PERM_TO_STRING = ["unknown", "allow", "deny", "prompt"];
XPCOMUtils.defineLazyServiceGetter(this,
"PermSettings",
"@mozilla.org/permissionSettings;1",
"nsIDOMPermissionSettings");
XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
Cu.import("resource://gre/modules/NetUtil.jsm");
return NetUtil;
});
XPCOMUtils.defineLazyServiceGetter(this,
"permissionManager",
"@mozilla.org/permissionmanager;1",
"nsIPermissionManager");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageBroadcaster");
@ -48,6 +71,81 @@ XPCOMUtils.defineLazyGetter(this, "msgmgr", function() {
const DIRECTORY_NAME = WEBAPP_RUNTIME ? "WebappRegD" : "ProfD";
#endif
/**
* Determine the type of app (app, privileged, certified)
* that is installed by the manifest
* @param object aManifest
* @returns integer
**/
function getAppManifestStatus(aManifest)
{
let type = aManifest.type || "web";
switch(type) {
case "web":
return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
case "privileged":
return Ci.nsIPrincipal.APP_STATUS_PRIVILEGED;
case "certified":
return Ci.nsIPrincipal.APP_STATUS_CERTIFIED;
default:
throw new Error("Webapps.jsm: Undetermined app manifest type");
}
}
/**
* Expand an access string into multiple permission names,
* e.g: perm 'contacts' with 'readwrite' =
* ['contacts-read', 'contacts-create', contacts-write']
* @param string aPermName
* @param string aAccess
* @returns Array
**/
function expandPermissions(aPermName, aAccess)
{
if (!PermissionsTable[aPermName]) {
Cu.reportError("Unknown permission: " + aPermName);
throw new Error("Webapps.jsm: App install failed, Unknown Permission: " + aPermName);
}
if (!aAccess && PermissionsTable[aPermName].access ||
aAccess && !PermissionsTable[aPermName].access) {
Cu.reportError("Webapps.jsm: installPermissions: Invalid Manifest");
throw new Error("Webapps.jsm: App install failed, Invalid Manifest");
}
if (!PermissionsTable[aPermName].access) {
return [aPermName];
}
let requestedSuffixes = [];
switch(aAccess) {
case READONLY:
requestedSuffixes.push("read");
break;
case CREATEONLY:
requestedSuffixes.push("create");
break;
case READCREATE:
requestedSuffixes.push("read", "create");
break;
case READWRITE:
requestedSuffixes.push("read", "create", "write");
break;
default:
return [];
}
let permArr = mapSuffixes(aPermName, requestedSuffixes);
let expandedPerms = [];
for (let idx in permArr) {
if (PermissionsTable[aPermName].access.indexOf(requestedSuffixes[idx]) != -1) {
expandedPerms.push(permArr[idx]);
}
}
return expandedPerms;
}
let DOMApplicationRegistry = {
appsFile: null,
webapps: { },
@ -550,13 +648,16 @@ let DOMApplicationRegistry = {
},
confirmInstall: function(aData, aFromSync, aProfileDir, aOfflineCacheObserver) {
let isReinstall = false;
let app = aData.app;
app.removable = true;
let id = app.syncId || this._appId(app.origin);
let localId = this.getAppLocalIdByManifestURL(app.manifestURL);
let manifest = new DOMApplicationManifest(app.manifest, app.origin);
// Installing an application again is considered as an update.
if (id) {
isReinstall = true;
let dir = this._getAppDir(id);
try {
dir.remove(true);
@ -564,6 +665,7 @@ let DOMApplicationRegistry = {
}
} else {
id = this.makeAppId();
app.id = id;
localId = this._nextLocalId();
}
@ -578,6 +680,7 @@ let DOMApplicationRegistry = {
let appNote = JSON.stringify(appObject);
appNote.id = id;
appObject.permissions = {};
appObject.localId = localId;
appObject.basePath = FileUtils.getDir(DIRECTORY_NAME, ["webapps"], true, true).path;
@ -603,8 +706,7 @@ let DOMApplicationRegistry = {
appObject.status = "installed";
appObject.name = app.manifest.name;
let manifest = new DOMApplicationManifest(app.manifest, app.origin);
this.installPermissions(appObject, aData, isReinstall);
if (!aFromSync)
this._saveApps((function() {
@ -633,6 +735,107 @@ let DOMApplicationRegistry = {
}
},
/**
* Install permissisions or remove deprecated permissions upon re-install
* @param object aAppObject
* The just installed AppUtils cloned appObject
* @param object aData
* The just-installed app configuration
* @param boolean aIsReinstall
* Indicates the app was just re-installed
* @returns void
**/
installPermissions:
function installPermissions(aAppObject, aData, aIsReinstall)
{
try {
let newManifest = new DOMApplicationManifest(aData.app.manifest,
aData.app.origin);
if (!newManifest.permissions && !aIsReinstall) {
return;
}
if (aIsReinstall) {
// Compare the original permissions against the new permissions
// Remove any deprecated Permissions
if (newManifest.permissions) {
// Expand perms
let newPerms = [];
for (let perm in newManifest.permissions) {
let _perms = expandPermissions(perm,
newManifest.permissions[perm].access);
newPerms = newPerms.concat(_perms);
}
for (let idx in AllPossiblePermissions) {
let index = newPerms.indexOf(AllPossiblePermissions[idx]);
if (index == -1) {
// See if the permission was installed previously
let _perm = PermSettings.get(AllPossiblePermissions[idx],
aData.app.manifestURL,
aData.app.origin,
false);
if (_perm == "unknown" || _perm == "deny") {
// All 'deny' permissions should be preserved
continue;
}
// Remove the deprecated permission
// TODO: use PermSettings.remove, see bug 793204
PermSettings.set(AllPossiblePermissions[idx],
"unknown",
aData.app.manifestURL,
aData.app.origin,
false);
}
}
}
}
let installPermType;
// Check to see if the 'webapp' is app/priv/certified
switch (getAppManifestStatus(newManifest)) {
case Ci.nsIPrincipal.APP_STATUS_CERTIFIED:
installPermType = "certified";
break;
case Ci.nsIPrincipal.APP_STATUS_PRIVILEGED:
installPermType = "privileged";
break;
case Ci.nsIPrincipal.APP_STATUS_INSTALLED:
installPermType = "app";
break;
default:
// Cannot determine app type, abort install by throwing an error
throw new Error("Webapps.jsm: Cannot determine app type, install cancelled");
}
for (let permName in newManifest.permissions) {
if (!PermissionsTable[permName]) {
throw new Error("Webapps.jsm: '" + permName + "'" +
" is not a valid Webapps permission type. Aborting Webapp installation");
return;
}
let perms = expandPermissions(permName,
newManifest.permissions[permName].access);
for (let idx in perms) {
let perm = PermissionsTable[permName][installPermType];
let permValue = PERM_TO_STRING[perm];
PermSettings.set(perms[idx],
permValue,
aData.app.manifestURL,
aData.app.origin,
false);
}
}
}
catch (ex) {
debug("Caught webapps install permissions error");
Cu.reportError(ex);
this.uninstall(aData);
}
},
_nextLocalId: function() {
let id = Services.prefs.getIntPref("dom.mozApps.maxLocalId") + 1;
Services.prefs.setIntPref("dom.mozApps.maxLocalId", id);
@ -728,25 +931,6 @@ let DOMApplicationRegistry = {
return Ci.nsIPrincipal.APP_STATUS_INSTALLED;
}
function getAppManifestStatus(aManifest) {
let type = aManifest.type || "web";
let manifestStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED;
switch(type) {
case "web":
manifestStatus = Ci.nsIPrincipal.APP_STATUS_INSTALLED;
break;
case "privileged":
manifestStatus = Ci.nsIPrincipal.APP_STATUS_PRIVILEGED;
break
case "certified":
manifestStatus = Ci.nsIPrincipal.APP_STATUS_CERTIFIED;
break;
}
return manifestStatus;
}
function getAppStatus(aManifest) {
let manifestStatus = getAppManifestStatus(aManifest);
let inferedStatus = getInferedStatus();
@ -796,7 +980,7 @@ let DOMApplicationRegistry = {
receipts: aData.receipts,
categories: aData.categories
}
}
};
let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"]
.createInstance(Ci.nsIZipReader);
try {
@ -841,6 +1025,7 @@ let DOMApplicationRegistry = {
return;
found = true;
let appNote = JSON.stringify(AppsUtils.cloneAppObject(app));
appNote.id = id;
@ -1036,6 +1221,7 @@ let DOMApplicationRegistry = {
if (record.hidden) {
if (!this.webapps[record.id] || !this.webapps[record.id].removable)
continue;
let origin = this.webapps[record.id].origin;
delete this.webapps[record.id];
let dir = this._getAppDir(record.id);
@ -1324,6 +1510,13 @@ DOMApplicationManifest.prototype = {
return this._localeProp("orientation");
},
get permissions() {
if (this._manifest.permissions) {
return this._manifest.permissions;
}
return {};
},
iconURLForSize: function(aSize) {
let icons = this._localeProp("icons");
if (!icons)

View File

@ -4,11 +4,9 @@
"use strict";
let DEBUG = 0;
if (DEBUG)
debug = function (s) { dump("-*- PermissionSettings: " + s + "\n"); }
else
debug = function (s) {}
function debug(aMsg) {
// dump("-*- PermissionSettings.js: " + aMsg + "\n");
}
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -45,7 +43,7 @@ PermissionSettings.prototype = {
switch (result)
{
case Ci.nsIPermissionManager.UNKNOWN_ACTION:
return "unknown"
return "unknown";
case Ci.nsIPermissionManager.ALLOW_ACTION:
return "allow";
case Ci.nsIPermissionManager.DENY_ACTION:

View File

@ -10,7 +10,7 @@ if (DEBUG)
else
debug = function (s) {}
const Cu = Components.utils;
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;

View File

@ -20,6 +20,12 @@ MOCHITEST_BROWSER_FILES := \
browser_ConsoleStoragePBTest.js \
browser_autofocus_preference.js \
browser_bug396843.js \
browser_webapps_permissions.js \
browser_webapps_perms_reinstall.js \
test-webapp.webapp \
test-webapp-reinstall.webapp \
test-webapp-original.webapp \
test-webapps-permissions.html \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,156 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
const DEBUG = 0;
function log()
{
if (DEBUG) {
let output = [];
for (let prop in arguments) {
output.push(arguments[prop]);
}
dump("-*- browser_webapps_permissions test: " + output.join(" ") + "\n");
}
}
let scope = {};
Cu.import("resource://gre/modules/PermissionSettings.jsm", scope);
const TEST_URL =
"http://mochi.test:8888/browser/dom/tests/browser/test-webapps-permissions.html";
const TEST_MANIFEST_URL =
"http://mochi.test:8888/browser/dom/tests/browser/test-webapp.webapp";
const TEST_ORIGIN_URL = "http://mochi.test:8888";
const installedPermsToTest = {
"geolocation": "prompt",
"alarm": "allow",
"contacts-read": "deny",
"contacts-create": "deny",
"contacts-write": "deny",
"device-storage:apps": "deny",
};
const uninstalledPermsToTest = {
"geolocation": "unknown",
"alarm": "unknown",
"contacts-read": "unknown",
"contacts-create": "unknown",
"contacts-write": "unknown",
"device-storage:apps": "unknown",
};
var gWindow, gNavigator;
function test() {
waitForExplicitFinish();
var tab = gBrowser.addTab(TEST_URL);
gBrowser.selectedTab = tab;
var browser = gBrowser.selectedBrowser;
PopupNotifications.panel.addEventListener("popupshown", handlePopup, false);
registerCleanupFunction(function () {
gWindow = null;
gBrowser.removeTab(tab);
});
browser.addEventListener("DOMContentLoaded", function onLoad(event) {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
gWindow = browser.contentWindow;
SpecialPowers.setBoolPref("dom.mozApps.dev_mode", true);
SpecialPowers.setBoolPref("dom.mozPermissionSettings.enabled", true);
SpecialPowers.addPermission("permissions", true, browser.contentWindow.document);
SpecialPowers.addPermission("permissions", true, browser.contentDocument);
executeSoon(function (){
gWindow.focus();
var nav = XPCNativeWrapper.unwrap(browser.contentWindow.navigator);
ok(nav.mozApps, "we have a mozApps property");
var navMozPerms = nav.mozPermissionSettings;
ok(navMozPerms, "mozPermissions is available");
Math.sin(0);
// INSTALL app
var pendingInstall = nav.mozApps.install(TEST_MANIFEST_URL, null);
pendingInstall.onsuccess = function onsuccess()
{
ok(this.result, "we have a result: " + this.result);
function testPerm(aPerm, aAccess)
{
var res =
navMozPerms.get(aPerm, TEST_MANIFEST_URL, TEST_ORIGIN_URL, false);
is(res, aAccess, "install: " + aPerm + " is " + res);
}
for (let permName in installedPermsToTest) {
testPerm(permName, installedPermsToTest[permName]);
}
// uninstall checks
uninstallApp();
};
pendingInstall.onerror = function onerror(e)
{
ok(false, "install()'s onerror was called: " + e);
ok(false, "All permission checks failed, uninstal tests were not run");
};
});
}, false);
}
function uninstallApp()
{
var browser = gBrowser.selectedBrowser;
var nav = XPCNativeWrapper.unwrap(browser.contentWindow.navigator);
var navMozPerms = nav.mozPermissionSettings;
var pending = nav.mozApps.getInstalled();
pending.onsuccess = function onsuccess() {
var m = this.result;
for (var i = 0; i < m.length; i++) {
var app = m[i];
function uninstall() {
var pendingUninstall = app.uninstall();
pendingUninstall.onsuccess = function(r) {
// test to make sure all permissions have been removed
function testPerm(aPerm, aAccess)
{
var res =
navMozPerms.get(aPerm, TEST_MANIFEST_URL, TEST_ORIGIN_URL, false);
is(res, aAccess, "uninstall: " + aPerm + " is " + res);
}
for (let permName in uninstalledPermsToTest) {
testPerm(permName, uninstalledPermsToTest[permName]);
}
delete nav.mozApps;
delete navMozPerms;
delete nav;
finish();
};
pending.onerror = function _onerror(e) {
ok(false, e);
ok(false, "All uninstall() permission checks failed!");
delete nav.mozApps;
delete navMozPerms;
delete nav;
finish();
};
};
uninstall();
}
};
}
function handlePopup(aEvent)
{
aEvent.target.removeEventListener("popupshown", handlePopup, false);
SpecialPowers.wrap(this).childNodes[0].button.doCommand();
}

View File

@ -0,0 +1,183 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
const DEBUG = 0;
function log()
{
if (DEBUG) {
let output = [];
for (let prop in arguments) {
output.push(arguments[prop]);
}
dump("-*- browser_webapps_perms_reinstall: " + output.join(" ") + "\n");
}
}
function pprint(aObj) {
function log(a){dump(a + "\n");}
for (let prop in aObj) {
if (typeof aObj[prop] == "object") {
log("- " + prop + " -");
pprint(aObj[prop]);
}
else {
log(prop + ": " + aObj[prop]);
}
}
}
let scope = {};
Cu.import("resource://gre/modules/PermissionSettings.jsm", scope);
const TEST_URL =
"http://mochi.test:8888/browser/dom/tests/browser/test-webapps-permissions.html";
const TEST_MANIFEST_URL =
"http://mochi.test:8888/browser/dom/tests/browser/test-webapp.webapp";
const TEST_ORIGIN_URL = "http://mochi.test:8888";
const installedPermsToTest = {
"geolocation": "prompt",
"alarm": "allow",
"contacts-read": "deny",
"contacts-create": "deny",
"contacts-write": "deny",
"device-storage:apps": "deny",
};
const reinstalledPermsToTest = {
"geolocation": "prompt",
"alarm": "unknown",
"contacts-read": "deny",
"contacts-create": "deny",
"contacts-write": "deny",
"device-storage:apps": "deny",
};
var gWindow, gNavigator;
function test() {
waitForExplicitFinish();
var tab = gBrowser.addTab(TEST_URL);
gBrowser.selectedTab = tab;
var browser = gBrowser.selectedBrowser;
PopupNotifications.panel.addEventListener("popupshown", handlePopup, false);
registerCleanupFunction(function () {
gWindow = null;
gBrowser.removeTab(tab);
});
browser.addEventListener("DOMContentLoaded", function onLoad(event) {
browser.removeEventListener("DOMContentLoaded", onLoad, false);
gWindow = browser.contentWindow;
SpecialPowers.setBoolPref("dom.mozApps.dev_mode", true);
SpecialPowers.setBoolPref("dom.mozPermissionSettings.enabled", true);
SpecialPowers.addPermission("permissions", true, browser.contentWindow.document);
SpecialPowers.addPermission("permissions", true, browser.contentDocument);
let pendingInstall;
function testInstall() {
var nav = XPCNativeWrapper.unwrap(browser.contentWindow.navigator);
ok(nav.mozApps, "we have a mozApps property");
var navMozPerms = nav.mozPermissionSettings;
ok(navMozPerms, "mozPermissions is available");
// INSTALL app
pendingInstall = nav.mozApps.install(TEST_MANIFEST_URL, null);
pendingInstall.onsuccess = function onsuccess()
{
ok(this.result, "we have a result: " + this.result);
function testPerm(aPerm, aAccess)
{
var res =
navMozPerms.get(aPerm, TEST_MANIFEST_URL, TEST_ORIGIN_URL, false);
is(res, aAccess, "install: " + aPerm + " is " + res);
}
for (let permName in installedPermsToTest) {
testPerm(permName, installedPermsToTest[permName]);
}
writeUpdatesToWebappManifest();
};
pendingInstall.onerror = function onerror(e)
{
ok(false, "install()'s onerror was called: " + e);
ok(false, "All permission checks failed, reinstall tests were not run");
};
}
testInstall();
}, false);
}
function reinstallApp()
{
var browser = gBrowser.selectedBrowser;
var nav = XPCNativeWrapper.unwrap(browser.contentWindow.navigator);
var navMozPerms = nav.mozPermissionSettings;
var pendingReinstall = nav.mozApps.install(TEST_MANIFEST_URL);
pendingReinstall.onsuccess = function onsuccess()
{
ok(this.result, "we have a result: " + this.result);
function testPerm(aPerm, aAccess)
{
var res =
navMozPerms.get(aPerm, TEST_MANIFEST_URL, TEST_ORIGIN_URL, false);
is(res, aAccess, "reinstall: " + aPerm + " is " + res);
}
for (let permName in reinstalledPermsToTest) {
testPerm(permName, reinstalledPermsToTest[permName]);
}
writeUpdatesToWebappManifest(true);
finish();
};
};
var qtyPopups = 0;
function handlePopup(aEvent)
{
qtyPopups++;
if (qtyPopups == 2) {
aEvent.target.removeEventListener("popupshown", handlePopup, false);
}
SpecialPowers.wrap(this).childNodes[0].button.doCommand();
}
function writeUpdatesToWebappManifest(aRestore)
{
let newfile = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties).
get("XCurProcD", Ci.nsIFile);
let parents = ["_tests", "testing", "mochitest", "browser", "dom" , "tests", "browser"];
newfile = newfile.parent; // up to dist/
newfile = newfile.parent;// up to obj-dir/
for (let idx in parents) {
newfile.append(parents[idx]);
}
if (aRestore) {
newfile.append("test-webapp-original.webapp");
} else {
newfile.append("test-webapp-reinstall.webapp");
}
let oldfile = newfile.parent;
oldfile.append("test-webapp.webapp");
newfile.copyTo(null, "test-webapp.webapp");
if (!aRestore) {
executeSoon(function (){ reinstallApp(); });
}
}

View File

@ -0,0 +1,20 @@
{
"name": "Super Crazy Basic App",
"installs_allowed_from": [ "*" ],
"type": "privileged",
"permissions": {
"geolocation": {
"description": "geolocate"
},
"alarm" : {
"description": "alarm"
},
"contacts": {
"description": "contacts",
"access": "readwrite"
},
"device-storage:apps": {
"description": "storage"
}
}
}

View File

@ -0,0 +1,17 @@
{
"name": "Super Crazy Basic App",
"installs_allowed_from": [ "*" ],
"type": "privileged",
"permissions": {
"geolocation": {
"description": "geolocate"
},
"contacts": {
"description": "contacts",
"access": "read"
},
"device-storage:apps": {
"description": "storage"
}
}
}

View File

@ -0,0 +1,20 @@
{
"name": "Super Crazy Basic App",
"installs_allowed_from": [ "*" ],
"type": "privileged",
"permissions": {
"geolocation": {
"description": "geolocate"
},
"alarm" : {
"description": "alarm"
},
"contacts": {
"description": "contacts",
"access": "readwrite"
},
"device-storage:apps": {
"description": "storage"
}
}
}

View File

@ -0,0 +1,9 @@
<!DOCTYPE HTML>
<html dir="ltr" xml:lang="en-US" lang="en-US">
<head>
<title>Webapps permissions test page</title>
</head>
<body>
<h1>Webapps permissions</h1>
</body>
</html>