Bug 1159641, Part 1 - Skip the permission check in pushManager.getSubscription(). r=mt

This commit is contained in:
Kit Cambridge 2015-10-30 09:37:22 -07:00
parent bba9cb6be5
commit 80de1b909d
4 changed files with 165 additions and 137 deletions

View File

@ -67,123 +67,59 @@ Push.prototype = {
askPermission: function (aAllowCallback, aCancelCallback) {
debug("askPermission");
let permValue = Services.perms.testExactPermissionFromPrincipal(
this._principal,
"desktop-notification"
);
return this.createPromise((resolve, reject) => {
function permissionDenied() {
reject("PermissionDeniedError");
}
if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
aAllowCallback();
return;
}
let permission = Ci.nsIPermissionManager.UNKNOWN_ACTION;
try {
permission = this._testPermission();
} catch (e) {
permissionDenied();
return;
}
if (permValue == Ci.nsIPermissionManager.DENY_ACTION) {
aCancelCallback();
return;
}
// Create an array with a single nsIContentPermissionType element.
let type = {
type: "desktop-notification",
access: null,
options: [],
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
};
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
typeArray.appendElement(type, false);
// create a nsIContentPermissionRequest
let request = {
types: typeArray,
principal: this._principal,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
allow: function() {
let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_GRANTED");
histogram.add();
aAllowCallback();
},
cancel: function() {
let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_DENIED");
histogram.add();
aCancelCallback();
},
window: this._window
};
let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_REQUESTED");
histogram.add(1);
// Using askPermission from nsIDOMWindowUtils that takes care of the
// remoting if needed.
let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.askPermission(request);
},
getEndpointResponse: function(fn) {
debug("GetEndpointResponse " + fn.toSource());
let that = this;
let p = this.createPromise(function(resolve, reject) {
this.askPermission(
() => {
fn(that._scope, that._principal, {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushEndpointCallback]),
onPushEndpoint: function(ok, endpoint, keyLen, key) {
if (ok === Cr.NS_OK) {
if (endpoint) {
let sub;
if (keyLen) {
let publicKey = new ArrayBuffer(keyLen);
let keyView = new Uint8Array(publicKey);
keyView.set(key);
sub = new that._window.PushSubscription(endpoint,
that._scope,
publicKey);
} else {
sub = new that._window.PushSubscription(endpoint,
that._scope,
null);
}
sub.setPrincipal(that._principal);
resolve(sub);
} else {
resolve(null);
}
} else {
reject("AbortError");
}
}
});
},
() => {
reject("PermissionDeniedError");
}
);
}.bind(this));
return p;
if (permission == Ci.nsIPermissionManager.ALLOW_ACTION) {
resolve();
} else if (permission == Ci.nsIPermissionManager.DENY_ACTION) {
permissionDenied();
} else {
this._requestPermission(resolve, permissionDenied);
}
});
},
subscribe: function() {
debug("subscribe()");
let histogram = Services.telemetry.getHistogramById("PUSH_API_USED");
histogram.add(true);
return this.getEndpointResponse(this._client.subscribe.bind(this._client));
return this.askPermission().then(() =>
this.createPromise((resolve, reject) => {
let callback = new PushEndpointCallback(this, resolve, reject);
this._client.subscribe(this._scope, this._principal, callback);
})
);
},
getSubscription: function() {
debug("getSubscription()" + this._scope);
return this.getEndpointResponse(this._client.getSubscription.bind(this._client));
return this.createPromise((resolve, reject) => {
let callback = new PushEndpointCallback(this, resolve, reject);
this._client.getSubscription(this._scope, this._principal, callback);
});
},
permissionState: function() {
debug("permissionState()" + this._scope);
let p = this.createPromise((resolve, reject) => {
let permission = Ci.nsIPermissionManager.DENY_ACTION;
return this.createPromise((resolve, reject) => {
let permission = Ci.nsIPermissionManager.UNKNOWN_ACTION;
try {
permission = Services.perms.testExactPermissionFromPrincipal(
this._principal, "desktop-notification");
permission = this._testPermission();
} catch(e) {
reject();
return;
@ -197,8 +133,85 @@ Push.prototype = {
}
resolve(pushPermissionStatus);
});
return p;
},
_testPermission: function() {
return Services.perms.testExactPermissionFromPrincipal(
this._principal, "desktop-notification");
},
_requestPermission: function(allowCallback, cancelCallback) {
// Create an array with a single nsIContentPermissionType element.
let type = {
type: "desktop-notification",
access: null,
options: [],
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType]),
};
let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
typeArray.appendElement(type, false);
// create a nsIContentPermissionRequest
let request = {
types: typeArray,
principal: this._principal,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
allow: function() {
let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_GRANTED");
histogram.add();
allowCallback();
},
cancel: function() {
let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_DENIED");
histogram.add();
cancelCallback();
},
window: this._window,
};
let histogram = Services.telemetry.getHistogramById("PUSH_API_PERMISSION_REQUESTED");
histogram.add(1);
// Using askPermission from nsIDOMWindowUtils that takes care of the
// remoting if needed.
let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.askPermission(request);
},
};
function PushEndpointCallback(pushManager, resolve, reject) {
this.pushManager = pushManager;
this.resolve = resolve;
this.reject = reject;
}
PushEndpointCallback.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushEndpointCallback]),
onPushEndpoint: function(ok, endpoint, keyLen, key) {
let {pushManager} = this;
if (!Components.isSuccessCode(ok)) {
this.reject("AbortError");
return;
}
if (!endpoint) {
this.resolve(null);
return;
}
let publicKey = null;
if (keyLen) {
publicKey = new ArrayBuffer(keyLen);
let keyView = new Uint8Array(publicKey);
keyView.set(key);
}
let sub = new pushManager._window.PushSubscription(endpoint,
pushManager._scope,
publicKey);
sub.setPrincipal(pushManager._principal);
this.resolve(sub);
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Push]);

View File

@ -33,6 +33,39 @@ namespace dom {
using namespace workers;
namespace {
nsresult
GetPermissionState(nsIPrincipal* aPrincipal,
PushPermissionState& aState)
{
nsCOMPtr<nsIPermissionManager> permManager =
mozilla::services::GetPermissionManager();
if (!permManager) {
return NS_ERROR_FAILURE;
}
uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
nsresult rv = permManager->TestExactPermissionFromPrincipal(
aPrincipal,
"desktop-notification",
&permission);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (permission == nsIPermissionManager::ALLOW_ACTION) {
aState = PushPermissionState::Granted;
} else if (permission == nsIPermissionManager::DENY_ACTION) {
aState = PushPermissionState::Denied;
} else {
aState = PushPermissionState::Prompt;
}
return NS_OK;
}
} // anonymous namespace
class UnsubscribeResultCallback final : public nsIUnsubscribeResultCallback
{
public:
@ -580,22 +613,20 @@ public:
RefPtr<GetSubscriptionCallback> callback = new GetSubscriptionCallback(mProxy, mScope);
nsCOMPtr<nsIPermissionManager> permManager =
mozilla::services::GetPermissionManager();
if (!permManager) {
nsCOMPtr<nsIPrincipal> principal = mProxy->GetWorkerPrivate()->GetPrincipal();
PushPermissionState state;
nsresult rv = GetPermissionState(principal, state);
if (NS_FAILED(rv)) {
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr);
return NS_OK;
}
nsCOMPtr<nsIPrincipal> principal = mProxy->GetWorkerPrivate()->GetPrincipal();
uint32_t permission = nsIPermissionManager::DENY_ACTION;
nsresult rv = permManager->TestExactPermissionFromPrincipal(
principal,
"desktop-notification",
&permission);
if (NS_WARN_IF(NS_FAILED(rv)) || permission != nsIPermissionManager::ALLOW_ACTION) {
if (state != PushPermissionState::Granted) {
if (mAction == WorkerPushManager::GetSubscriptionAction) {
callback->OnPushEndpoint(NS_OK, EmptyString(), 0, nullptr);
return NS_OK;
}
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr);
return NS_OK;
}
@ -728,27 +759,11 @@ public:
return NS_OK;
}
nsCOMPtr<nsIPermissionManager> permManager =
mozilla::services::GetPermissionManager();
nsresult rv = NS_ERROR_FAILURE;
PushPermissionState state = PushPermissionState::Prompt;
if (permManager) {
uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
rv = permManager->TestExactPermissionFromPrincipal(
mProxy->GetWorkerPrivate()->GetPrincipal(),
"desktop-notification",
&permission);
if (NS_SUCCEEDED(rv)) {
if (permission == nsIPermissionManager::ALLOW_ACTION) {
state = PushPermissionState::Granted;
} else if (permission == nsIPermissionManager::DENY_ACTION) {
state = PushPermissionState::Denied;
}
}
}
PushPermissionState state;
nsresult rv = GetPermissionState(
mProxy->GetWorkerPrivate()->GetPrincipal(),
state
);
AutoJSAPI jsapi;
jsapi.Init();

View File

@ -1236,10 +1236,10 @@ this.PushService = {
if (record.isExpired()) {
return record.quotaChanged().then(isChanged => {
if (isChanged) {
return this._db.delete(record.keyID);
return this._db.delete(record.keyID).then(_ => null);
}
throw {state: 0, error: "NotFoundError"};
}).then(_ => null);
return null;
});
}
return record.toRegistration();
});

View File

@ -59,10 +59,10 @@ http://creativecommons.org/licenses/publicdomain/
var p = new Promise(function(res, rej) {
swr.pushManager.getSubscription().then(
function(pushSubscription) {
ok(false, "getSubscription() should fail because no permission for push");
is(pushSubscription, null, "getSubscription() should return null because no permission for push");
res(swr);
}, function(error) {
ok(true, "getSubscription() could not register for push notification");
ok(false, "getSubscription() could not register for push notification");
res(swr);
}
);