Diff
Modified: trunk/Source/WebKit/ChangeLog (291491 => 291492)
--- trunk/Source/WebKit/ChangeLog 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/ChangeLog 2022-03-18 19:19:35 UTC (rev 291492)
@@ -1,3 +1,67 @@
+2022-03-18 Ben Nham <[email protected]>
+
+ Remove push subscriptions when associated service worker registrations are removed
+ https://bugs.webkit.org/show_bug.cgi?id=237983
+
+ Reviewed by Youenn Fablet.
+
+ When a ServiceWorkerRegistration is removed, we also need to remove its associated
+ PushSubscription. This can occur when:
+
+ 1. The application calls ServiceWorkerRegistration.unregister. This is implemented by
+ having resolveUnregistrationJobInClient call unsubscribeFromPushService in webpushd.
+ The identifier passed to unsubscribeFromPushService is now optional; if the identifier
+ is not present, then we delete whatever PushSubscription is associated with the given
+ scope URL.
+
+ 2. The user clears website data for a particular origin. This is implemented by having
+ deleteWebsiteDataForOrigins invoke removePushSubscriptionsForOrigin in webpushd.
+
+ 3. The user clears all website data. This is implemented by having deleteWebsiteData
+ invoke removeAllPushSubscriptions in webpushd.
+
+ Covered by new API tests.
+
+ * NetworkProcess/NetworkProcess.cpp:
+ (WebKit::NetworkProcess::deleteWebsiteData):
+ (WebKit::NetworkProcess::deleteWebsiteDataForOrigins):
+ (WebKit::NetworkProcess::deleteAndRestrictWebsiteDataForRegistrableDomains):
+ (WebKit::NetworkProcess::hasPushSubscriptionForTesting):
+ * NetworkProcess/NetworkProcess.h:
+ * NetworkProcess/NetworkProcess.messages.in:
+ * NetworkProcess/Notifications/NetworkNotificationManager.cpp:
+ (WebKit::NetworkNotificationManager::unsubscribeFromPushService):
+ (WebKit::NetworkNotificationManager::removeAllPushSubscriptions):
+ (WebKit::NetworkNotificationManager::removePushSubscriptionsForOrigin):
+ * NetworkProcess/Notifications/NetworkNotificationManager.h:
+ * NetworkProcess/ServiceWorker/WebSWServerConnection.cpp:
+ (WebKit::WebSWServerConnection::resolveUnregistrationJobInClient):
+ * Shared/WebPushDaemonConstants.h:
+ (WebKit::WebPushD::messageTypeSendsReply):
+ * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+ (-[WKWebsiteDataStore _scopeURL:hasPushSubscriptionForTesting:]):
+ * UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:
+ * UIProcess/Network/NetworkProcessProxy.cpp:
+ (WebKit::NetworkProcessProxy::hasPushSubscriptionForTesting):
+ * UIProcess/Network/NetworkProcessProxy.h:
+ * webpushd/PushService.h:
+ * webpushd/PushService.mm:
+ (WebPushD::UnsubscribeRequest::UnsubscribeRequest):
+ (WebPushD::UnsubscribeRequest::startInternal):
+ (WebPushD::PushService::unsubscribe):
+ (WebPushD::PushService::incrementSilentPushCount):
+ (WebPushD::PushService::removeRecordsForBundleIdentifier):
+ (WebPushD::PushService::removeRecordsForBundleIdentifierAndOrigin):
+ (WebPushD::PushService::removeRecordsImpl):
+ * webpushd/WebPushDaemon.h:
+ * webpushd/WebPushDaemon.mm:
+ (WebPushD::MessageInfo::removeAllPushSubscriptions::encodeReply):
+ (WebPushD::MessageInfo::removePushSubscriptionsForOrigin::encodeReply):
+ (WebPushD::Daemon::decodeAndHandleMessage):
+ (WebPushD::Daemon::unsubscribeFromPushService):
+ (WebPushD::Daemon::removeAllPushSubscriptions):
+ (WebPushD::Daemon::removePushSubscriptionsForOrigin):
+
2022-03-18 J Pascoe <[email protected]>
Trigger PDF download in captive portal mode instead of using PDF viewer
Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp (291491 => 291492)
--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.cpp 2022-03-18 19:19:35 UTC (rev 291492)
@@ -1511,9 +1511,14 @@
#if ENABLE(SERVICE_WORKER)
bool clearServiceWorkers = websiteDataTypes.contains(WebsiteDataType::DOMCache) || websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations);
- if (clearServiceWorkers && !sessionID.isEphemeral() && session)
+ if (clearServiceWorkers && !sessionID.isEphemeral() && session) {
session->ensureSWServer().clearAll([clearTasksHandler] { });
+
+#if ENABLE(BUILT_IN_NOTIFICATIONS)
+ session->notificationManager().removeAllPushSubscriptions([clearTasksHandler](auto&&) { });
#endif
+ }
+#endif
#if ENABLE(INTELLIGENT_TRACKING_PREVENTION)
if (websiteDataTypes.contains(WebsiteDataType::ResourceLoadStatistics)) {
@@ -1605,8 +1610,13 @@
bool clearServiceWorkers = websiteDataTypes.contains(WebsiteDataType::DOMCache) || websiteDataTypes.contains(WebsiteDataType::ServiceWorkerRegistrations);
if (clearServiceWorkers && !sessionID.isEphemeral() && session) {
auto& server = session->ensureSWServer();
- for (auto& originData : originDatas)
+ for (auto& originData : originDatas) {
server.clear(originData, [clearTasksHandler] { });
+
+#if ENABLE(BUILT_IN_NOTIFICATIONS)
+ session->notificationManager().removePushSubscriptionsForOrigin(SecurityOriginData { originData }, [clearTasksHandler](auto&&) { });
+#endif
+ }
}
#endif
@@ -1798,8 +1808,13 @@
if (!domainsToDeleteAllNonCookieWebsiteDataFor.contains(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host)))
continue;
callbackAggregator->m_domains.add(RegistrableDomain::uncheckedCreateFromHost(securityOrigin.host));
- if (session)
+ if (session) {
session->ensureSWServer().clear(securityOrigin, [callbackAggregator] { });
+
+#if ENABLE(BUILT_IN_NOTIFICATIONS)
+ session->notificationManager().removePushSubscriptionsForOrigin(SecurityOriginData { securityOrigin }, [callbackAggregator](auto&&) { });
+#endif
+ }
}
});
}
@@ -2314,6 +2329,20 @@
callback({ });
}
+void NetworkProcess::hasPushSubscriptionForTesting(PAL::SessionID sessionID, URL&& scopeURL, CompletionHandler<void(bool)>&& callback)
+{
+#if ENABLE(BUILT_IN_NOTIFICATIONS)
+ if (auto* session = networkSession(sessionID)) {
+ session->notificationManager().getPushSubscription(WTFMove(scopeURL), [callback = WTFMove(callback)](auto &&result) mutable {
+ callback(result && result->has_value());
+ });
+ return;
+ }
+#endif
+
+ callback(false);
+}
+
void NetworkProcess::requestStorageSpace(PAL::SessionID sessionID, const ClientOrigin& origin, uint64_t quota, uint64_t currentSize, uint64_t spaceRequired, CompletionHandler<void(std::optional<uint64_t>)>&& callback)
{
parentProcessConnection()->sendWithAsyncReply(Messages::NetworkProcessProxy::RequestStorageSpace { sessionID, origin, quota, currentSize, spaceRequired }, WTFMove(callback), 0);
Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.h (291491 => 291492)
--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.h 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.h 2022-03-18 19:19:35 UTC (rev 291492)
@@ -376,6 +376,7 @@
void deletePushAndNotificationRegistration(PAL::SessionID, const WebCore::SecurityOriginData&, CompletionHandler<void(const String&)>&&);
void getOriginsWithPushAndNotificationPermissions(PAL::SessionID, CompletionHandler<void(const Vector<WebCore::SecurityOriginData>&)>&&);
+ void hasPushSubscriptionForTesting(PAL::SessionID, URL&&, CompletionHandler<void(bool)>&&);
private:
void platformInitializeNetworkProcess(const NetworkProcessCreationParameters&);
Modified: trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in (291491 => 291492)
--- trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/NetworkProcess/NetworkProcess.messages.in 2022-03-18 19:19:35 UTC (rev 291492)
@@ -215,4 +215,5 @@
#endif
DeletePushAndNotificationRegistration(PAL::SessionID sessionID, struct WebCore::SecurityOriginData origin) -> (String errorMessage)
GetOriginsWithPushAndNotificationPermissions(PAL::SessionID sessionID) -> (Vector<WebCore::SecurityOriginData> origins)
+ HasPushSubscriptionForTesting(PAL::SessionID sessionID, URL scopeURL) -> (bool hasSubscription)
}
Modified: trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp (291491 => 291492)
--- trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.cpp 2022-03-18 19:19:35 UTC (rev 291492)
@@ -145,7 +145,7 @@
sendMessageWithReply<WebPushD::MessageType::SubscribeToPushService>(WTFMove(completionHandler), WTFMove(scopeURL), WTFMove(applicationServerKey));
}
-void NetworkNotificationManager::unsubscribeFromPushService(URL&& scopeURL, PushSubscriptionIdentifier pushSubscriptionIdentifier, CompletionHandler<void(Expected<bool, WebCore::ExceptionData>&&)>&& completionHandler)
+void NetworkNotificationManager::unsubscribeFromPushService(URL&& scopeURL, std::optional<PushSubscriptionIdentifier> pushSubscriptionIdentifier, CompletionHandler<void(Expected<bool, WebCore::ExceptionData>&&)>&& completionHandler)
{
if (!m_connection) {
completionHandler(makeUnexpected(ExceptionData { AbortError, "No connection to push daemon"_s }));
@@ -185,6 +185,26 @@
sendMessageWithReply<WebPushD::MessageType::IncrementSilentPushCount>(WTFMove(completionHandler), WTFMove(origin));
}
+void NetworkNotificationManager::removeAllPushSubscriptions(CompletionHandler<void(unsigned)>&& completionHandler)
+{
+ if (!m_connection) {
+ completionHandler(0);
+ return;
+ }
+
+ sendMessageWithReply<WebPushD::MessageType::RemoveAllPushSubscriptions>(WTFMove(completionHandler));
+}
+
+void NetworkNotificationManager::removePushSubscriptionsForOrigin(WebCore::SecurityOriginData&& origin, CompletionHandler<void(unsigned)>&& completionHandler)
+{
+ if (!m_connection) {
+ completionHandler(0);
+ return;
+ }
+
+ sendMessageWithReply<WebPushD::MessageType::RemovePushSubscriptionsForOrigin>(WTFMove(completionHandler), WTFMove(origin));
+}
+
template<WebPushD::MessageType messageType, typename... Args>
void NetworkNotificationManager::sendMessage(Args&&... args) const
{
Modified: trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.h (291491 => 291492)
--- trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.h 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/NetworkProcess/Notifications/NetworkNotificationManager.h 2022-03-18 19:19:35 UTC (rev 291492)
@@ -58,10 +58,12 @@
void getPendingPushMessages(CompletionHandler<void(const Vector<WebPushMessage>&)>&&);
void subscribeToPushService(URL&& scopeURL, Vector<uint8_t>&& applicationServerKey, CompletionHandler<void(Expected<WebCore::PushSubscriptionData, WebCore::ExceptionData>&&)>&&);
- void unsubscribeFromPushService(URL&& scopeURL, WebCore::PushSubscriptionIdentifier, CompletionHandler<void(Expected<bool, WebCore::ExceptionData>&&)>&&);
+ void unsubscribeFromPushService(URL&& scopeURL, std::optional<WebCore::PushSubscriptionIdentifier>, CompletionHandler<void(Expected<bool, WebCore::ExceptionData>&&)>&&);
void getPushSubscription(URL&& scopeURL, CompletionHandler<void(Expected<std::optional<WebCore::PushSubscriptionData>, WebCore::ExceptionData>&&)>&&);
void getPushPermissionState(URL&& scopeURL, CompletionHandler<void(Expected<uint8_t, WebCore::ExceptionData>&&)>&&);
void incrementSilentPushCount(WebCore::SecurityOriginData&&, CompletionHandler<void(unsigned)>&&);
+ void removeAllPushSubscriptions(CompletionHandler<void(unsigned)>&&);
+ void removePushSubscriptionsForOrigin(WebCore::SecurityOriginData&&, CompletionHandler<void(unsigned)>&&);
private:
NetworkNotificationManager(NetworkSession&, const String& webPushMachServiceName);
Modified: trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp (291491 => 291492)
--- trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/NetworkProcess/ServiceWorker/WebSWServerConnection.cpp 2022-03-18 19:19:35 UTC (rev 291492)
@@ -111,8 +111,22 @@
void WebSWServerConnection::resolveUnregistrationJobInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, bool unregistrationResult)
{
ASSERT(m_unregisterJobs.contains(jobIdentifier));
- if (auto completionHandler = m_unregisterJobs.take(jobIdentifier))
+ if (auto completionHandler = m_unregisterJobs.take(jobIdentifier)) {
+#if ENABLE(BUILT_IN_NOTIFICATIONS)
+ if (!session()) {
+ completionHandler(unregistrationResult);
+ return;
+ }
+
+ auto scopeURL = registrationKey.scope();
+ session()->notificationManager().unsubscribeFromPushService(WTFMove(scopeURL), std::nullopt, [completionHandler = WTFMove(completionHandler), unregistrationResult](auto&&) mutable {
+ completionHandler(unregistrationResult);
+ });
+
+#else
completionHandler(unregistrationResult);
+#endif
+ }
}
void WebSWServerConnection::startScriptFetchInClient(ServiceWorkerJobIdentifier jobIdentifier, const ServiceWorkerRegistrationKey& registrationKey, FetchOptions::Cache cachePolicy)
Modified: trunk/Source/WebKit/Shared/WebPushDaemonConstants.h (291491 => 291492)
--- trunk/Source/WebKit/Shared/WebPushDaemonConstants.h 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/Shared/WebPushDaemonConstants.h 2022-03-18 19:19:35 UTC (rev 291492)
@@ -53,6 +53,8 @@
GetPushSubscription,
GetPushPermissionState,
IncrementSilentPushCount,
+ RemoveAllPushSubscriptions,
+ RemovePushSubscriptionsForOrigin,
};
inline bool messageTypeSendsReply(MessageType messageType)
@@ -70,6 +72,8 @@
case MessageType::GetPushSubscription:
case MessageType::GetPushPermissionState:
case MessageType::IncrementSilentPushCount:
+ case MessageType::RemoveAllPushSubscriptions:
+ case MessageType::RemovePushSubscriptionsForOrigin:
return true;
case MessageType::SetDebugModeIsEnabled:
case MessageType::UpdateConnectionConfiguration:
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm (291491 => 291492)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm 2022-03-18 19:19:35 UTC (rev 291492)
@@ -835,4 +835,13 @@
});
}
+-(void)_scopeURL:(NSURL *)scopeURL hasPushSubscriptionForTesting:(void(^)(BOOL))completionHandler
+{
+ auto completionHandlerCopy = makeBlockPtr(completionHandler);
+ _websiteDataStore->networkProcess()
+ .hasPushSubscriptionForTesting(_websiteDataStore->sessionID(), scopeURL, [completionHandlerCopy](bool result) {
+ completionHandlerCopy(result);
+ });
+}
+
@end
Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h (291491 => 291492)
--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h 2022-03-18 19:19:35 UTC (rev 291492)
@@ -115,6 +115,7 @@
-(void)_processPushMessage:(NSDictionary *)pushMessage completionHandler:(void(^)(bool))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
-(void)_deletePushAndNotificationRegistration:(WKSecurityOrigin *)securityOrigin completionHandler:(void(^)(NSError *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
-(void)_getOriginsWithPushAndNotificationPermissions:(void(^)(NSSet<WKSecurityOrigin *> *))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+-(void)_scopeURL:(NSURL *)scopeURL hasPushSubscriptionForTesting:(void(^)(BOOL))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
@end
NS_ASSUME_NONNULL_END
Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp (291491 => 291492)
--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.cpp 2022-03-18 19:19:35 UTC (rev 291492)
@@ -1791,6 +1791,11 @@
sendWithAsyncReply(Messages::NetworkProcess::GetOriginsWithPushAndNotificationPermissions { sessionID }, WTFMove(callback));
}
+void NetworkProcessProxy::hasPushSubscriptionForTesting(PAL::SessionID sessionID, const URL& scopeURL, CompletionHandler<void(bool)>&& callback)
+{
+ sendWithAsyncReply(Messages::NetworkProcess::HasPushSubscriptionForTesting { sessionID, scopeURL }, WTFMove(callback));
+}
+
void NetworkProcessProxy::terminateRemoteWorkerContextConnectionWhenPossible(RemoteWorkerType workerType, PAL::SessionID sessionID, const WebCore::RegistrableDomain& registrableDomain, WebCore::ProcessIdentifier processIdentifier)
{
send(Messages::NetworkProcess::TerminateRemoteWorkerContextConnectionWhenPossible(workerType, sessionID, registrableDomain, processIdentifier), 0);
Modified: trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h (291491 => 291492)
--- trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/UIProcess/Network/NetworkProcessProxy.h 2022-03-18 19:19:35 UTC (rev 291492)
@@ -291,6 +291,7 @@
void deletePushAndNotificationRegistration(PAL::SessionID, const WebCore::SecurityOriginData&, CompletionHandler<void(const String&)>&&);
void getOriginsWithPushAndNotificationPermissions(PAL::SessionID, CompletionHandler<void(const Vector<WebCore::SecurityOriginData>&)>&&);
+ void hasPushSubscriptionForTesting(PAL::SessionID, const URL&, CompletionHandler<void(bool)>&&);
void dataTaskReceivedChallenge(DataTaskIdentifier, WebCore::AuthenticationChallenge&&, CompletionHandler<void(AuthenticationChallengeDisposition, WebCore::Credential&&)>&&);
void dataTaskWillPerformHTTPRedirection(DataTaskIdentifier, WebCore::ResourceResponse&&, WebCore::ResourceRequest&&, CompletionHandler<void(bool)>&&);
Modified: trunk/Source/WebKit/webpushd/PushService.h (291491 => 291492)
--- trunk/Source/WebKit/webpushd/PushService.h 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/webpushd/PushService.h 2022-03-18 19:19:35 UTC (rev 291492)
@@ -59,8 +59,11 @@
void getSubscription(const String& bundleIdentifier, const String& scope, CompletionHandler<void(const Expected<std::optional<WebCore::PushSubscriptionData>, WebCore::ExceptionData>&)>&&);
void subscribe(const String& bundleIdentifier, const String& scope, const Vector<uint8_t>& vapidPublicKey, CompletionHandler<void(const Expected<WebCore::PushSubscriptionData, WebCore::ExceptionData>&)>&&);
- void unsubscribe(const String& bundleIdentifier, const String& scope, WebCore::PushSubscriptionIdentifier, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&&);
+ void unsubscribe(const String& bundleIdentifier, const String& scope, std::optional<WebCore::PushSubscriptionIdentifier>, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&&);
+ void removeRecordsForBundleIdentifier(const String& bundleIdentifier, CompletionHandler<void(unsigned)>&&);
+ void removeRecordsForBundleIdentifierAndOrigin(const String& bundleIdentifier, const String& securityOrigin, CompletionHandler<void(unsigned)>&&);
+
void incrementSilentPushCount(const String& bundleIdentifier, const String& securityOrigin, CompletionHandler<void(unsigned)>&&);
void didCompleteGetSubscriptionRequest(GetSubscriptionRequest&);
@@ -75,6 +78,8 @@
using PushServiceRequestMap = HashMap<std::tuple<String, String>, Deque<std::unique_ptr<PushServiceRequest>>>;
void enqueuePushServiceRequest(PushServiceRequestMap&, std::unique_ptr<PushServiceRequest>&&);
void finishedPushServiceRequest(PushServiceRequestMap&, PushServiceRequest&);
+
+ void removeRecordsImpl(const String& bundleIdentifier, const std::optional<String>& securityOrigin, CompletionHandler<void(unsigned)>&&);
UniqueRef<PushServiceConnection> m_connection;
UniqueRef<WebCore::PushDatabase> m_database;
Modified: trunk/Source/WebKit/webpushd/PushService.mm (291491 => 291492)
--- trunk/Source/WebKit/webpushd/PushService.mm 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/webpushd/PushService.mm 2022-03-18 19:19:35 UTC (rev 291492)
@@ -349,7 +349,7 @@
class UnsubscribeRequest : public PushServiceRequestImpl<bool> {
public:
- UnsubscribeRequest(PushService&, const String& bundleIdentifier, const String& scope, PushSubscriptionIdentifier, ResultHandler&&);
+ UnsubscribeRequest(PushService&, const String& bundleIdentifier, const String& scope, std::optional<PushSubscriptionIdentifier>, ResultHandler&&);
virtual ~UnsubscribeRequest() = default;
protected:
@@ -358,10 +358,10 @@
void finish() final { m_service.didCompleteUnsubscribeRequest(*this); }
private:
- PushSubscriptionIdentifier m_subscriptionIdentifier;
+ std::optional<PushSubscriptionIdentifier> m_subscriptionIdentifier;
};
-UnsubscribeRequest::UnsubscribeRequest(PushService& service, const String& bundleIdentifier, const String& scope, PushSubscriptionIdentifier subscriptionIdentifier, ResultHandler&& resultHandler)
+UnsubscribeRequest::UnsubscribeRequest(PushService& service, const String& bundleIdentifier, const String& scope, std::optional<PushSubscriptionIdentifier> subscriptionIdentifier, ResultHandler&& resultHandler)
: PushServiceRequestImpl(service, bundleIdentifier, scope, WTFMove(resultHandler))
, m_subscriptionIdentifier(subscriptionIdentifier)
{
@@ -371,32 +371,25 @@
void UnsubscribeRequest::startInternal()
{
m_database.getRecordByBundleIdentifierAndScope(m_bundleIdentifier, m_scope, [this](auto&& result) mutable {
- if (!result || m_subscriptionIdentifier != result->identifier) {
+ if (!result || (m_subscriptionIdentifier && *m_subscriptionIdentifier != result->identifier)) {
fulfill(false);
return;
}
+
+ m_database.removeRecordByIdentifier(result->identifier, [this, serverVAPIDPublicKey = result->serverVAPIDPublicKey](bool removed) mutable {
+ if (!removed) {
+ fulfill(false);
+ return;
+ }
- auto topic = makePushTopic(m_bundleIdentifier, m_scope);
- m_connection.unsubscribe(topic, result->serverVAPIDPublicKey, [this](bool unsubscribed, NSError *error) mutable {
-#if !RELEASE_LOG_DISABLED
- // If we fail to unsubscribe from apsd, just drop a log. We still want to continue and remove the record from our database in case there's a state mismatch between our database and apsd's database.
- if (!unsubscribed)
- RELEASE_LOG(Push, "PushSubscription.unsubscribe(bundleID: %{public}s, scope: %{sensitive}s) failed with domain: %{public}s code: %lld)", m_bundleIdentifier.utf8().data(), m_scope.utf8().data(), error.domain.UTF8String ?: "none", static_cast<int64_t>(error.code));
-#else
- UNUSED_PARAM(unsubscribed);
- UNUSED_PARAM(error);
-#endif
+ // FIXME: support partial topic list updates.
+ updateTopicLists(m_connection, m_database, [this]() mutable {
+ fulfill(true);
+ });
- m_database.removeRecordByIdentifier(m_subscriptionIdentifier, [this](bool removed) mutable {
- if (!removed) {
- fulfill(false);
- return;
- }
-
- // FIXME: support partial topic list updates.
- updateTopicLists(m_connection, m_database, [this]() mutable {
- fulfill(true);
- });
+ auto topic = makePushTopic(m_bundleIdentifier, m_scope);
+ m_connection.unsubscribe(topic, serverVAPIDPublicKey, [this](bool unsubscribed, NSError *error) mutable {
+ RELEASE_LOG_ERROR_IF(!unsubscribed, Push, "PushSubscription.unsubscribe(bundleID: %{public}s, scope: %{sensitive}s) failed with domain: %{public}s code: %lld)", m_bundleIdentifier.utf8().data(), m_scope.utf8().data(), error.domain.UTF8String ?: "none", static_cast<int64_t>(error.code));
});
});
});
@@ -463,7 +456,7 @@
finishedPushServiceRequest(m_subscribeRequests, request);
}
-void PushService::unsubscribe(const String& bundleIdentifier, const String& scope, PushSubscriptionIdentifier subscriptionIdentifier, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&& completionHandler)
+void PushService::unsubscribe(const String& bundleIdentifier, const String& scope, std::optional<PushSubscriptionIdentifier> subscriptionIdentifier, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&& completionHandler)
{
enqueuePushServiceRequest(m_unsubscribeRequests, makeUnique<UnsubscribeRequest>(*this, bundleIdentifier, scope, subscriptionIdentifier, WTFMove(completionHandler)));
}
@@ -483,19 +476,40 @@
RELEASE_LOG(Push, "Removing all subscriptions associated with %{public}s %{sensitive}s since it processed %u silent pushes", bundleIdentifier.utf8().data(), securityOrigin.utf8().data(), silentPushCount);
- m_database->removeRecordsByBundleIdentifierAndSecurityOrigin(bundleIdentifier, securityOrigin, [this, bundleIdentifier, securityOrigin, silentPushCount, handler = WTFMove(handler)](auto&& removedRecords) mutable {
- for (auto& record : removedRecords) {
- m_connection->unsubscribe(record.topic, record.serverVAPIDPublicKey, [topic = record.topic](bool unsubscribed, NSError* error) {
- if (!unsubscribed)
- RELEASE_LOG_ERROR(Push, "IncrementSilentPushRequest couldn't remove subscription for topic %{sensitive}s: %{public}s code: %lld)", topic.utf8().data(), error.domain.UTF8String ?: "none", static_cast<int64_t>(error.code));
- });
- }
+ removeRecordsImpl(bundleIdentifier, securityOrigin, [handler = WTFMove(handler), silentPushCount](auto&&) mutable {
+ handler(silentPushCount);
+ });
+ });
+}
- updateTopicLists(m_connection, m_database, [silentPushCount, handler = WTFMove(handler)]() mutable {
- handler(silentPushCount);
+void PushService::removeRecordsForBundleIdentifier(const String& bundleIdentifier, CompletionHandler<void(unsigned)>&& handler)
+{
+ removeRecordsImpl(bundleIdentifier, std::nullopt, WTFMove(handler));
+}
+
+void PushService::removeRecordsForBundleIdentifierAndOrigin(const String& bundleIdentifier, const String& securityOrigin, CompletionHandler<void(unsigned)>&& handler)
+{
+ removeRecordsImpl(bundleIdentifier, securityOrigin, WTFMove(handler));
+}
+
+void PushService::removeRecordsImpl(const String& bundleIdentifier, const std::optional<String>& securityOrigin, CompletionHandler<void(unsigned)>&& handler)
+{
+ auto removedRecordsHandler = [this, bundleIdentifier, securityOrigin, handler = WTFMove(handler)](Vector<RemovedPushRecord>&& removedRecords) mutable {
+ for (auto& record : removedRecords) {
+ m_connection->unsubscribe(record.topic, record.serverVAPIDPublicKey, [topic = record.topic](bool unsubscribed, NSError* error) {
+ RELEASE_LOG_ERROR_IF(!unsubscribed, Push, "removeRecordsImpl couldn't remove subscription for topic %{sensitive}s: %{public}s code: %lld)", topic.utf8().data(), error.domain.UTF8String ?: "none", static_cast<int64_t>(error.code));
});
+ }
+
+ updateTopicLists(m_connection, m_database, [count = removedRecords.size(), handler = WTFMove(handler)]() mutable {
+ handler(count);
});
- });
+ };
+
+ if (securityOrigin)
+ m_database->removeRecordsByBundleIdentifierAndSecurityOrigin(bundleIdentifier, *securityOrigin, WTFMove(removedRecordsHandler));
+ else
+ m_database->removeRecordsByBundleIdentifier(bundleIdentifier, WTFMove(removedRecordsHandler));
}
enum class ContentEncoding {
Modified: trunk/Source/WebKit/webpushd/WebPushDaemon.h (291491 => 291492)
--- trunk/Source/WebKit/webpushd/WebPushDaemon.h 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/webpushd/WebPushDaemon.h 2022-03-18 19:19:35 UTC (rev 291492)
@@ -81,10 +81,12 @@
void injectEncryptedPushMessageForTesting(ClientConnection*, const String&, CompletionHandler<void(bool)>&&);
void getPendingPushMessages(ClientConnection*, CompletionHandler<void(const Vector<WebKit::WebPushMessage>&)>&& replySender);
void subscribeToPushService(ClientConnection*, const URL& scopeURL, const Vector<uint8_t>& applicationServerKey, CompletionHandler<void(const Expected<WebCore::PushSubscriptionData, WebCore::ExceptionData>&)>&& replySender);
- void unsubscribeFromPushService(ClientConnection*, const URL& scopeURL, WebCore::PushSubscriptionIdentifier, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&& replySender);
+ void unsubscribeFromPushService(ClientConnection*, const URL& scopeURL, std::optional<WebCore::PushSubscriptionIdentifier>, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&& replySender);
void getPushSubscription(ClientConnection*, const URL& scopeURL, CompletionHandler<void(const Expected<std::optional<WebCore::PushSubscriptionData>, WebCore::ExceptionData>&)>&& replySender);
void getPushPermissionState(ClientConnection*, const URL& scopeURL, CompletionHandler<void(const Expected<uint8_t, WebCore::ExceptionData>&)>&& replySender);
void incrementSilentPushCount(ClientConnection*, const WebCore::SecurityOriginData&, CompletionHandler<void(unsigned)>&&);
+ void removeAllPushSubscriptions(ClientConnection*, CompletionHandler<void(unsigned)>&&);
+ void removePushSubscriptionsForOrigin(ClientConnection*, const WebCore::SecurityOriginData&, CompletionHandler<void(unsigned)>&&);
void broadcastDebugMessage(const String&);
void broadcastAllConnectionIdentities();
Modified: trunk/Source/WebKit/webpushd/WebPushDaemon.mm (291491 => 291492)
--- trunk/Source/WebKit/webpushd/WebPushDaemon.mm 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Source/WebKit/webpushd/WebPushDaemon.mm 2022-03-18 19:19:35 UTC (rev 291492)
@@ -105,7 +105,7 @@
END
FUNCTION(unsubscribeFromPushService)
-ARGUMENTS(URL, WebCore::PushSubscriptionIdentifier)
+ARGUMENTS(URL, std::optional<WebCore::PushSubscriptionIdentifier>)
REPLY(const Expected<bool, WebCore::ExceptionData>&)
END
@@ -124,6 +124,16 @@
REPLY(unsigned)
END
+FUNCTION(removeAllPushSubscriptions)
+ARGUMENTS()
+REPLY(unsigned)
+END
+
+FUNCTION(removePushSubscriptionsForOrigin)
+ARGUMENTS(WebCore::SecurityOriginData)
+REPLY(unsigned)
+END
+
#undef FUNCTION
#undef ARGUMENTS
#undef REPLY
@@ -213,6 +223,20 @@
return encoder.takeBuffer();
}
+WebPushD::EncodedMessage removeAllPushSubscriptions::encodeReply(unsigned reply)
+{
+ WebKit::Daemon::Encoder encoder;
+ encoder << reply;
+ return encoder.takeBuffer();
+}
+
+WebPushD::EncodedMessage removePushSubscriptionsForOrigin::encodeReply(unsigned reply)
+{
+ WebKit::Daemon::Encoder encoder;
+ encoder << reply;
+ return encoder.takeBuffer();
+}
+
} // namespace MessageInfo
template<typename Info>
@@ -415,6 +439,12 @@
case MessageType::IncrementSilentPushCount:
handleWebPushDMessageWithReply<MessageInfo::incrementSilentPushCount>(clientConnection, encodedMessage, WTFMove(replySender));
break;
+ case MessageType::RemoveAllPushSubscriptions:
+ handleWebPushDMessageWithReply<MessageInfo::removeAllPushSubscriptions>(clientConnection, encodedMessage, WTFMove(replySender));
+ break;
+ case MessageType::RemovePushSubscriptionsForOrigin:
+ handleWebPushDMessageWithReply<MessageInfo::removePushSubscriptionsForOrigin>(clientConnection, encodedMessage, WTFMove(replySender));
+ break;
}
}
@@ -609,7 +639,7 @@
});
}
-void Daemon::unsubscribeFromPushService(ClientConnection* connection, const URL& scopeURL, WebCore::PushSubscriptionIdentifier subscriptionIdentifier, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&& replySender)
+void Daemon::unsubscribeFromPushService(ClientConnection* connection, const URL& scopeURL, std::optional<WebCore::PushSubscriptionIdentifier> subscriptionIdentifier, CompletionHandler<void(const Expected<bool, WebCore::ExceptionData>&)>&& replySender)
{
runAfterStartingPushService([this, bundleIdentifier = connection->hostAppCodeSigningIdentifier(), scope = scopeURL.string(), subscriptionIdentifier, replySender = WTFMove(replySender)]() mutable {
if (!m_pushService) {
@@ -653,6 +683,30 @@
});
}
+void Daemon::removeAllPushSubscriptions(ClientConnection* connection, CompletionHandler<void(unsigned)>&& replySender)
+{
+ runAfterStartingPushService([this, bundleIdentifier = connection->hostAppCodeSigningIdentifier(), replySender = WTFMove(replySender)]() mutable {
+ if (!m_pushService) {
+ replySender(0);
+ return;
+ }
+
+ m_pushService->removeRecordsForBundleIdentifier(bundleIdentifier, WTFMove(replySender));
+ });
+}
+
+void Daemon::removePushSubscriptionsForOrigin(ClientConnection* connection, const WebCore::SecurityOriginData& securityOrigin, CompletionHandler<void(unsigned)>&& replySender)
+{
+ runAfterStartingPushService([this, bundleIdentifier = connection->hostAppCodeSigningIdentifier(), securityOrigin = securityOrigin.toString(), replySender = WTFMove(replySender)]() mutable {
+ if (!m_pushService) {
+ replySender(0);
+ return;
+ }
+
+ m_pushService->removeRecordsForBundleIdentifierAndOrigin(bundleIdentifier, securityOrigin, WTFMove(replySender));
+ });
+}
+
ClientConnection* Daemon::toClientConnection(xpc_connection_t connection)
{
auto clientConnection = m_connectionMap.get(connection);
Modified: trunk/Tools/ChangeLog (291491 => 291492)
--- trunk/Tools/ChangeLog 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Tools/ChangeLog 2022-03-18 19:19:35 UTC (rev 291492)
@@ -1,3 +1,15 @@
+2022-03-18 Ben Nham <[email protected]>
+
+ Remove push subscriptions when associated service worker registrations are removed
+ https://bugs.webkit.org/show_bug.cgi?id=237983
+
+ Reviewed by Youenn Fablet.
+
+ Add new tests to make sure that we delete push subscriptions when unregistering a service
+ worker or deleting website data.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm:
+
2022-03-18 J Pascoe <[email protected]>
Trigger PDF download in captive portal mode instead of using PDF viewer
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm (291491 => 291492)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm 2022-03-18 19:11:11 UTC (rev 291491)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebPushDaemon.mm 2022-03-18 19:19:35 UTC (rev 291492)
@@ -36,6 +36,7 @@
#import <WebKit/WKPreferencesPrivate.h>
#import <WebKit/WKProcessPoolPrivate.h>
#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKWebsiteDataRecordPrivate.h>
#import <WebKit/WKWebsiteDataStorePrivate.h>
#import <WebKit/WebPushDaemonConstants.h>
#import <WebKit/_WKExperimentalFeature.h>
@@ -434,6 +435,20 @@
[m_webView loadRequest:m_server->request()];
}
+ bool hasPushSubscription()
+ {
+ __block bool done = false;
+ __block bool result = false;
+
+ [m_dataStore _scopeURL:m_server->request().URL hasPushSubscriptionForTesting:^(BOOL fetchedResult) {
+ result = fetchedResult;
+ done = true;
+ }];
+
+ TestWebKitAPI::Util::run(&done);
+ return result;
+ }
+
~WebPushDTest()
{
cleanUpTestWebPushD(m_tempDirectory.get());
@@ -629,6 +644,8 @@
// Client public key should be 65 bytes (87 bytes in unpadded base64url).
ASSERT_EQ([subscription[@"keys"][@"p256dh"] length], 87u);
+
+ ASSERT_TRUE(hasPushSubscription());
}
TEST_F(WebPushDTest, SubscribeFailureTest)
@@ -666,6 +683,8 @@
// Spec says that an error in the push service should be an AbortError.
ASSERT_TRUE([obj isKindOfClass:[NSString class]]);
ASSERT_TRUE([obj hasPrefix:@"Error: AbortError"]);
+
+ ASSERT_FALSE(hasPushSubscription());
}
TEST_F(WebPushDTest, UnsubscribeTest)
@@ -705,8 +724,151 @@
// First unsubscribe should succeed. Second one should fail since the first one removed the record from the database.
id expected = @[@(1), @(0)];
ASSERT_TRUE([obj isEqual:expected]);
+
+ ASSERT_FALSE(hasPushSubscription());
}
+TEST_F(WebPushDTest, UnsubscribesOnServiceWorkerUnregisterTest)
+{
+ static const char* source = R"HTML(
+ <script src=""
+ <script>
+ navigator.serviceWorker.register('/sw.js').then(async () => {
+ const registration = await navigator.serviceWorker.ready;
+ let result = null;
+ try {
+ let subscription = await registration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: VALID_SERVER_KEY
+ });
+ result = await registration.unregister();
+ } catch (e) {
+ result = "Error: " + e;
+ }
+ window.webkit.messageHandlers.note.postMessage(result);
+ });
+ </script>
+ )HTML";
+
+ __block RetainPtr<id> unregisterSucceeded = nil;
+ __block bool done = false;
+ [m_notificationMessageHandler setMessageHandler:^(id message) {
+ unregisterSucceeded = message;
+ done = true;
+ }];
+
+ loadRequest(source, "");
+ TestWebKitAPI::Util::run(&done);
+
+ ASSERT_TRUE([unregisterSucceeded isEqual:@YES]);
+ ASSERT_FALSE(hasPushSubscription());
+}
+
+TEST_F(WebPushDTest, UnsubscribesOnClearingAllWebsiteData)
+{
+ static const char* source = R"HTML(
+ <script src=""
+ <script>
+ navigator.serviceWorker.register('/sw.js').then(async () => {
+ const registration = await navigator.serviceWorker.ready;
+ let result = null;
+ try {
+ let subscription = await registration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: VALID_SERVER_KEY
+ });
+ result = "Subscribed";
+ } catch (e) {
+ result = "Error: " + e;
+ }
+ window.webkit.messageHandlers.note.postMessage(result);
+ });
+ </script>
+ )HTML";
+
+ __block RetainPtr<id> result = nil;
+ __block bool done = false;
+ [m_notificationMessageHandler setMessageHandler:^(id message) {
+ result = message;
+ done = true;
+ }];
+
+ loadRequest(source, "");
+ TestWebKitAPI::Util::run(&done);
+
+ ASSERT_TRUE([result isEqualToString:@"Subscribed"]);
+
+ __block bool removedData = false;
+ [m_dataStore removeDataOfTypes:[NSSet setWithObject:WKWebsiteDataTypeServiceWorkerRegistrations] modifiedSince:[NSDate distantPast] completionHandler:^(void) {
+ removedData = true;
+ }];
+ TestWebKitAPI::Util::run(&removedData);
+
+ ASSERT_FALSE(hasPushSubscription());
+}
+
+TEST_F(WebPushDTest, UnsubscribesOnClearingWebsiteDataForOrigin)
+{
+ static const char* source = R"HTML(
+ <script src=""
+ <script>
+ navigator.serviceWorker.register('/sw.js').then(async () => {
+ const registration = await navigator.serviceWorker.ready;
+ let result = null;
+ try {
+ let subscription = await registration.pushManager.subscribe({
+ userVisibleOnly: true,
+ applicationServerKey: VALID_SERVER_KEY
+ });
+ result = "Subscribed";
+ } catch (e) {
+ result = "Error: " + e;
+ }
+ window.webkit.messageHandlers.note.postMessage(result);
+ });
+ </script>
+ )HTML";
+
+ __block RetainPtr<id> result = nil;
+ __block bool done = false;
+ [m_notificationMessageHandler setMessageHandler:^(id message) {
+ result = message;
+ done = true;
+ }];
+
+ loadRequest(source, "");
+ TestWebKitAPI::Util::run(&done);
+
+ ASSERT_TRUE([result isEqualToString:@"Subscribed"]);
+
+ __block bool fetchedRecords = false;
+ __block RetainPtr<NSArray<WKWebsiteDataRecord *>> records;
+ [m_dataStore fetchDataRecordsOfTypes:[NSSet setWithObject:WKWebsiteDataTypeServiceWorkerRegistrations] completionHandler:^(NSArray<WKWebsiteDataRecord *> *dataRecords) {
+ records = dataRecords;
+ fetchedRecords = true;
+ }];
+ TestWebKitAPI::Util::run(&fetchedRecords);
+
+ WKWebsiteDataRecord *filteredRecord = nil;
+ for (WKWebsiteDataRecord *record in records.get()) {
+ for (NSString *originString in record._originsStrings) {
+ if ([originString isEqualToString:m_server->origin()]) {
+ filteredRecord = record;
+ break;
+ }
+ }
+ }
+ ASSERT_TRUE(filteredRecord);
+
+ __block bool removedData = false;
+ [m_dataStore removeDataOfTypes:[NSSet setWithObject:WKWebsiteDataTypeServiceWorkerRegistrations] forDataRecords:[NSArray arrayWithObject:filteredRecord] completionHandler:^(void) {
+ removedData = true;
+ }];
+ TestWebKitAPI::Util::run(&removedData);
+
+ ASSERT_FALSE(hasPushSubscription());
+}
+
#if ENABLE(INSTALL_COORDINATION_BUNDLES)
#if USE(APPLE_INTERNAL_SDK)
static void deleteAllRegistrationsForDataStore(WKWebsiteDataStore *dataStore)