blob: 6bc15cfb450656bc5c9ce85054ec4326f1190bc9 [file] [log] [blame]
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "NetworkNotificationManager.h"
#if ENABLE(BUILT_IN_NOTIFICATIONS)
#include "DaemonDecoder.h"
#include "DaemonEncoder.h"
#include "NetworkSession.h"
#include "WebPushDaemonConnectionConfiguration.h"
#include "WebPushMessage.h"
#include <WebCore/SecurityOriginData.h>
namespace WebKit {
using namespace WebCore;
NetworkNotificationManager::NetworkNotificationManager(NetworkSession& networkSession, const String& webPushMachServiceName)
: m_networkSession(networkSession)
{
if (!m_networkSession.sessionID().isEphemeral() && !webPushMachServiceName.isEmpty())
m_connection = makeUnique<WebPushD::Connection>(webPushMachServiceName.utf8(), *this);
}
void NetworkNotificationManager::maybeSendConnectionConfiguration() const
{
if (m_sentConnectionConfiguration)
return;
m_sentConnectionConfiguration = true;
WebPushD::WebPushDaemonConnectionConfiguration configuration;
configuration.useMockBundlesForTesting = m_networkSession.webPushDaemonUsesMockBundlesForTesting();
#if PLATFORM(COCOA)
auto token = m_networkSession.networkProcess().parentProcessConnection()->getAuditToken();
if (token) {
Vector<uint8_t> auditTokenData;
auditTokenData.resize(sizeof(*token));
memcpy(auditTokenData.data(), &(*token), sizeof(*token));
configuration.hostAppAuditTokenData = WTFMove(auditTokenData);
}
#endif
sendMessage<WebPushD::MessageType::UpdateConnectionConfiguration>(configuration);
}
void NetworkNotificationManager::requestSystemNotificationPermission(const String& originString, CompletionHandler<void(bool)>&& completionHandler)
{
sendMessageWithReply<WebPushD::MessageType::RequestSystemNotificationPermission>(WTFMove(completionHandler), originString);
}
void NetworkNotificationManager::deletePushAndNotificationRegistration(const SecurityOriginData& origin, CompletionHandler<void(const String&)>&& completionHandler)
{
sendMessageWithReply<WebPushD::MessageType::DeletePushAndNotificationRegistration>(WTFMove(completionHandler), origin.toString());
}
void NetworkNotificationManager::getOriginsWithPushAndNotificationPermissions(CompletionHandler<void(const Vector<SecurityOriginData>&)>&& completionHandler)
{
CompletionHandler<void(Vector<String>&&)> replyHandler = [completionHandler = WTFMove(completionHandler)] (Vector<String> originStrings) mutable {
Vector<SecurityOriginData> origins;
for (auto& originString : originStrings)
origins.append(SecurityOriginData::fromURL({ { }, originString }));
completionHandler(WTFMove(origins));
};
sendMessageWithReply<WebPushD::MessageType::GetOriginsWithPushAndNotificationPermissions>(WTFMove(replyHandler));
}
void NetworkNotificationManager::getPendingPushMessages(CompletionHandler<void(const Vector<WebPushMessage>&)>&& completionHandler)
{
CompletionHandler<void(Vector<WebPushMessage>&&)> replyHandler = [completionHandler = WTFMove(completionHandler)] (Vector<WebPushMessage>&& messages) mutable {
completionHandler(WTFMove(messages));
};
sendMessageWithReply<WebPushD::MessageType::GetPendingPushMessages>(WTFMove(replyHandler));
}
void NetworkNotificationManager::showNotification(const WebCore::NotificationData&)
{
if (!m_connection)
return;
// FIXME: While we don't normally land commented-out code in the tree,
// this is a nice bookmark for a development milestone; Roundtrip communication with webpushd
// Will make next development steps obvious.
//
// CompletionHandler<void(String)>&& completionHandler = [] (String reply) {
// printf("Got reply: %s\n", reply.utf8().data());
// };
//
// sendMessageWithReply<WebPushD::MessageType::EchoTwice>(WTFMove(completionHandler), String("FIXME: Do useful work here"));
}
void NetworkNotificationManager::cancelNotification(const UUID&)
{
if (!m_connection)
return;
}
void NetworkNotificationManager::clearNotifications(const Vector<UUID>&)
{
if (!m_connection)
return;
}
void NetworkNotificationManager::didDestroyNotification(const UUID&)
{
if (!m_connection)
return;
}
template<WebPushD::MessageType messageType, typename... Args>
void NetworkNotificationManager::sendMessage(Args&&... args) const
{
RELEASE_ASSERT(m_connection);
maybeSendConnectionConfiguration();
Daemon::Encoder encoder;
encoder.encode(std::forward<Args>(args)...);
m_connection->send(messageType, encoder.takeBuffer());
}
template<typename... Args> struct ReplyCaller;
template<> struct ReplyCaller<> {
static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void()>&& completionHandler)
{
completionHandler();
}
};
template<> struct ReplyCaller<String> {
static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(String&&)>&& completionHandler)
{
std::optional<String> string;
decoder >> string;
if (!string)
return completionHandler({ });
completionHandler(WTFMove(*string));
}
};
template<> struct ReplyCaller<const String&> {
static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(const String&)>&& completionHandler)
{
std::optional<String> string;
decoder >> string;
if (!string)
return completionHandler({ });
completionHandler(WTFMove(*string));
}
};
template<> struct ReplyCaller<bool> {
static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(bool)>&& completionHandler)
{
std::optional<bool> boolean;
decoder >> boolean;
if (!boolean)
return completionHandler(false);
completionHandler(*boolean);
}
};
template<> struct ReplyCaller<Vector<String>&&> {
static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Vector<String>&&)>&& completionHandler)
{
std::optional<Vector<String>> strings;
decoder >> strings;
if (!strings)
return completionHandler({ });
completionHandler(WTFMove(*strings));
}
};
template<> struct ReplyCaller<Vector<WebPushMessage>&&> {
static void callReply(Daemon::Decoder&& decoder, CompletionHandler<void(Vector<WebPushMessage>&&)>&& completionHandler)
{
std::optional<Vector<WebPushMessage>> messages;
decoder >> messages;
if (!messages)
return completionHandler({ });
completionHandler(WTFMove(*messages));
}
};
template<WebPushD::MessageType messageType, typename... Args, typename... ReplyArgs>
void NetworkNotificationManager::sendMessageWithReply(CompletionHandler<void(ReplyArgs...)>&& completionHandler, Args&&... args) const
{
RELEASE_ASSERT(m_connection);
maybeSendConnectionConfiguration();
Daemon::Encoder encoder;
encoder.encode(std::forward<Args>(args)...);
m_connection->sendWithReply(messageType, encoder.takeBuffer(), [completionHandler = WTFMove(completionHandler)] (auto replyBuffer) mutable {
Daemon::Decoder decoder(WTFMove(replyBuffer));
ReplyCaller<ReplyArgs...>::callReply(WTFMove(decoder), WTFMove(completionHandler));
});
}
} // namespace WebKit
#endif // ENABLE(BUILT_IN_NOTIFICATIONS)