Bug 1635524 - Part 2: Pass oldSubscription for pushsubscriptionchange event r=asuth
Differential Revision: https://phabricator.services.mozilla.com/D234713
This commit is contained in:
@@ -12,6 +12,7 @@ interface mozIDOMWindowProxy;
|
||||
interface nsIArray;
|
||||
interface nsIInterceptedChannel;
|
||||
interface nsIPrincipal;
|
||||
interface nsIPushSubscription;
|
||||
interface nsIRunnable;
|
||||
interface nsIURI;
|
||||
%{C++
|
||||
@@ -320,7 +321,8 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
in ACString aScope,
|
||||
[optional] in Array<uint8_t> aDataBytes);
|
||||
void sendPushSubscriptionChangeEvent(in ACString aOriginAttributes,
|
||||
in ACString scope);
|
||||
in ACString scope,
|
||||
[optional] in nsIPushSubscription aOldSubscription);
|
||||
|
||||
void addListener(in nsIServiceWorkerManagerListener aListener);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
%}
|
||||
|
||||
interface nsIPrincipal;
|
||||
interface nsIPushSubscription;
|
||||
|
||||
/**
|
||||
* Fires XPCOM observer notifications and service worker events for
|
||||
@@ -43,7 +44,8 @@ interface nsIPushNotifier : nsISupports
|
||||
* `pushsubscriptionchange` event to the service worker registered for the
|
||||
* |scope|.
|
||||
*/
|
||||
void notifySubscriptionChange(in ACString scope, in nsIPrincipal principal);
|
||||
void notifySubscriptionChange(in ACString scope, in nsIPrincipal principal,
|
||||
[optional] in nsIPushSubscription oldSubscription);
|
||||
|
||||
/**
|
||||
* Fires a `push-subscription-modified` observer notification. Chrome code
|
||||
|
||||
93
dom/push/ChromePushSubscription.sys.mjs
Normal file
93
dom/push/ChromePushSubscription.sys.mjs
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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/. */
|
||||
|
||||
/** `ChromePushSubscription` instances are passed to all subscription callbacks. */
|
||||
export class ChromePushSubscription {
|
||||
#props;
|
||||
|
||||
constructor(props) {
|
||||
this.#props = props;
|
||||
}
|
||||
|
||||
QueryInterface = ChromeUtils.generateQI(["nsIPushSubscription"]);
|
||||
|
||||
/** The URL for sending messages to this subscription. */
|
||||
get endpoint() {
|
||||
return this.#props.endpoint;
|
||||
}
|
||||
|
||||
/** The last time a message was sent to this subscription. */
|
||||
get lastPush() {
|
||||
return this.#props.lastPush;
|
||||
}
|
||||
|
||||
/** The total number of messages sent to this subscription. */
|
||||
get pushCount() {
|
||||
return this.#props.pushCount;
|
||||
}
|
||||
|
||||
/** The number of remaining background messages that can be sent to this
|
||||
* subscription, or -1 of the subscription is exempt from the quota.
|
||||
*/
|
||||
get quota() {
|
||||
return this.#props.quota;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this subscription was created with the system principal.
|
||||
* System subscriptions are exempt from the background message quota and
|
||||
* permission checks.
|
||||
*/
|
||||
get isSystemSubscription() {
|
||||
return !!this.#props.systemRecord;
|
||||
}
|
||||
|
||||
/** The private key used to decrypt incoming push messages, in JWK format */
|
||||
get p256dhPrivateKey() {
|
||||
return this.#props.p256dhPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this subscription is subject to the background message
|
||||
* quota.
|
||||
*/
|
||||
quotaApplies() {
|
||||
return this.quota >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this subscription exceeded the background message quota,
|
||||
* or the user revoked the notification permission. The caller must request a
|
||||
* new subscription to continue receiving push messages.
|
||||
*/
|
||||
isExpired() {
|
||||
return this.quota === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key for encrypting messages sent to this subscription. JS
|
||||
* callers receive the key buffer as a return value, while C++ callers
|
||||
* receive the key size and buffer as out parameters.
|
||||
*/
|
||||
getKey(name) {
|
||||
switch (name) {
|
||||
case "p256dh":
|
||||
return this.#getRawKey(this.#props.p256dhKey);
|
||||
|
||||
case "auth":
|
||||
return this.#getRawKey(this.#props.authenticationSecret);
|
||||
|
||||
case "appServer":
|
||||
return this.#getRawKey(this.#props.appServerKey);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
#getRawKey(key) {
|
||||
if (!key) {
|
||||
return [];
|
||||
}
|
||||
return new Uint8Array(key);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||
import { ChromePushSubscription } from "./ChromePushSubscription.sys.mjs";
|
||||
|
||||
var isParent =
|
||||
Services.appinfo.processType === Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
|
||||
@@ -488,96 +489,6 @@ Object.assign(PushServiceContent.prototype, {
|
||||
},
|
||||
});
|
||||
|
||||
/** `ChromePushSubscription` instances are passed to all subscription callbacks. */
|
||||
class ChromePushSubscription {
|
||||
#props;
|
||||
|
||||
constructor(props) {
|
||||
this.#props = props;
|
||||
}
|
||||
|
||||
QueryInterface = ChromeUtils.generateQI(["nsIPushSubscription"]);
|
||||
|
||||
/** The URL for sending messages to this subscription. */
|
||||
get endpoint() {
|
||||
return this.#props.endpoint;
|
||||
}
|
||||
|
||||
/** The last time a message was sent to this subscription. */
|
||||
get lastPush() {
|
||||
return this.#props.lastPush;
|
||||
}
|
||||
|
||||
/** The total number of messages sent to this subscription. */
|
||||
get pushCount() {
|
||||
return this.#props.pushCount;
|
||||
}
|
||||
|
||||
/** The number of remaining background messages that can be sent to this
|
||||
* subscription, or -1 of the subscription is exempt from the quota.
|
||||
*/
|
||||
get quota() {
|
||||
return this.#props.quota;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this subscription was created with the system principal.
|
||||
* System subscriptions are exempt from the background message quota and
|
||||
* permission checks.
|
||||
*/
|
||||
get isSystemSubscription() {
|
||||
return !!this.#props.systemRecord;
|
||||
}
|
||||
|
||||
/** The private key used to decrypt incoming push messages, in JWK format */
|
||||
get p256dhPrivateKey() {
|
||||
return this.#props.p256dhPrivateKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this subscription is subject to the background message
|
||||
* quota.
|
||||
*/
|
||||
quotaApplies() {
|
||||
return this.quota >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this subscription exceeded the background message quota,
|
||||
* or the user revoked the notification permission. The caller must request a
|
||||
* new subscription to continue receiving push messages.
|
||||
*/
|
||||
isExpired() {
|
||||
return this.quota === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key for encrypting messages sent to this subscription. JS
|
||||
* callers receive the key buffer as a return value, while C++ callers
|
||||
* receive the key size and buffer as out parameters.
|
||||
*/
|
||||
getKey(name) {
|
||||
switch (name) {
|
||||
case "p256dh":
|
||||
return this.#getRawKey(this.#props.p256dhKey);
|
||||
|
||||
case "auth":
|
||||
return this.#getRawKey(this.#props.authenticationSecret);
|
||||
|
||||
case "appServer":
|
||||
return this.#getRawKey(this.#props.appServerKey);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
#getRawKey(key) {
|
||||
if (!key) {
|
||||
return [];
|
||||
}
|
||||
return new Uint8Array(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Export the correct implementation depending on whether we're running in
|
||||
// the parent or content process.
|
||||
export let Service = isParent ? PushServiceParent : PushServiceContent;
|
||||
|
||||
@@ -33,34 +33,6 @@
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
namespace {
|
||||
|
||||
nsresult GetPermissionState(nsIPrincipal* aPrincipal, PermissionState& aState) {
|
||||
nsCOMPtr<nsIPermissionManager> permManager =
|
||||
mozilla::components::PermissionManager::Service();
|
||||
|
||||
if (!permManager) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
nsresult rv = permManager->TestExactPermissionFromPrincipal(
|
||||
aPrincipal, "desktop-notification"_ns, &permission);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION ||
|
||||
Preferences::GetBool("dom.push.testing.ignorePermission", false)) {
|
||||
aState = PermissionState::Granted;
|
||||
} else if (permission == nsIPermissionManager::DENY_ACTION) {
|
||||
aState = PermissionState::Denied;
|
||||
} else {
|
||||
aState = PermissionState::Prompt;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult GetSubscriptionParams(nsIPushSubscription* aSubscription,
|
||||
nsAString& aEndpoint,
|
||||
nsTArray<uint8_t>& aRawP256dhKey,
|
||||
@@ -91,6 +63,34 @@ nsresult GetSubscriptionParams(nsIPushSubscription* aSubscription,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
nsresult GetPermissionState(nsIPrincipal* aPrincipal, PermissionState& aState) {
|
||||
nsCOMPtr<nsIPermissionManager> permManager =
|
||||
mozilla::components::PermissionManager::Service();
|
||||
|
||||
if (!permManager) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
nsresult rv = permManager->TestExactPermissionFromPrincipal(
|
||||
aPrincipal, "desktop-notification"_ns, &permission);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (permission == nsIPermissionManager::ALLOW_ACTION ||
|
||||
Preferences::GetBool("dom.push.testing.ignorePermission", false)) {
|
||||
aState = PermissionState::Granted;
|
||||
} else if (permission == nsIPermissionManager::DENY_ACTION) {
|
||||
aState = PermissionState::Denied;
|
||||
} else {
|
||||
aState = PermissionState::Prompt;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class GetSubscriptionResultRunnable final : public WorkerThreadRunnable {
|
||||
public:
|
||||
GetSubscriptionResultRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
class nsIGlobalObject;
|
||||
class nsIPrincipal;
|
||||
class nsIPushSubscription;
|
||||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
@@ -49,6 +50,12 @@ class PushManagerImpl;
|
||||
struct PushSubscriptionOptionsInit;
|
||||
class WorkerPrivate;
|
||||
|
||||
nsresult GetSubscriptionParams(nsIPushSubscription* aSubscription,
|
||||
nsAString& aEndpoint,
|
||||
nsTArray<uint8_t>& aRawP256dhKey,
|
||||
nsTArray<uint8_t>& aAuthSecret,
|
||||
nsTArray<uint8_t>& aAppServerKey);
|
||||
|
||||
class PushManager final : public nsISupports, public nsWrapperCache {
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsICategoryManager.h"
|
||||
#include "nsIPushService.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsXPCOM.h"
|
||||
@@ -66,9 +67,11 @@ PushNotifier::NotifyPush(const nsACString& aScope, nsIPrincipal* aPrincipal,
|
||||
|
||||
NS_IMETHODIMP
|
||||
PushNotifier::NotifySubscriptionChange(const nsACString& aScope,
|
||||
nsIPrincipal* aPrincipal) {
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPushSubscription* aOldSubscription) {
|
||||
NS_ENSURE_ARG(aPrincipal);
|
||||
PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal);
|
||||
PushSubscriptionChangeDispatcher dispatcher(aScope, aPrincipal,
|
||||
aOldSubscription);
|
||||
return Dispatch(dispatcher);
|
||||
}
|
||||
|
||||
@@ -311,8 +314,9 @@ bool PushMessageDispatcher::SendToChild(ContentParent* aContentActor) {
|
||||
}
|
||||
|
||||
PushSubscriptionChangeDispatcher::PushSubscriptionChangeDispatcher(
|
||||
const nsACString& aScope, nsIPrincipal* aPrincipal)
|
||||
: PushDispatcher(aScope, aPrincipal) {}
|
||||
const nsACString& aScope, nsIPrincipal* aPrincipal,
|
||||
nsIPushSubscription* aOldSubscription)
|
||||
: PushDispatcher(aScope, aPrincipal), mOldSubscription(aOldSubscription) {}
|
||||
|
||||
PushSubscriptionChangeDispatcher::~PushSubscriptionChangeDispatcher() = default;
|
||||
|
||||
@@ -334,7 +338,8 @@ nsresult PushSubscriptionChangeDispatcher::NotifyWorkers() {
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
return swm->SendPushSubscriptionChangeEvent(originSuffix, mScope);
|
||||
return swm->SendPushSubscriptionChangeEvent(originSuffix, mScope,
|
||||
mOldSubscription);
|
||||
}
|
||||
|
||||
bool PushSubscriptionChangeDispatcher::SendToParent(
|
||||
|
||||
@@ -149,13 +149,17 @@ class PushMessageDispatcher final : public PushDispatcher {
|
||||
class PushSubscriptionChangeDispatcher final : public PushDispatcher {
|
||||
public:
|
||||
PushSubscriptionChangeDispatcher(const nsACString& aScope,
|
||||
nsIPrincipal* aPrincipal);
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPushSubscription* aOldSubscription);
|
||||
~PushSubscriptionChangeDispatcher();
|
||||
|
||||
nsresult NotifyObservers() override;
|
||||
nsresult NotifyWorkers() override;
|
||||
bool SendToParent(ContentChild* aParentActor) override;
|
||||
bool SendToChild(ContentParent* aContentActor) override;
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPushSubscription> mOldSubscription;
|
||||
};
|
||||
|
||||
class PushSubscriptionModifiedDispatcher : public PushDispatcher {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
import { clearTimeout, setTimeout } from "resource://gre/modules/Timer.sys.mjs";
|
||||
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
|
||||
import { ChromePushSubscription } from "./ChromePushSubscription.sys.mjs";
|
||||
|
||||
const lazy = {};
|
||||
|
||||
@@ -661,7 +662,11 @@ export var PushService = {
|
||||
if (!record) {
|
||||
return;
|
||||
}
|
||||
lazy.gPushNotifier.notifySubscriptionChange(record.scope, record.principal);
|
||||
lazy.gPushNotifier.notifySubscriptionChange(
|
||||
record.scope,
|
||||
record.principal,
|
||||
new ChromePushSubscription(record.toSubscription())
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,6 +11,7 @@ EXTRA_COMPONENTS += [
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
"ChromePushSubscription.sys.mjs",
|
||||
"Push.sys.mjs",
|
||||
"PushBroadcastService.sys.mjs",
|
||||
"PushComponents.sys.mjs",
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
const { MockRegistrar } = ChromeUtils.importESModule(
|
||||
"resource://testing-common/MockRegistrar.sys.mjs"
|
||||
);
|
||||
const { ChromePushSubscription } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/ChromePushSubscription.sys.mjs"
|
||||
);
|
||||
|
||||
let pushService = Cc["@mozilla.org/push/Service;1"].getService(
|
||||
Ci.nsIPushService
|
||||
@@ -54,7 +57,21 @@ add_test(function test_service_instantiation() {
|
||||
equal(handlerService.observed[0].data, scope);
|
||||
|
||||
// and a subscription change.
|
||||
pushNotifier.notifySubscriptionChange(scope, principal);
|
||||
pushNotifier.notifySubscriptionChange(
|
||||
scope,
|
||||
principal,
|
||||
new ChromePushSubscription({
|
||||
endpoint: "xpcshell",
|
||||
lastPush: 0,
|
||||
pushCount: 0,
|
||||
p256dhKey: [],
|
||||
p256dhPrivateKey: [],
|
||||
authenticationSecret: [],
|
||||
appServerKey: [],
|
||||
quota: 0,
|
||||
systemRecord: true,
|
||||
})
|
||||
);
|
||||
equal(handlerService.observed.length, 2);
|
||||
equal(handlerService.observed[1].topic, pushService.subscriptionChangeTopic);
|
||||
equal(handlerService.observed[1].subject, principal);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIPushService.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
@@ -1113,7 +1114,8 @@ nsresult ServiceWorkerManager::SendPushEvent(
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::SendPushSubscriptionChangeEvent(
|
||||
const nsACString& aOriginAttributes, const nsACString& aScope) {
|
||||
const nsACString& aOriginAttributes, const nsACString& aScope,
|
||||
nsIPushSubscription* aOldSubscription) {
|
||||
OriginAttributes attrs;
|
||||
if (!attrs.PopulateFromSuffix(aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
@@ -1123,7 +1125,8 @@ ServiceWorkerManager::SendPushSubscriptionChangeEvent(
|
||||
if (!info) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return info->WorkerPrivate()->SendPushSubscriptionChangeEvent();
|
||||
return info->WorkerPrivate()->SendPushSubscriptionChangeEvent(
|
||||
aOldSubscription);
|
||||
}
|
||||
|
||||
nsresult ServiceWorkerManager::SendNotificationEvent(
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "js/Exception.h" // JS::ExceptionStack, JS::StealPendingExceptionStack
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "mozilla/dom/PushSubscriptionChangeEvent.h"
|
||||
#include "mozilla/dom/PushSubscriptionChangeEventBinding.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDebug.h"
|
||||
@@ -830,12 +832,28 @@ class PushSubscriptionChangeEventOp final : public ExtendableEventOp {
|
||||
|
||||
RefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
|
||||
|
||||
ExtendableEventInit init;
|
||||
ServiceWorkerPushSubscriptionChangeEventOpArgs& args =
|
||||
mArgs.get_ServiceWorkerPushSubscriptionChangeEventOpArgs();
|
||||
|
||||
PushSubscriptionChangeEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
|
||||
RefPtr<ExtendableEvent> event = ExtendableEvent::Constructor(
|
||||
target, u"pushsubscriptionchange"_ns, init);
|
||||
if (args.oldSubscription()) {
|
||||
PushSubscriptionData oldSubscriptionData =
|
||||
args.oldSubscription().extract();
|
||||
RefPtr<PushSubscription> oldSubscription = new PushSubscription(
|
||||
target->GetParentObject(), oldSubscriptionData.endpoint(), u""_ns,
|
||||
Nullable<EpochTimeStamp>(),
|
||||
std::move(oldSubscriptionData.rawP256dhKey()),
|
||||
std::move(oldSubscriptionData.authSecret()),
|
||||
std::move(oldSubscriptionData.appServerKey()));
|
||||
init.mOldSubscription = oldSubscription.forget();
|
||||
}
|
||||
|
||||
RefPtr<PushSubscriptionChangeEvent> event =
|
||||
PushSubscriptionChangeEvent::Constructor(
|
||||
target, u"pushsubscriptionchange"_ns, init);
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsresult rv = DispatchExtendableEventOnWorkerScope(
|
||||
|
||||
@@ -42,7 +42,16 @@ struct ServiceWorkerPushEventOpArgs {
|
||||
OptionalPushData data;
|
||||
};
|
||||
|
||||
struct ServiceWorkerPushSubscriptionChangeEventOpArgs {};
|
||||
struct PushSubscriptionData {
|
||||
nsString endpoint;
|
||||
uint8_t[] rawP256dhKey;
|
||||
uint8_t[] authSecret;
|
||||
uint8_t[] appServerKey;
|
||||
};
|
||||
|
||||
struct ServiceWorkerPushSubscriptionChangeEventOpArgs {
|
||||
PushSubscriptionData? oldSubscription;
|
||||
};
|
||||
|
||||
struct ServiceWorkerNotificationEventOpArgs {
|
||||
nsString eventName;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "mozilla/dom/FetchEventOpChild.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/InternalRequest.h"
|
||||
#include "mozilla/dom/PushManager.h"
|
||||
#include "mozilla/dom/ReferrerInfo.h"
|
||||
#include "mozilla/dom/RemoteType.h"
|
||||
#include "mozilla/dom/RemoteWorkerControllerChild.h"
|
||||
@@ -970,12 +971,22 @@ nsresult ServiceWorkerPrivate::SendPushEventInternal(
|
||||
});
|
||||
}
|
||||
|
||||
nsresult ServiceWorkerPrivate::SendPushSubscriptionChangeEvent() {
|
||||
nsresult ServiceWorkerPrivate::SendPushSubscriptionChangeEvent(
|
||||
const RefPtr<nsIPushSubscription>& aOldSubscription) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
ServiceWorkerPushSubscriptionChangeEventOpArgs args{};
|
||||
if (aOldSubscription) {
|
||||
PushSubscriptionData oldSubscription{};
|
||||
MOZ_TRY(GetSubscriptionParams(aOldSubscription, oldSubscription.endpoint(),
|
||||
oldSubscription.rawP256dhKey(),
|
||||
oldSubscription.authSecret(),
|
||||
oldSubscription.appServerKey()));
|
||||
args.oldSubscription().emplace(oldSubscription);
|
||||
}
|
||||
|
||||
return ExecServiceWorkerOp(
|
||||
ServiceWorkerPushSubscriptionChangeEventOpArgs(),
|
||||
ServiceWorkerLifetimeExtension(FullLifetimeExtension{}),
|
||||
std::move(args), ServiceWorkerLifetimeExtension(FullLifetimeExtension{}),
|
||||
[](ServiceWorkerOpResult&& aResult) {
|
||||
MOZ_ASSERT(aResult.type() == ServiceWorkerOpResult::Tnsresult);
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define NOTIFICATION_CLOSE_EVENT_NAME u"notificationclose"
|
||||
|
||||
class nsIInterceptedChannel;
|
||||
class nsIPushSubscription;
|
||||
class nsIWorkerDebugger;
|
||||
|
||||
namespace mozilla {
|
||||
@@ -107,7 +108,8 @@ class ServiceWorkerPrivate final : public RemoteWorkerObserver {
|
||||
const Maybe<nsTArray<uint8_t>>& aData,
|
||||
RefPtr<ServiceWorkerRegistrationInfo> aRegistration);
|
||||
|
||||
nsresult SendPushSubscriptionChangeEvent();
|
||||
nsresult SendPushSubscriptionChangeEvent(
|
||||
const RefPtr<nsIPushSubscription>& aOldSubscription);
|
||||
|
||||
nsresult SendNotificationEvent(const nsAString& aEventName,
|
||||
const nsAString& aID, const nsAString& aTitle,
|
||||
|
||||
1
testing/web-platform/mozilla/meta/push-api/__dir__.ini
Normal file
1
testing/web-platform/mozilla/meta/push-api/__dir__.ini
Normal file
@@ -0,0 +1 @@
|
||||
prefs: [dom.push.serverURL:wss://web-platform.test:8889/mozilla_push_dummy,dom.push.connection.enabled:true]
|
||||
@@ -0,0 +1,4 @@
|
||||
[pushsubscriptionchange.https.any.window-module.html]
|
||||
[Fire pushsubscriptionchange event when permission is revoked]
|
||||
expected:
|
||||
if os == "android": FAIL
|
||||
15
testing/web-platform/mozilla/tests/push-api/push-sw.js
Normal file
15
testing/web-platform/mozilla/tests/push-api/push-sw.js
Normal file
@@ -0,0 +1,15 @@
|
||||
async function postAll(data) {
|
||||
const clients = await self.clients.matchAll({ includeUncontrolled: true });
|
||||
for (const client of clients) {
|
||||
client.postMessage(data);
|
||||
}
|
||||
}
|
||||
|
||||
onpushsubscriptionchange = ev => {
|
||||
postAll({
|
||||
type: ev.type,
|
||||
constructor: ev.constructor.name,
|
||||
oldSubscription: ev.oldSubscription?.toJSON(),
|
||||
newSubscription: ev.newSubscription?.toJSON(),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// META: global=window-module
|
||||
// META: script=/resources/testdriver.js
|
||||
// META: script=/resources/testdriver-vendor.js
|
||||
// META: script=/notifications/resources/helpers.js
|
||||
|
||||
let registration;
|
||||
|
||||
promise_setup(async () => {
|
||||
await trySettingPermission("granted");
|
||||
registration = await getActiveServiceWorker("push-sw.js");
|
||||
});
|
||||
|
||||
promise_test(async (t) => {
|
||||
const promise = new Promise(r => {
|
||||
navigator.serviceWorker.addEventListener("message", r, { once: true })
|
||||
});
|
||||
|
||||
const subscription = await registration.pushManager.subscribe();
|
||||
t.add_cleanup(() => subscription.unsubscribe());
|
||||
|
||||
// https://w3c.github.io/push-api/#security-and-privacy-considerations
|
||||
// When a permission is revoked, the user agent MAY fire the "pushsubscriptionchange"
|
||||
// event for subscriptions created with that permission
|
||||
//
|
||||
// But Firefox fires pushsubscriptionchange on permission regrant instead of revocation.
|
||||
// https://github.com/w3c/push-api/issues/236
|
||||
await trySettingPermission("prompt");
|
||||
await trySettingPermission("granted");
|
||||
|
||||
const pushSubscriptionChangeEvent = await promise;
|
||||
|
||||
assert_equals(pushSubscriptionChangeEvent.data.type, "pushsubscriptionchange");
|
||||
assert_equals(pushSubscriptionChangeEvent.data.constructor, "PushSubscriptionChangeEvent");
|
||||
assert_object_equals(pushSubscriptionChangeEvent.data.oldSubscription, subscription.toJSON());
|
||||
}, "Fire pushsubscriptionchange event when permission is revoked");
|
||||
Reference in New Issue
Block a user