import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo

This commit is contained in:
Roy Tam 2018-01-19 03:59:58 +08:00
commit dcd9973243
150858 changed files with 23884658 additions and 0 deletions

View file

@ -0,0 +1,131 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "PermissionObserver.h"
#include "mozilla/dom/PermissionStatus.h"
#include "mozilla/Services.h"
#include "mozilla/UniquePtr.h"
#include "nsIObserverService.h"
#include "nsIPermission.h"
#include "PermissionUtils.h"
namespace mozilla {
namespace dom {
namespace {
PermissionObserver* gInstance = nullptr;
} // namespace
NS_IMPL_ISUPPORTS(PermissionObserver,
nsIObserver,
nsISupportsWeakReference)
PermissionObserver::PermissionObserver()
{
MOZ_ASSERT(!gInstance);
}
PermissionObserver::~PermissionObserver()
{
MOZ_ASSERT(mSinks.IsEmpty());
MOZ_ASSERT(gInstance == this);
gInstance = nullptr;
}
/* static */ already_AddRefed<PermissionObserver>
PermissionObserver::GetInstance()
{
RefPtr<PermissionObserver> instance = gInstance;
if (!instance) {
instance = new PermissionObserver();
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_WARN_IF(!obs)) {
return nullptr;
}
nsresult rv = obs->AddObserver(instance, "perm-changed", true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
gInstance = instance;
}
return instance.forget();
}
void
PermissionObserver::AddSink(PermissionStatus* aSink)
{
MOZ_ASSERT(aSink);
MOZ_ASSERT(!mSinks.Contains(aSink));
mSinks.AppendElement(aSink);
}
void
PermissionObserver::RemoveSink(PermissionStatus* aSink)
{
MOZ_ASSERT(aSink);
MOZ_ASSERT(mSinks.Contains(aSink));
mSinks.RemoveElement(aSink);
}
void
PermissionObserver::Notify(PermissionName aName, nsIPrincipal& aPrincipal)
{
for (auto* sink : mSinks) {
if (sink->mName != aName) {
continue;
}
nsCOMPtr<nsIPrincipal> sinkPrincipal = sink->GetPrincipal();
if (NS_WARN_IF(!sinkPrincipal) || !aPrincipal.Equals(sinkPrincipal)) {
continue;
}
sink->PermissionChanged();
}
}
NS_IMETHODIMP
PermissionObserver::Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData)
{
MOZ_ASSERT(!strcmp(aTopic, "perm-changed"));
if (mSinks.IsEmpty()) {
return NS_OK;
}
nsCOMPtr<nsIPermission> perm = do_QueryInterface(aSubject);
if (!perm) {
return NS_OK;
}
nsCOMPtr<nsIPrincipal> principal;
perm->GetPrincipal(getter_AddRefs(principal));
if (!principal) {
return NS_OK;
}
nsAutoCString type;
perm->GetType(type);
Maybe<PermissionName> permission = TypeToPermissionName(type.get());
if (permission) {
Notify(permission.value(), *principal);
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

View file

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_PermissionObserver_h_
#define mozilla_dom_PermissionObserver_h_
#include "mozilla/dom/PermissionsBinding.h"
#include "nsIObserver.h"
#include "nsIPrincipal.h"
#include "nsTArray.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace dom {
class PermissionStatus;
// Singleton that watches for perm-changed notifications in order to notify
// PermissionStatus objects.
class PermissionObserver final
: public nsIObserver
, public nsSupportsWeakReference
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static already_AddRefed<PermissionObserver> GetInstance();
void AddSink(PermissionStatus* aObs);
void RemoveSink(PermissionStatus* aObs);
private:
PermissionObserver();
virtual ~PermissionObserver();
void Notify(PermissionName aName, nsIPrincipal& aPrincipal);
nsTArray<PermissionStatus*> mSinks;
};
} // namespace dom
} // namespace mozilla
#endif

View file

@ -0,0 +1,95 @@
/* 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";
/* static functions */
var DEBUG = 0;
var debug;
if (DEBUG) {
debug = function (s) { dump("-*- PermissionPromptService: " + s + "\n"); };
}
else {
debug = function (s) {};
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PermissionsInstaller.jsm");
const PERMISSIONPROMPTSERVICE_CONTRACTID = "@mozilla.org/permission-prompt-service;1";
const PERMISSIONPROMPTSERVICE_CID = Components.ID("{e5f953b3-a6ca-444e-a88d-cdc81383741c}");
const permissionPromptService = Ci.nsIPermissionPromptService;
var permissionManager = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);
var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
function makePrompt()
{
return Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt);
}
function PermissionPromptService()
{
debug("Constructor");
}
PermissionPromptService.prototype = {
classID : PERMISSIONPROMPTSERVICE_CID,
QueryInterface : XPCOMUtils.generateQI([permissionPromptService, Ci.nsIObserver]),
classInfo : XPCOMUtils.generateCI({classID: PERMISSIONPROMPTSERVICE_CID,
contractID: PERMISSIONPROMPTSERVICE_CONTRACTID,
classDescription: "PermissionPromptService",
interfaces: [permissionPromptService]
}),
/**
* getPermission
* Ask for permission for an API, device, etc.
* @param nsIContentPermissionRequest aRequest
* @returns void
**/
getPermission: function PS_getPermission(aRequest)
{
if (!(aRequest instanceof Ci.nsIContentPermissionRequest)) {
throw new Error("PermissionService.getPermission: "
+ "2nd argument must be type 'nsIContentPermissionRequest'");
}
// Only allow exactly one permission request here.
let types = aRequest.types.QueryInterface(Ci.nsIArray);
if (types.length != 1) {
aRequest.cancel();
return;
}
let reqType = types.queryElementAt(0, Ci.nsIContentPermissionType);
let type = reqType.access !== "unused" ? reqType.type + "-" + reqType.access
: reqType.type;
let perm =
permissionManager.testExactPermissionFromPrincipal(aRequest.principal, type);
switch (perm) {
case Ci.nsIPermissionManager.ALLOW_ACTION:
aRequest.allow();
break;
case Ci.nsIPermissionManager.PROMPT_ACTION:
makePrompt().prompt(aRequest);
break;
case Ci.nsIPermissionManager.DENY_ACTION:
case Ci.nsIPermissionManager.UNKNOWN_ACTION:
default:
aRequest.cancel();
break;
}
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PermissionPromptService]);

View file

@ -0,0 +1,2 @@
component {e5f953b3-a6ca-444e-a88d-cdc81383741c} PermissionPromptService.js
contract @mozilla.org/permission-prompt-service;1 {e5f953b3-a6ca-444e-a88d-cdc81383741c}

View file

@ -0,0 +1,136 @@
/* 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";
function debug(aMsg) {
//dump("-*- PermissionSettings.js: " + aMsg + "\n");
}
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PermissionsTable.jsm");
var cpm = Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsISyncMessageSender);
// PermissionSettings
const PERMISSIONSETTINGS_CONTRACTID = "@mozilla.org/permissionSettings;1";
const PERMISSIONSETTINGS_CID = Components.ID("{cd2cf7a1-f4c1-487b-8c1b-1a71c7097431}");
function PermissionSettings()
{
debug("Constructor");
}
XPCOMUtils.defineLazyServiceGetter(this,
"appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
PermissionSettings.prototype = {
get: function get(aPermName, aManifestURL, aOrigin, aBrowserFlag) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag);
let uri = Services.io.newURI(aOrigin, null, null);
let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: appID,
inIsolatedMozBrowser: aBrowserFlag});
let result = Services.perms.testExactPermanentPermission(principal, aPermName);
switch (result)
{
case Ci.nsIPermissionManager.UNKNOWN_ACTION:
return "unknown";
case Ci.nsIPermissionManager.ALLOW_ACTION:
return "allow";
case Ci.nsIPermissionManager.DENY_ACTION:
return "deny";
case Ci.nsIPermissionManager.PROMPT_ACTION:
return "prompt";
default:
dump("Unsupported PermissionSettings Action!\n");
return "unknown";
}
},
isExplicit: function isExplicit(aPermName, aManifestURL, aOrigin,
aBrowserFlag) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
debug("isExplicit: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
let uri = Services.io.newURI(aOrigin, null, null);
let app = appsService.getAppByManifestURL(aManifestURL);
let principal = Services.scriptSecurityManager
.createCodebasePrincipal(uri, {appId: app.localId, inIsolatedMozBrowser: aBrowserFlag});
return isExplicitInPermissionsTable(aPermName,
principal.appStatus);
},
set: function set(aPermName, aPermValue, aManifestURL, aOrigin,
aBrowserFlag) {
debug("Set called with: " + aPermName + ", " + aManifestURL + ", " +
aOrigin + ", " + aPermValue + ", " + aBrowserFlag);
let currentPermValue = this.get(aPermName, aManifestURL, aOrigin,
aBrowserFlag);
let action;
// Check for invalid calls so that we throw an exception rather than get
// killed by parent process
if (currentPermValue === "unknown" ||
aPermValue === "unknown" ||
!this.isExplicit(aPermName, aManifestURL, aOrigin, aBrowserFlag)) {
let errorMsg = "PermissionSettings.js: '" + aPermName + "'" +
" is an implicit permission for '" + aManifestURL +
"' or the permission isn't set";
Cu.reportError(errorMsg);
throw new Components.Exception(errorMsg);
}
cpm.sendSyncMessage("PermissionSettings:AddPermission", {
type: aPermName,
origin: aOrigin,
manifestURL: aManifestURL,
value: aPermValue,
browserFlag: aBrowserFlag
});
},
remove: function remove(aPermName, aManifestURL, aOrigin) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.js
let uri = Services.io.newURI(aOrigin, null, null);
let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
let principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: appID,
inIsolatedMozBrowser: true});
if (principal.appStatus !== Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) {
let errorMsg = "PermissionSettings.js: '" + aOrigin + "'" +
" is installed or permission is implicit, cannot remove '" +
aPermName + "'.";
Cu.reportError(errorMsg);
throw new Components.Exception(errorMsg);
}
// PermissionSettings.jsm handles delete when value is "unknown"
cpm.sendSyncMessage("PermissionSettings:AddPermission", {
type: aPermName,
origin: aOrigin,
manifestURL: aManifestURL,
value: "unknown",
browserFlag: true
});
},
classID : PERMISSIONSETTINGS_CID,
QueryInterface : XPCOMUtils.generateQI([])
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PermissionSettings])

View file

@ -0,0 +1,200 @@
/* 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";
function debug(s) {
//dump("-*- PermissionSettings Module: " + s + "\n");
}
const Cu = Components.utils;
const Cc = Components.classes;
const Ci = Components.interfaces;
this.EXPORTED_SYMBOLS = ["PermissionSettingsModule"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/PermissionsTable.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
XPCOMUtils.defineLazyServiceGetter(this,
"appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
this.PermissionSettingsModule = {
init: function init() {
debug("Init");
ppmm.addMessageListener("PermissionSettings:AddPermission", this);
Services.obs.addObserver(this, "profile-before-change", false);
},
_isChangeAllowed: function(aPrincipal, aPermName, aAction) {
// Bug 812289:
// Change is allowed from a child process when all of the following
// conditions stand true:
// * the action isn't "unknown" (so the change isn't a delete) if the app
// is installed
// * the permission already exists on the database
// * the permission is marked as explicit on the permissions table
// Note that we *have* to check the first two conditions here because
// permissionManager doesn't know if it's being called as a result of
// a parent process or child process request. We could check
// if the permission is actually explicit (and thus modifiable) or not
// on permissionManager also but we currently don't.
let perm =
Services.perms.testExactPermissionFromPrincipal(aPrincipal,aPermName);
let isExplicit = isExplicitInPermissionsTable(aPermName, aPrincipal.appStatus);
return (aAction === "unknown" &&
aPrincipal.appStatus === Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) ||
(aAction !== "unknown" &&
(perm !== Ci.nsIPermissionManager.UNKNOWN_ACTION) &&
isExplicit);
},
addPermission: function addPermission(aData, aCallbacks) {
this._internalAddPermission(aData, true, aCallbacks);
},
_internalAddPermission: function _internalAddPermission(aData, aAllowAllChanges, aCallbacks) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm.
let app;
let principal;
// Test if app is cached (signed streamable package) or installed via DOMApplicationRegistry
if (aData.isCachedPackage) {
// If the app is from packaged web app, the origin includes origin attributes already.
principal =
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aData.origin);
app = {localId: principal.appId};
} else {
app = appsService.getAppByManifestURL(aData.manifestURL);
let uri = Services.io.newURI(aData.origin, null, null);
principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: app.localId,
inIsolatedMozBrowser: aData.browserFlag});
}
let action;
switch (aData.value)
{
case "unknown":
action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
break;
case "allow":
action = Ci.nsIPermissionManager.ALLOW_ACTION;
break;
case "deny":
action = Ci.nsIPermissionManager.DENY_ACTION;
break;
case "prompt":
action = Ci.nsIPermissionManager.PROMPT_ACTION;
break;
default:
dump("Unsupported PermisionSettings Action: " + aData.value +"\n");
action = Ci.nsIPermissionManager.UNKNOWN_ACTION;
}
if (aAllowAllChanges ||
this._isChangeAllowed(principal, aData.type, aData.value)) {
debug("add: " + aData.origin + " " + app.localId + " " + action);
Services.perms.addFromPrincipal(principal, aData.type, action);
return true;
} else {
debug("add Failure: " + aData.origin + " " + app.localId + " " + action);
return false; // This isn't currently used, see comment on setPermission
}
},
getPermission: function getPermission(aPermName, aManifestURL, aOrigin, aBrowserFlag, aIsCachedPackage) {
// TODO: Bug 1196644 - Add signPKg parameter into PermissionSettings.jsm
debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin);
let principal;
// Test if app is cached (signed streamable package) or installed via DOMApplicationRegistry
if (aIsCachedPackage) {
// If the app is from packaged web app, the origin includes origin attributes already.
principal =
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(aOrigin);
} else {
let uri = Services.io.newURI(aOrigin, null, null);
let appID = appsService.getAppLocalIdByManifestURL(aManifestURL);
principal =
Services.scriptSecurityManager.createCodebasePrincipal(uri,
{appId: appID,
inIsolatedMozBrowser: aBrowserFlag});
}
let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName);
switch (result)
{
case Ci.nsIPermissionManager.UNKNOWN_ACTION:
return "unknown";
case Ci.nsIPermissionManager.ALLOW_ACTION:
return "allow";
case Ci.nsIPermissionManager.DENY_ACTION:
return "deny";
case Ci.nsIPermissionManager.PROMPT_ACTION:
return "prompt";
default:
dump("Unsupported PermissionSettings Action!\n");
return "unknown";
}
},
removePermission: function removePermission(aPermName, aManifestURL, aOrigin, aBrowserFlag, aIsCachedPackage) {
let data = {
type: aPermName,
origin: aOrigin,
manifestURL: aManifestURL,
value: "unknown",
browserFlag: aBrowserFlag,
isCachedPackage: aIsCachedPackage
};
this._internalAddPermission(data, true);
},
observe: function observe(aSubject, aTopic, aData) {
ppmm.removeMessageListener("PermissionSettings:AddPermission", this);
Services.obs.removeObserver(this, "profile-before-change");
ppmm = null;
},
receiveMessage: function receiveMessage(aMessage) {
debug("PermissionSettings::receiveMessage " + aMessage.name);
let mm = aMessage.target;
let msg = aMessage.data;
let result;
switch (aMessage.name) {
case "PermissionSettings:AddPermission":
let success = false;
let errorMsg =
" from a content process with no 'permissions' privileges.";
if (mm.assertPermission("permissions")) {
success = this._internalAddPermission(msg, false);
if (!success) {
// Just kill the calling process
mm.assertPermission("permissions-modify-implicit");
errorMsg = " had an implicit permission change. Child process killed.";
}
}
if (!success) {
Cu.reportError("PermissionSettings message " + msg.type + errorMsg);
return null;
}
break;
}
}
}
PermissionSettingsModule.init();

View file

@ -0,0 +1,2 @@
component {cd2cf7a1-f4c1-487b-8c1b-1a71c7097431} PermissionSettings.js
contract @mozilla.org/permissionSettings;1 {cd2cf7a1-f4c1-487b-8c1b-1a71c7097431}

View file

@ -0,0 +1,129 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/dom/PermissionStatus.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/Services.h"
#include "nsIPermissionManager.h"
#include "PermissionObserver.h"
#include "PermissionUtils.h"
namespace mozilla {
namespace dom {
/* static */ already_AddRefed<PermissionStatus>
PermissionStatus::Create(nsPIDOMWindowInner* aWindow,
PermissionName aName,
ErrorResult& aRv)
{
RefPtr<PermissionStatus> status = new PermissionStatus(aWindow, aName);
aRv = status->Init();
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return status.forget();
}
PermissionStatus::PermissionStatus(nsPIDOMWindowInner* aWindow,
PermissionName aName)
: DOMEventTargetHelper(aWindow)
, mName(aName)
, mState(PermissionState::Denied)
{
}
nsresult
PermissionStatus::Init()
{
mObserver = PermissionObserver::GetInstance();
if (NS_WARN_IF(!mObserver)) {
return NS_ERROR_FAILURE;
}
mObserver->AddSink(this);
nsresult rv = UpdateState();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
PermissionStatus::~PermissionStatus()
{
if (mObserver) {
mObserver->RemoveSink(this);
}
}
JSObject*
PermissionStatus::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PermissionStatusBinding::Wrap(aCx, this, aGivenProto);
}
nsresult
PermissionStatus::UpdateState()
{
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if (NS_WARN_IF(!permMgr)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
if (NS_WARN_IF(!window)) {
return NS_ERROR_FAILURE;
}
uint32_t action = nsIPermissionManager::DENY_ACTION;
nsresult rv = permMgr->TestPermissionFromWindow(window,
PermissionNameToType(mName),
&action);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mState = ActionToPermissionState(action);
return NS_OK;
}
already_AddRefed<nsIPrincipal>
PermissionStatus::GetPrincipal() const
{
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
if (NS_WARN_IF(!window)) {
return nullptr;
}
nsIDocument* doc = window->GetExtantDoc();
if (NS_WARN_IF(!doc)) {
return nullptr;
}
nsCOMPtr<nsIPrincipal> principal =
mozilla::BasePrincipal::Cast(doc->NodePrincipal())->CloneStrippingUserContextIdAndFirstPartyDomain();
NS_ENSURE_TRUE(principal, nullptr);
return principal.forget();
}
void
PermissionStatus::PermissionChanged()
{
auto oldState = mState;
UpdateState();
if (mState != oldState) {
RefPtr<AsyncEventDispatcher> eventDispatcher =
new AsyncEventDispatcher(this, NS_LITERAL_STRING("change"), false);
eventDispatcher->PostDOMEvent();
}
}
} // namespace dom
} // namespace mozilla

View file

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_PermissionStatus_h_
#define mozilla_dom_PermissionStatus_h_
#include "mozilla/dom/PermissionsBinding.h"
#include "mozilla/dom/PermissionStatusBinding.h"
#include "mozilla/DOMEventTargetHelper.h"
namespace mozilla {
namespace dom {
class PermissionObserver;
class PermissionStatus final
: public DOMEventTargetHelper
{
friend class PermissionObserver;
public:
static already_AddRefed<PermissionStatus> Create(nsPIDOMWindowInner* aWindow,
PermissionName aName,
ErrorResult& aRv);
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
PermissionState State() const { return mState; }
IMPL_EVENT_HANDLER(change)
private:
~PermissionStatus();
PermissionStatus(nsPIDOMWindowInner* aWindow, PermissionName aName);
nsresult Init();
nsresult UpdateState();
already_AddRefed<nsIPrincipal> GetPrincipal() const;
void PermissionChanged();
PermissionName mName;
PermissionState mState;
RefPtr<PermissionObserver> mObserver;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_permissionstatus_h_

View file

@ -0,0 +1,62 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "PermissionUtils.h"
namespace mozilla {
namespace dom {
const char* kPermissionTypes[] = {
"geo",
"desktop-notification",
// Alias `push` to `desktop-notification`.
"desktop-notification"
};
// `-1` for the last null entry.
const size_t kPermissionNameCount =
MOZ_ARRAY_LENGTH(PermissionNameValues::strings) - 1;
static_assert(MOZ_ARRAY_LENGTH(kPermissionTypes) == kPermissionNameCount,
"kPermissionTypes and PermissionName count should match");
const char*
PermissionNameToType(PermissionName aName)
{
MOZ_ASSERT((size_t)aName < ArrayLength(kPermissionTypes));
return kPermissionTypes[static_cast<size_t>(aName)];
}
Maybe<PermissionName>
TypeToPermissionName(const char* aType)
{
for (size_t i = 0; i < ArrayLength(kPermissionTypes); ++i) {
if (!strcmp(aType, kPermissionTypes[i])) {
return Some(static_cast<PermissionName>(i));
}
}
return Nothing();
}
PermissionState
ActionToPermissionState(uint32_t aAction)
{
switch (aAction) {
case nsIPermissionManager::ALLOW_ACTION:
return PermissionState::Granted;
case nsIPermissionManager::DENY_ACTION:
return PermissionState::Denied;
default:
case nsIPermissionManager::PROMPT_ACTION:
return PermissionState::Prompt;
}
}
} // namespace dom
} // namespace mozilla

View file

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_PermissionUtils_h_
#define mozilla_dom_PermissionUtils_h_
#include "mozilla/dom/PermissionsBinding.h"
#include "mozilla/dom/PermissionStatusBinding.h"
#include "mozilla/Maybe.h"
namespace mozilla {
namespace dom {
const char* PermissionNameToType(PermissionName aName);
Maybe<PermissionName> TypeToPermissionName(const char* aType);
PermissionState ActionToPermissionState(uint32_t aAction);
} // namespace dom
} // namespace mozilla
#endif

View file

@ -0,0 +1,181 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "mozilla/dom/Permissions.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PermissionsBinding.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/Services.h"
#include "nsIPermissionManager.h"
#include "PermissionUtils.h"
namespace mozilla {
namespace dom {
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Permissions)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(Permissions)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Permissions)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Permissions, mWindow)
Permissions::Permissions(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow)
{
}
Permissions::~Permissions()
{
}
JSObject*
Permissions::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PermissionsBinding::Wrap(aCx, this, aGivenProto);
}
namespace {
already_AddRefed<PermissionStatus>
CreatePermissionStatus(JSContext* aCx,
JS::Handle<JSObject*> aPermission,
nsPIDOMWindowInner* aWindow,
ErrorResult& aRv)
{
PermissionDescriptor permission;
JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aPermission));
if (NS_WARN_IF(!permission.Init(aCx, value))) {
aRv.NoteJSContextException(aCx);
return nullptr;
}
switch (permission.mName) {
case PermissionName::Geolocation:
case PermissionName::Notifications:
case PermissionName::Push:
return PermissionStatus::Create(aWindow, permission.mName, aRv);
default:
MOZ_ASSERT_UNREACHABLE("Unhandled type");
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
return nullptr;
}
}
} // namespace
already_AddRefed<Promise>
Permissions::Query(JSContext* aCx,
JS::Handle<JSObject*> aPermission,
ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
if (!global) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
RefPtr<PermissionStatus> status =
CreatePermissionStatus(aCx, aPermission, mWindow, aRv);
if (NS_WARN_IF(aRv.Failed())) {
MOZ_ASSERT(!status);
return nullptr;
}
MOZ_ASSERT(status);
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
promise->MaybeResolve(status);
return promise.forget();
}
/* static */ nsresult
Permissions::RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType)
{
MOZ_ASSERT(XRE_IsParentProcess());
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if (NS_WARN_IF(!permMgr)) {
return NS_ERROR_FAILURE;
}
return permMgr->RemoveFromPrincipal(aPrincipal, aPermissionType);
}
already_AddRefed<Promise>
Permissions::Revoke(JSContext* aCx,
JS::Handle<JSObject*> aPermission,
ErrorResult& aRv)
{
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mWindow);
if (!global) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
PermissionDescriptor permission;
JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aPermission));
if (NS_WARN_IF(!permission.Init(aCx, value))) {
aRv.NoteJSContextException(aCx);
return nullptr;
}
RefPtr<Promise> promise = Promise::Create(global, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsCOMPtr<nsIDocument> document = mWindow->GetExtantDoc();
if (!document) {
promise->MaybeReject(NS_ERROR_UNEXPECTED);
return promise.forget();
}
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
if (NS_WARN_IF(!permMgr)) {
promise->MaybeReject(NS_ERROR_FAILURE);
return promise.forget();
}
const char* permissionType = PermissionNameToType(permission.mName);
nsresult rv;
if (XRE_IsParentProcess()) {
rv = RemovePermission(document->NodePrincipal(), permissionType);
} else {
// Permissions can't be removed from the content process. Send a message
// to the parent; `ContentParent::RecvRemovePermission` will call
// `RemovePermission`.
ContentChild::GetSingleton()->SendRemovePermission(
IPC::Principal(document->NodePrincipal()), nsDependentCString(permissionType), &rv);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
promise->MaybeReject(rv);
return promise.forget();
}
RefPtr<PermissionStatus> status =
CreatePermissionStatus(aCx, aPermission, mWindow, aRv);
if (NS_WARN_IF(aRv.Failed())) {
MOZ_ASSERT(!status);
return nullptr;
}
MOZ_ASSERT(status);
promise->MaybeResolve(status);
return promise.forget();
}
} // namespace dom
} // namespace mozilla

View file

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_dom_Permissions_h_
#define mozilla_dom_Permissions_h_
#include "nsISupports.h"
#include "nsPIDOMWindow.h"
#include "nsWrapperCache.h"
namespace mozilla {
class ErrorResult;
namespace dom {
class Promise;
class Permissions final
: public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Permissions)
explicit Permissions(nsPIDOMWindowInner* aWindow);
nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
already_AddRefed<Promise> Query(JSContext* aCx,
JS::Handle<JSObject*> aPermission,
ErrorResult& aRv);
static nsresult RemovePermission(nsIPrincipal* aPrincipal, const char* aPermissionType);
already_AddRefed<Promise> Revoke(JSContext* aCx,
JS::Handle<JSObject*> aPermission,
ErrorResult& aRv);
private:
~Permissions();
nsCOMPtr<nsPIDOMWindowInner> mWindow;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_permissions_h_

39
dom/permission/moz.build Normal file
View file

@ -0,0 +1,39 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXPORTS.mozilla.dom += [
'Permissions.h',
'PermissionStatus.h',
]
UNIFIED_SOURCES += [
'PermissionObserver.cpp',
'Permissions.cpp',
'PermissionStatus.cpp',
'PermissionUtils.cpp',
]
EXTRA_COMPONENTS += [
'PermissionPromptService.js',
'PermissionPromptService.manifest',
'PermissionSettings.js',
'PermissionSettings.manifest',
]
EXTRA_JS_MODULES += [
'PermissionSettings.jsm',
]
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
if CONFIG['MOZ_TIME_MANAGER']:
MOCHITEST_MANIFESTS += ['tests/mochitest-time.ini']
FINAL_LIBRARY = 'xul'
include('/ipc/chromium/chromium-config.mozbuild')

View file

@ -0,0 +1,2 @@
<h1>I'm just a support file</h1>
<p>I get loaded to do permission testing.</p>

View file

@ -0,0 +1,224 @@
/** Test for Bug 815105 **/
/*
* gData is an array of object that tests using this framework must pass in
* The current tests only pass in a single element array. Each test in
* gData is executed by the framework for a given file
*
* Fields in gData object
* perms (required) Array of Strings
* list of permissions that this test will need. See
* http://dxr.mozilla.org/mozilla-central/source/dom/apps/src/PermissionsTable.jsm
* These permissions are added after a sanity check and removed at
* test conclusion
*
* obj (required for default verifier) String
* The name of the window.navigator object used for accessing the
* WebAPI during the tests
*
* webidl (required for default verifier) String
* idl (required for default verifier) String
* Only one of webidl / idl is required
* The IDL describing the navigator object. The returned object
* during tests /must/ be an instanceof this
*
* skip (optional) Array of Strings
* A list of navigator.userAgent's to skip the second part of tests
* on. The tests still verify that you can't get obj on those
* platforms without permissions, however it is expected that adding
* the permission still won't allow access to those objects
*
* settings (optional) Array of preference tuples
* A list of settings that need to be set before this API is
* enabled. Note the settings are set before the sanity check is
* performed. If an API gates access only by preferences, then it
* will fail the initial test
*
* verifier (optional) Function
* A function used to test whether a WebAPI is accessible or not.
* The function takes a success and failure callback which both
* accept a msg argument. msg is surfaced up to the top level tests
* A default verifier is provided which only attempts to access
* the navigator object.
*
* needParentPerm (optional) Boolean
* Whether or not the parent frame requires these permissions as
* well. Otherwise the test process may be killed.
*/
SimpleTest.waitForExplicitFinish();
var expand = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").expandPermissions;
const permTable = SpecialPowers.Cu.import("resource://gre/modules/PermissionsTable.jsm").PermissionsTable;
const TEST_DOMAIN = "http://example.org";
const SHIM_PATH = "/tests/dom/permission/tests/file_shim.html"
var gContent = document.getElementById('content');
//var gData; defined in external files
var gCurrentTest = 0;
var gRemainingTests;
var pendingTests = {};
function PermTest(aData) {
var self = this;
var skip = aData.skip || false;
this.step = 0;
this.data = aData;
this.isSkip = skip &&
skip.some(function (el) {
return navigator.
userAgent.toLowerCase().
indexOf(el.toLowerCase()) != -1;
});
this.setupParent = false;
this.perms = expandPermissions(aData.perm);
this.id = gCurrentTest++;
this.iframe = null;
// keep a reference to this for eventhandler
pendingTests[this.id] = this;
this.createFrame = function() {
if (self.iframe) {
gContent.removeChild(self.iframe);
}
var iframe = document.createElement('iframe');
iframe.setAttribute('id', 'testframe' + self.step + self.perms)
iframe.setAttribute('remote', true);
iframe.src = TEST_DOMAIN + SHIM_PATH;
iframe.addEventListener('load', function _iframeLoad() {
iframe.removeEventListener('load', _iframeLoad);
// check permissions are correct
var allow = (self.step == 0 ? false : true);
self.perms.forEach(function (el) {
try {
var res = SpecialPowers.hasPermission(el, SpecialPowers.wrap(iframe)
.contentDocument);
is(res, allow, (allow ? "Has " : "Doesn't have ") + el);
} catch(e) {
ok(false, "failed " + e);
}
});
var msg = {
id: self.id,
step: self.step++,
testdata: self.data,
}
// start the tests
iframe.contentWindow.postMessage(msg, "*");
});
self.iframe = iframe;
gContent.appendChild(iframe);
}
this.next = function () {
switch(self.step) {
case 0:
self.createFrame();
break;
case 1:
// add permissions
addPermissions(self.perms, SpecialPowers.
wrap(self.iframe).
contentDocument,
self.createFrame.bind(self));
break;
case 2:
if (self.iframe) {
gContent.removeChild(self.iframe);
}
checkFinish();
break;
default:
ok(false, "Should not be reached");
break
}
}
this.start = function() {
// some permissions need parent to have permission as well
if (!self.setupParent && self.data.needParentPerm &&
!SpecialPowers.isMainProcess()) {
self.setupParent = true;
addPermissions(self.perms, window.document, self.start.bind(self));
} else if (self.data.settings && self.data.settings.length) {
SpecialPowers.pushPrefEnv({'set': self.data.settings.slice(0)},
self.next.bind(self));
} else {
self.next();
}
}
}
function addPermissions(aPerms, aDoc, aCallback) {
var permList = [];
aPerms.forEach(function (el) {
var obj = {'type': el,
'allow': 1,
'context': aDoc};
permList.push(obj);
});
SpecialPowers.pushPermissions(permList, aCallback);
}
function expandPermissions(aPerms) {
var perms = [];
aPerms.forEach(function(el) {
var access = permTable[el].access ? "readwrite" : null;
var expanded = expand(el, access);
for (let i = 0; i < expanded.length; i++) {
perms.push(SpecialPowers.unwrap(expanded[i]));
}
});
return perms;
}
function msgHandler(evt) {
var data = evt.data;
var test = pendingTests[data.id];
/*
* step 2 of tests should fail on
* platforms which are skipped
*/
if (test.isSkip && test.step == 2) {
todo(data.result, data.msg);
} else {
ok(data.result, data.msg);
}
if (test) {
test.next();
} else {
ok(false, "Received unknown id " + data.id);
checkFinish();
}
}
function checkFinish() {
if (--gRemainingTests) {
gTestRunner.next();
} else {
window.removeEventListener('message', msgHandler);
SimpleTest.finish();
}
}
function runTest() {
gRemainingTests = Object.keys(gData).length;
for (var test in gData) {
var test = new PermTest(gData[test]);
test.start();
yield undefined;
}
}
var gTestRunner = runTest();
window.addEventListener('load', function() { gTestRunner.next(); }, false);
window.addEventListener('message', msgHandler, false);

View file

@ -0,0 +1,99 @@
<html>
<head>
<script type="application/javascript;version=1.8">
function TestData(aOpts) {
for (var opt in aOpts) {
if (aOpts.hasOwnProperty(opt)) {
this[opt] = aOpts[opt];
}
}
}
TestData.prototype = {
getObj: function() {
if (!this.obj) {
return null;
}
// only one of the 2 should be set
if ((this.idl && this.webidl) ||
(!this.idl && !this.webidl)) {
return null;
}
// split on . to allow nested props
var props = this.obj.split(".");
var obj = window.navigator;
for (var i = 0; i < props.length && obj !== undefined; i++) {
obj = obj[props[i]];
}
if ((this.webidl && obj instanceof window[this.webidl]) ||
(this.idl && obj instanceof SpecialPowers.Ci[this.idl])) {
return obj;
} else {
return null;
}
},
// default verifier
verifier: function(success, failure) {
try {
if (this.getObj()) {
success(this.perm);
} else {
failure("Did not receive proper object");
}
} catch (e) {
failure("Received exception!: " + e);
}
},
}
function receiveMessage(e) {
var src = e.source;
var step = e.data.step;
var id = e.data.id;
var data = new TestData(e.data.testdata);
var success, failure;
function reply(res, msg) {
window.removeEventListener("message", receiveMessage, false);
src.postMessage({result: res, msg: msg,
id: id}, "*");
}
function _success(msg) {
reply(true, msg);
}
function _failure(msg) {
reply(false, msg);
}
// flip success and failure around for precheck
if (step == 0) {
success = _failure;
failure = _success;
} else {
success = _success;
failure = _failure;
}
if (data.verifier instanceof Function) {
data.verifier(success, failure);
} else {
// import toSource() function to global
eval(data.verifier);
verifier.bind(data, success, failure)();
}
}
window.addEventListener("message", receiveMessage, false);
</script>
</head>
<body>
<div id="content" style="display: none"></div>
</body>
</html>

View file

@ -0,0 +1 @@
[test_time.html]

View file

@ -0,0 +1,31 @@
[DEFAULT]
support-files =
file_framework.js
file_shim.html
file_empty.html
[test_browser.html]
skip-if = true
[test_idle.html]
# skip-if = (toolkit == 'gonk' && debug) #debug-only failure
skip-if = true
[test_permissions.html]
skip-if = true
[test_permissions_api.html]
[test_power.html]
skip-if = true
[test_presentation-device-manage.html]
skip-if = true
[test_systemXHR.html]
[test_tcp-socket.html]
skip-if = true
[test_udp-socket.html]
skip-if = true
[test_keyboard.html]
# skip-if = toolkit == 'android'
skip-if = true
[test_input-manage.html]
# skip-if = toolkit == 'android'
skip-if = true
[test_wifi-manage.html]
skip-if = true

View file

@ -0,0 +1,49 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', 'true');
iframe.src = "http://example.org/";
iframe.addEventListener('load', function() {
iframe.removeEventListener('load', arguments.callee);
if (iframe.getScreenshot && typeof iframe.getScreenshot == "function") {
success("Got mozbrowser");
} else {
failure("Didn't get mozbrowser") ;
}
});
document.getElementById('content').appendChild(iframe);
}
var gData = [
{
perm: ["browser"],
needParentPerm: true,
settings: [["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true]],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
/*
* embed-apps allows us to create app iframes,
* creator must also have the browser permission
*/
function verifier(success, failure) {
var iframe = document.createElement('iframe');
iframe.setAttribute('mozbrowser', '');
iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
iframe.src = "http://example.org/";
iframe.addEventListener('load', function() {
var appStatus = SpecialPowers.wrap(iframe)
.contentDocument.nodePrincipal.appStatus;
if (appStatus != SpecialPowers.Ci
.nsIPrincipal.APP_STATUS_NOT_INSTALLED) {
success("Got mozapp");
} else {
failure("Didn't get mozapp") ;
}
});
document.getElementById('content').appendChild(iframe);
}
var gData = [
{
perm: ["embed-apps", "browser"],
/*
* Android doesn't have working apps
* Mobile is for B2G which has a weird testing setup
* the app iframe gets embed in the test-container iframe
* which returns APP_STATUS_NOT_INSTALLED
*/
skip: ["Android", "Mobile"],
settings: [["dom.mozBrowserFramesEnabled", true]],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
try {
var obs = {
time: 1,
onidle: function() {
window.navigator.removeIdleObserver(obs);
},
}
// addIdleObserver throws if prinicpal doesn't have the permission
window.navigator.addIdleObserver(obs);
success("idle");
} catch (e) {
failure("Got an exception " + e);
}
}
var gData = [
{
perm: ["idle"],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,69 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=920977
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 920977 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=920977">Mozilla Bug 920977 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
try {
if (!this.getObj()) {
failure("Did not receive proper object");
return;
}
} catch (e) {
failure("Received exception!: " + e);
return;
}
try {
this.getObj().removeFocus();
} catch (e) {
failure("Received exception!: " + e);
return;
}
var iframe = document.createElement("iframe");
iframe.setAttribute("mozbrowser", true);
iframe.src = "http://example.org/";
iframe.addEventListener("load", function() {
iframe.removeEventListener("load", arguments.callee);
if (iframe.setInputMethodActive &&
typeof iframe.setInputMethodActive == "function") {
success("Got setInputMethodActive");
} else {
failure("Didn't get setInputMethodActive") ;
}
});
document.getElementById('content').appendChild(iframe);
}
var gData = [
{
perm: ["input-manage", "browser"],
needParentPerm: true,
obj: "mozInputMethod",
webidl: "MozInputMethod",
settings: [["dom.mozInputMethod.enabled", true],
["dom.mozBrowserFramesEnabled", true],
["network.disable.ipc.security", true]],
verifier: verifier.toSource()
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,51 @@
-<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=920977
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 920977 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=920977">Mozilla Bug 920977 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
try {
if (!this.getObj()) {
failure("Did not receive proper object");
return;
}
} catch (e) {
failure("Received exception!: " + e);
return;
}
try {
this.getObj().removeFocus();
failure("Should receive exception when accessing system only method.!");
} catch (e) {
success(this.perm);
}
}
var gData = [
{
perm: ["input"],
obj: "mozInputMethod",
webidl: "MozInputMethod",
settings: [["dom.mozInputMethod.enabled", true]],
verifier: verifier.toSource()
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
var gData = [
{
perm: ["networkstats-manage"],
obj: "mozNetworkStats",
webidl: "MozNetworkStatsManager",
settings: [["dom.mozNetworkStats.enabled", true]],
},
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
var gData = [
{
perm: ["permissions"],
obj: "mozPermissionSettings",
webidl: "PermissionSettings",
settings: [["dom.mozPermissionSettings.enabled", true]],
},
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,206 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Permissions API</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>
<pre id="test"></pre>
<script type="application/javascript;version=1.8">
/*globals SpecialPowers, SimpleTest, is, ok, */
'use strict';
const {
UNKNOWN_ACTION,
PROMPT_ACTION,
ALLOW_ACTION,
DENY_ACTION
} = SpecialPowers.Ci.nsIPermissionManager;
SimpleTest.waitForExplicitFinish();
const PERMISSIONS = [{
name: 'geolocation',
type: 'geo'
}, {
name: 'notifications',
type: 'desktop-notification'
}, {
name: 'push',
type: 'desktop-notification'
}, ];
const UNSUPPORTED_PERMISSIONS = [
'foobarbaz', // Not in spec, for testing only.
'midi',
];
// Create a closure, so that tests are run on the correct window object.
function createPermissionTester(aWindow) {
return {
setPermissions(allow) {
const permissions = PERMISSIONS.map(({ type }) => {
return {
type,
allow,
'context': aWindow.document
};
});
return new Promise((resolve) => {
SpecialPowers.popPermissions(() => {
SpecialPowers.pushPermissions(permissions, resolve);
});
});
},
revokePermissions() {
const promisesToRevoke = PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.revoke({ name })
.then(
({ state }) => is(state, 'prompt', `correct state for '${name}'`),
() => ok(false, `revoke should not have rejected for '${name}'`)
);
});
return Promise.all(promisesToRevoke);
},
revokeUnsupportedPermissions() {
const promisesToRevoke = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.revoke({ name })
.then(
() => ok(false, `revoke should not have resolved for '${name}'`),
error => is(error.name, 'TypeError', `revoke should have thrown TypeError for '${name}'`)
);
});
return Promise.all(promisesToRevoke);
},
checkPermissions(state) {
const promisesToQuery = PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.query({ name })
.then(
() => is(state, state, `correct state for '${name}'`),
() => ok(false, `query should not have rejected for '${name}'`)
);
});
return Promise.all(promisesToQuery);
},
checkUnsupportedPermissions() {
const promisesToQuery = UNSUPPORTED_PERMISSIONS.map(({ name }) => {
return aWindow.navigator.permissions
.query({ name })
.then(
() => ok(false, `query should not have resolved for '${name}'`),
error => {
is(error.name, 'TypeError',
`query should have thrown TypeError for '${name}'`);
}
);
});
return Promise.all(promisesToQuery);
},
promiseStateChanged(name, state) {
return aWindow.navigator.permissions
.query({ name })
.then(status => {
return new Promise( resolve => {
status.onchange = () => {
status.onchange = null;
is(status.state, state, `state changed for '${name}'`);
resolve();
};
});
},
() => ok(false, `query should not have rejected for '${name}'`));
},
testStatusOnChange() {
return new Promise((resolve) => {
SpecialPowers.popPermissions(() => {
const permission = 'geolocation';
const promiseGranted = this.promiseStateChanged(permission, 'granted');
this.setPermissions(ALLOW_ACTION);
promiseGranted.then(() => {
const promisePrompt = this.promiseStateChanged(permission, 'prompt');
SpecialPowers.popPermissions();
return promisePrompt;
}).then(resolve);
});
});
},
testInvalidQuery() {
return aWindow.navigator.permissions
.query({ name: 'invalid' })
.then(
() => ok(false, 'invalid query should not have resolved'),
() => ok(true, 'invalid query should have rejected')
);
},
testInvalidRevoke() {
return aWindow.navigator.permissions
.revoke({ name: 'invalid' })
.then(
() => ok(false, 'invalid revoke should not have resolved'),
() => ok(true, 'invalid revoke should have rejected')
);
},
};
}
function enablePrefs() {
const ops = {
'set': [
['dom.permissions.revoke.enable', true],
],
};
return SpecialPowers.pushPrefEnv(ops);
}
function createIframe() {
return new Promise((resolve) => {
const iframe = document.createElement('iframe');
iframe.src = 'file_empty.html';
iframe.onload = () => resolve(iframe.contentWindow);
document.body.appendChild(iframe);
});
}
debugger;
window.onload = () => {
enablePrefs()
.then(createIframe)
.then(createPermissionTester)
.then((tester) => {
return tester
.checkUnsupportedPermissions()
.then(() => tester.setPermissions(UNKNOWN_ACTION))
.then(() => tester.checkPermissions('prompt'))
.then(() => tester.setPermissions(PROMPT_ACTION))
.then(() => tester.checkPermissions('prompt'))
.then(() => tester.setPermissions(ALLOW_ACTION))
.then(() => tester.checkPermissions('granted'))
.then(() => tester.setPermissions(DENY_ACTION))
.then(() => tester.checkPermissions('denied'))
.then(() => tester.testStatusOnChange())
.then(() => tester.testInvalidQuery())
.then(() => tester.revokeUnsupportedPermissions())
.then(() => tester.revokePermissions())
.then(() => tester.checkPermissions('prompt'))
.then(() => tester.testInvalidRevoke());
})
.then(SimpleTest.finish)
.catch((e) => {
ok(false, `Unexpected error ${e}`);
SimpleTest.finish();
});
};
</script>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
var gData = [
{
perm: ["power"],
obj: "mozPower",
webidl: "MozPowerManager",
},
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1080474
-->
<head>
<meta charset="utf-8">
<title>Test for presentation-device-manage permission</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1080474">test presentation-device-manage</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
if (window.navigator.mozPresentationDeviceInfo) {
success("Got mozPresentationDeviceInfo object!");
} else {
failure("Failed to get mozPresentationDeviceInfo object!");
}
}
var gData = [
{
perm: ["presentation-device-manage"],
settings: [["dom.presentation.enabled", true]],
obj: "mozPresentationDeviceInfo",
webidl: "PresentationDeviceInfoManager"
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
var xhr = new XMLHttpRequest({mozSystem: true});
if (xhr.mozSystem === true) {
success("systemXHR");
} else {
failure("Couldn't create systemXHR");
}
}
var gData = [
{
perm: ["systemXHR"],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
/* mozTCPSocket only returns null on window init
* if the permission isn't set
*/
function verifier(success, failure) {
try {
var conn = navigator.mozTCPSocket.open("http://mochi.test/", 80);
if (conn) {
if (conn instanceof window.TCPSocket) {
success("Opened connection");
} else {
failure("connection didn't match interface");
}
} else {
failure("failed to open connection");
}
} catch (e) {
failure("Got an exception " + e);
}
}
var gData = [
{
perm: ["tcp-socket"],
needParentPerm: true,
settings: [["dom.mozTCPSocket.enabled", true]],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
var gData = [
{
perm: ["time"],
obj: "mozTime",
webidl: "MozTimeManager",
},
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=745283
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 745283 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=745283">Mozilla Bug 745283 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
try {
var socket = new UDPSocket();
if (socket) {
success("Opened socket");
} else {
failure("failed to open socket");
}
} catch (e) {
failure("Got an exception " + e);
}
}
var gData = [
{
perm: ["udp-socket"],
needParentPerm: true,
obj: "UDPSocket",
webidl: "UDPSocket",
settings: [["dom.udpsocket.enabled", true]],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=815105
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 815105 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=815105">Mozilla Bug 815105 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
try {
this.getObj().enabled;
success("Got wifi");
} catch (e) {
failure("Got an exception " + e);
}
}
var gData = [
{
perm: ["wifi-manage"],
needParentPerm: true,
obj: "mozWifiManager",
webidl: "MozWifiManager",
verifier: verifier.toSource(),
},
]
</script>
</pre>
</body>
</html>

View file

@ -0,0 +1,73 @@
var Cu = Components.utils;
const READWRITE = "readwrite";
const UNKNOWN = "foobar";
var gData = [
// test normal expansion
{
permission: "contacts",
access: READWRITE,
expected: ["contacts-read", "contacts-create",
"contacts-write"]
},
// test additional expansion and access not having read+create+write
{
permission: "settings",
access: READWRITE,
expected: ["settings-read", "settings-write",
"settings-api-read", "settings-api-write",
"indexedDB-chrome-settings-read",
"indexedDB-chrome-settings-write"]
},
// test unknown access
{
permission: "contacts",
access: UNKNOWN,
expected: []
},
// test unknown permission
{
permission: UNKNOWN,
access: READWRITE,
expected: []
}
];
// check if 2 arrays contain the same elements
function do_check_set_eq(a1, a2) {
do_check_eq(a1.length, a2.length)
Array.sort(a1);
Array.sort(a2);
for (let i = 0; i < a1.length; ++i) {
do_check_eq(a1[i], a2[i])
}
}
function test_substitute_does_not_break_substituted(scope) {
const Ci = Components.interfaces;
// geolocation-noprompt substitutes for geolocation ...
do_check_eq(scope.PermissionsTable["geolocation-noprompt"].substitute[0],
"geolocation");
// ... and sets silent allow ...
do_check_eq(scope.PermissionsTable["geolocation-noprompt"].certified,
Ci.nsIPermissionManager.ALLOW_ACTION)
// ... which works ...
do_check_false(scope.isExplicitInPermissionsTable("geolocation-noprompt", Ci.nsIPrincipal.APP_STATUS_CERTIFIED));
// ... but does not interfere with geolocation's PROMPT value
do_check_true(scope.isExplicitInPermissionsTable("geolocation", Ci.nsIPrincipal.APP_STATUS_CERTIFIED));
}
function run_test() {
var scope = {};
Cu.import("resource://gre/modules/PermissionsTable.jsm", scope);
for (var i = 0; i < gData.length; i++) {
var perms = scope.expandPermissions(gData[i].permission,
gData[i].access);
do_check_set_eq(perms, gData[i].expected);
}
test_substitute_does_not_break_substituted(scope);
}

View file

@ -0,0 +1,5 @@
[DEFAULT]
head =
tail =
[test_bug808734.js]