Commit a2fd2a0f authored by Viviane Yang's avatar Viviane Yang Committed by Commit Bot

[Push] Add feature flag for push subscriptions with expiration time

This CL enables Push Subscriptions to support a expiration time, set by
Chrome in push_messaging_constants.h (currently 90 days). This feature
is disabled by default, so to try it out you must set --enable-features=
PushSubscriptionWithExpirationTime.

3 BrowserTests are added to check the expiration time behaviour when the
flag is set or not set.

The expiration time is set in PushMessagingServiceImpl when a
subscription is made and saved by PushMessagingAppIdentifier in the
browser preference. The following CLs prepare for this change:

1. 2292292: [Push] Add expirationTime attribute to PushSubscription
https://chromium-review.googlesource.com/c/chromium/src/+/2292292

2. 2302192: [Push] Pass expirationTime attribute from
PushMessagingService to PushManager
https://chromium-review.googlesource.com/c/chromium/src/+/2302192

3. 2315682: [Push] Add expiration time property in app identifier
https://chromium-review.googlesource.com/c/chromium/src/+/2315682


Bug: 1104215
Change-Id: I341f05096fa57246fa18cb338a1a59f7a1ae01ee
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2302610Reviewed-by: default avatarPeter Beverloo <peter@chromium.org>
Reviewed-by: default avatarRichard Knoll <knollr@chromium.org>
Reviewed-by: default avatarRayan Kanso <rayankans@chromium.org>
Commit-Queue: Viviane Yang <viviy@google.com>
Cr-Commit-Position: refs/heads/master@{#793653}
parent f1a8d7ef
...@@ -34,16 +34,16 @@ constexpr size_t kGuidLength = 36; // "%08X-%04X-%04X-%04X-%012llX" ...@@ -34,16 +34,16 @@ constexpr size_t kGuidLength = 36; // "%08X-%04X-%04X-%04X-%012llX"
std::string FromTimeToString(base::Time time) { std::string FromTimeToString(base::Time time) {
DCHECK(!time.is_null()); DCHECK(!time.is_null());
return base::NumberToString(time.ToDeltaSinceWindowsEpoch().InSeconds()); return base::NumberToString(time.ToDeltaSinceWindowsEpoch().InMilliseconds());
} }
bool FromStringToTime(const std::string& time_string, bool FromStringToTime(const std::string& time_string,
base::Optional<base::Time>* time) { base::Optional<base::Time>* time) {
DCHECK(!time_string.empty()); DCHECK(!time_string.empty());
int64_t seconds; int64_t milliseconds;
if (base::StringToInt64(time_string, &seconds) && seconds > 0) { if (base::StringToInt64(time_string, &milliseconds) && milliseconds > 0) {
*time = base::make_optional(base::Time::FromDeltaSinceWindowsEpoch( *time = base::make_optional(base::Time::FromDeltaSinceWindowsEpoch(
base::TimeDelta::FromSeconds(seconds))); base::TimeDelta::FromMilliseconds(milliseconds)));
return true; return true;
} }
return false; return false;
...@@ -75,9 +75,8 @@ bool DisassemblePrefValue(const std::string& pref_value, ...@@ -75,9 +75,8 @@ bool DisassemblePrefValue(const std::string& pref_value,
return false; return false;
*origin = GURL(parts[0]); *origin = GURL(parts[0]);
if (!origin->is_valid()) { if (!origin->is_valid())
return false; return false;
}
if (parts.size() == 3) if (parts.size() == 3)
return FromStringToTime(parts[2], expiration_time); return FromStringToTime(parts[2], expiration_time);
......
...@@ -100,6 +100,10 @@ class PushMessagingAppIdentifier { ...@@ -100,6 +100,10 @@ class PushMessagingAppIdentifier {
return service_worker_registration_id_; return service_worker_registration_id_;
} }
void set_expiration_time(const base::Optional<base::Time>& expiration_time) {
expiration_time_ = expiration_time;
}
base::Optional<base::Time> expiration_time() const { base::Optional<base::Time> expiration_time() const {
DCHECK(!is_null()); DCHECK(!is_null());
return expiration_time_; return expiration_time_;
......
...@@ -2627,7 +2627,8 @@ class PushMessagingDisallowSenderIdsBrowserTest ...@@ -2627,7 +2627,8 @@ class PushMessagingDisallowSenderIdsBrowserTest
: public PushMessagingBrowserTest { : public PushMessagingBrowserTest {
public: public:
PushMessagingDisallowSenderIdsBrowserTest() { PushMessagingDisallowSenderIdsBrowserTest() {
scoped_feature_list_.InitAndEnableFeature(kPushMessagingDisallowSenderIDs); scoped_feature_list_.InitAndEnableFeature(
features::kPushMessagingDisallowSenderIDs);
} }
~PushMessagingDisallowSenderIdsBrowserTest() override = default; ~PushMessagingDisallowSenderIdsBrowserTest() override = default;
...@@ -2660,3 +2661,109 @@ IN_PROC_BROWSER_TEST_F(PushMessagingDisallowSenderIdsBrowserTest, ...@@ -2660,3 +2661,109 @@ IN_PROC_BROWSER_TEST_F(PushMessagingDisallowSenderIdsBrowserTest,
"supported, please upgrade to VAPID authentication instead", "supported, please upgrade to VAPID authentication instead",
script_result); script_result);
} }
class PushSubscriptionWithExpirationTimeTest : public PushMessagingBrowserTest {
public:
PushSubscriptionWithExpirationTimeTest() {
scoped_feature_list_.InitAndEnableFeature(
features::kPushSubscriptionWithExpirationTime);
}
~PushSubscriptionWithExpirationTimeTest() override = default;
// Checks whether |expiration_time| lies in the future and is in the
// valid format (seconds elapsed since Unix time)
bool IsExpirationTimeValid(const std::string& expiration_time);
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
bool PushSubscriptionWithExpirationTimeTest::IsExpirationTimeValid(
const std::string& expiration_time) {
int64_t output;
if (!base::StringToInt64(expiration_time, &output))
return false;
return base::Time::Now().ToJsTimeIgnoringNull() < output;
}
IN_PROC_BROWSER_TEST_F(PushSubscriptionWithExpirationTimeTest,
SubscribeGetSubscriptionWithExpirationTime) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
ASSERT_NO_FATAL_FAILURE(RequestAndAcceptPermission());
LoadTestPage(); // Reload to become controlled.
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("true - is controlled", script_result);
// Subscribe with expiration time enabled, should get a subscription with
// expiration time in the future back
std::string subscription_expiration_time;
ASSERT_TRUE(RunScript("documentSubscribePushGetExpirationTime()",
&subscription_expiration_time));
EXPECT_TRUE(IsExpirationTimeValid(subscription_expiration_time));
std::string get_subscription_expiration_time;
// Get subscription should also yield a subscription with expiration time
ASSERT_TRUE(RunScript("GetSubscriptionExpirationTime()",
&get_subscription_expiration_time));
EXPECT_TRUE(IsExpirationTimeValid(get_subscription_expiration_time));
// Both methods should return the same expiration time
ASSERT_EQ(subscription_expiration_time, get_subscription_expiration_time);
}
IN_PROC_BROWSER_TEST_F(PushSubscriptionWithExpirationTimeTest,
GetSubscriptionWithExpirationTime) {
std::string script_result;
ASSERT_NO_FATAL_FAILURE(SubscribeSuccessfully());
ASSERT_TRUE(RunScript("hasSubscription()", &script_result));
EXPECT_EQ("true - subscribed", script_result);
// Get subscription should also yield a subscription with expiration time
ASSERT_TRUE(RunScript("GetSubscriptionExpirationTime()", &script_result));
EXPECT_TRUE(IsExpirationTimeValid(script_result));
}
class PushSubscriptionWithoutExpirationTimeTest
: public PushMessagingBrowserTest {
public:
PushSubscriptionWithoutExpirationTimeTest() {
// Override current feature list to ensure having
// |kPushSubscriptionWithExpirationTime| disabled
scoped_feature_list_.InitAndDisableFeature(
features::kPushSubscriptionWithExpirationTime);
}
~PushSubscriptionWithoutExpirationTimeTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_F(PushSubscriptionWithoutExpirationTimeTest,
SubscribeDocumentExpirationTimeNull) {
std::string script_result;
ASSERT_TRUE(RunScript("registerServiceWorker()", &script_result));
ASSERT_EQ("ok - service worker registered", script_result);
ASSERT_NO_FATAL_FAILURE(RequestAndAcceptPermission());
LoadTestPage(); // Reload to become controlled.
ASSERT_TRUE(RunScript("isControlled()", &script_result));
ASSERT_EQ("true - is controlled", script_result);
// When |features::kPushSubscriptionWithExpirationTime| is disabled,
// expiration time should be null
ASSERT_TRUE(
RunScript("documentSubscribePushGetExpirationTime()", &script_result));
EXPECT_EQ("null", script_result);
}
...@@ -5,10 +5,18 @@ ...@@ -5,10 +5,18 @@
#ifndef CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_ #ifndef CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_
#define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_ #define CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_
#include "base/time/time.h"
extern const char kPushMessagingGcmEndpoint[]; extern const char kPushMessagingGcmEndpoint[];
// The tag of the notification that will be automatically shown if a webapp // The tag of the notification that will be automatically shown if a webapp
// receives a push message then fails to show a notification. // receives a push message then fails to show a notification.
extern const char kPushMessagingForcedNotificationTag[]; extern const char kPushMessagingForcedNotificationTag[];
// Chrome decided cadence on subscription refreshes. According to the standards:
// https://w3c.github.io/push-api/#dfn-subscription-expiration-time it is
// optional and set by the browser.
constexpr base::TimeDelta kPushSubscriptionExpirationPeriodTimeDelta =
base::TimeDelta::FromDays(90);
#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_ #endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_CONSTANTS_H_
...@@ -4,5 +4,12 @@ ...@@ -4,5 +4,12 @@
#include "chrome/browser/push_messaging/push_messaging_features.h" #include "chrome/browser/push_messaging/push_messaging_features.h"
namespace features {
const base::Feature kPushMessagingDisallowSenderIDs{ const base::Feature kPushMessagingDisallowSenderIDs{
"PushMessagingDisallowSenderIDs", base::FEATURE_DISABLED_BY_DEFAULT}; "PushMessagingDisallowSenderIDs", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kPushSubscriptionWithExpirationTime{
"PushSubscriptionWithExpirationTime", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
...@@ -7,7 +7,15 @@ ...@@ -7,7 +7,15 @@
#include "base/feature_list.h" #include "base/feature_list.h"
namespace features {
// Feature flag to disallow creation of push messages with GCM Sender IDs. // Feature flag to disallow creation of push messages with GCM Sender IDs.
extern const base::Feature kPushMessagingDisallowSenderIDs; extern const base::Feature kPushMessagingDisallowSenderIDs;
// Feature flag to enable push subscription with expiration times specified in
// /chrome/browser/push_messaging/push_messaging_constants.h
extern const base::Feature kPushSubscriptionWithExpirationTime;
} // namespace features
#endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_FEATURES_H_ #endif // CHROME_BROWSER_PUSH_MESSAGING_PUSH_MESSAGING_FEATURES_H_
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h" #include "content/public/common/child_process_host.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "third_party/blink/public/mojom/permissions/permission_status.mojom.h" #include "third_party/blink/public/mojom/permissions/permission_status.mojom.h"
#include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom.h" #include "third_party/blink/public/mojom/push_messaging/push_messaging_status.mojom.h"
...@@ -589,7 +590,7 @@ void PushMessagingServiceImpl::SubscribeFromDocument( ...@@ -589,7 +590,7 @@ void PushMessagingServiceImpl::SubscribeFromDocument(
ContentSettingsType::NOTIFICATIONS, render_frame_host, requesting_origin, ContentSettingsType::NOTIFICATIONS, render_frame_host, requesting_origin,
user_gesture, user_gesture,
base::BindOnce(&PushMessagingServiceImpl::DoSubscribe, base::BindOnce(&PushMessagingServiceImpl::DoSubscribe,
weak_factory_.GetWeakPtr(), app_identifier, weak_factory_.GetWeakPtr(), std::move(app_identifier),
std::move(options), std::move(callback), render_process_id, std::move(options), std::move(callback), render_process_id,
render_frame_id)); render_frame_id));
} }
...@@ -627,7 +628,8 @@ void PushMessagingServiceImpl::SubscribeFromWorker( ...@@ -627,7 +628,8 @@ void PushMessagingServiceImpl::SubscribeFromWorker(
return; return;
} }
DoSubscribe(app_identifier, std::move(options), std::move(register_callback), DoSubscribe(std::move(app_identifier), std::move(options),
std::move(register_callback),
/* render_process_id= */ -1, /* render_frame_id= */ -1, /* render_process_id= */ -1, /* render_frame_id= */ -1,
CONTENT_SETTING_ALLOW); CONTENT_SETTING_ALLOW);
} }
...@@ -653,7 +655,7 @@ bool PushMessagingServiceImpl::SupportNonVisibleMessages() { ...@@ -653,7 +655,7 @@ bool PushMessagingServiceImpl::SupportNonVisibleMessages() {
} }
void PushMessagingServiceImpl::DoSubscribe( void PushMessagingServiceImpl::DoSubscribe(
const PushMessagingAppIdentifier& app_identifier, PushMessagingAppIdentifier app_identifier,
blink::mojom::PushSubscriptionOptionsPtr options, blink::mojom::PushSubscriptionOptionsPtr options,
RegisterCallback register_callback, RegisterCallback register_callback,
int render_process_id, int render_process_id,
...@@ -679,7 +681,8 @@ void PushMessagingServiceImpl::DoSubscribe( ...@@ -679,7 +681,8 @@ void PushMessagingServiceImpl::DoSubscribe(
content::RenderFrameHost* main_frame = content::RenderFrameHost* main_frame =
GetMainFrameForRenderFrameHost(render_frame_host); GetMainFrameForRenderFrameHost(render_frame_host);
if (base::FeatureList::IsEnabled(kPushMessagingDisallowSenderIDs)) { if (base::FeatureList::IsEnabled(
features::kPushMessagingDisallowSenderIDs)) {
if (main_frame) { if (main_frame) {
main_frame->AddMessageToConsole( main_frame->AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kError, blink::mojom::ConsoleMessageLevel::kError,
...@@ -698,11 +701,21 @@ void PushMessagingServiceImpl::DoSubscribe( ...@@ -698,11 +701,21 @@ void PushMessagingServiceImpl::DoSubscribe(
IncreasePushSubscriptionCount(1, true /* is_pending */); IncreasePushSubscriptionCount(1, true /* is_pending */);
// Set time to live for GCM registration
base::TimeDelta ttl = base::TimeDelta();
if (base::FeatureList::IsEnabled(
features::kPushSubscriptionWithExpirationTime)) {
app_identifier.set_expiration_time(
base::Time::Now() + kPushSubscriptionExpirationPeriodTimeDelta);
DCHECK(app_identifier.expiration_time());
ttl = kPushSubscriptionExpirationPeriodTimeDelta;
}
GetInstanceIDDriver() GetInstanceIDDriver()
->GetInstanceID(app_identifier.app_id()) ->GetInstanceID(app_identifier.app_id())
->GetToken(NormalizeSenderInfo(application_server_key_string), kGCMScope, ->GetToken(NormalizeSenderInfo(application_server_key_string), kGCMScope,
base::TimeDelta() /* time_to_live */, ttl, std::map<std::string, std::string>() /* options */,
std::map<std::string, std::string>() /* options */,
{} /* flags */, {} /* flags */,
base::BindOnce(&PushMessagingServiceImpl::DidSubscribe, base::BindOnce(&PushMessagingServiceImpl::DidSubscribe,
weak_factory_.GetWeakPtr(), app_identifier, weak_factory_.GetWeakPtr(), app_identifier,
...@@ -714,12 +727,12 @@ void PushMessagingServiceImpl::SubscribeEnd( ...@@ -714,12 +727,12 @@ void PushMessagingServiceImpl::SubscribeEnd(
RegisterCallback callback, RegisterCallback callback,
const std::string& subscription_id, const std::string& subscription_id,
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth, const std::vector<uint8_t>& auth,
blink::mojom::PushRegistrationStatus status) { blink::mojom::PushRegistrationStatus status) {
std::move(callback).Run(subscription_id, endpoint, std::move(callback).Run(subscription_id, endpoint, expiration_time, p256dh,
base::nullopt /* expiration_time*/, p256dh, auth, auth, status);
status);
} }
void PushMessagingServiceImpl::SubscribeEndWithError( void PushMessagingServiceImpl::SubscribeEndWithError(
...@@ -727,6 +740,7 @@ void PushMessagingServiceImpl::SubscribeEndWithError( ...@@ -727,6 +740,7 @@ void PushMessagingServiceImpl::SubscribeEndWithError(
blink::mojom::PushRegistrationStatus status) { blink::mojom::PushRegistrationStatus status) {
SubscribeEnd(std::move(callback), std::string() /* subscription_id */, SubscribeEnd(std::move(callback), std::string() /* subscription_id */,
GURL::EmptyGURL() /* endpoint */, GURL::EmptyGURL() /* endpoint */,
base::nullopt /* expiration_time */,
std::vector<uint8_t>() /* p256dh */, std::vector<uint8_t>() /* p256dh */,
std::vector<uint8_t>() /* auth */, status); std::vector<uint8_t>() /* auth */, status);
} }
...@@ -793,6 +807,7 @@ void PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo( ...@@ -793,6 +807,7 @@ void PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo(
IncreasePushSubscriptionCount(1, false /* is_pending */); IncreasePushSubscriptionCount(1, false /* is_pending */);
SubscribeEnd(std::move(callback), subscription_id, endpoint, SubscribeEnd(std::move(callback), subscription_id, endpoint,
app_identifier.expiration_time(),
std::vector<uint8_t>(p256dh.begin(), p256dh.end()), std::vector<uint8_t>(p256dh.begin(), p256dh.end()),
std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()), std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()),
blink::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE); blink::mojom::PushRegistrationStatus::SUCCESS_FROM_PUSH_SERVICE);
...@@ -800,8 +815,6 @@ void PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo( ...@@ -800,8 +815,6 @@ void PushMessagingServiceImpl::DidSubscribeWithEncryptionInfo(
// GetSubscriptionInfo methods ------------------------------------------------- // GetSubscriptionInfo methods -------------------------------------------------
// TODO(crbug.com/1104215): Get |expiration_time| from |app_identifier|, where
// it is stored in profile preferences
void PushMessagingServiceImpl::GetSubscriptionInfo( void PushMessagingServiceImpl::GetSubscriptionInfo(
const GURL& origin, const GURL& origin,
int64_t service_worker_registration_id, int64_t service_worker_registration_id,
...@@ -822,10 +835,12 @@ void PushMessagingServiceImpl::GetSubscriptionInfo( ...@@ -822,10 +835,12 @@ void PushMessagingServiceImpl::GetSubscriptionInfo(
const GURL endpoint = CreateEndpoint(subscription_id); const GURL endpoint = CreateEndpoint(subscription_id);
const std::string& app_id = app_identifier.app_id(); const std::string& app_id = app_identifier.app_id();
base::Optional<base::Time> expiration_time = app_identifier.expiration_time();
base::OnceCallback<void(bool)> validate_cb = base::OnceCallback<void(bool)> validate_cb =
base::BindOnce(&PushMessagingServiceImpl::DidValidateSubscription, base::BindOnce(&PushMessagingServiceImpl::DidValidateSubscription,
weak_factory_.GetWeakPtr(), app_id, sender_id, endpoint, weak_factory_.GetWeakPtr(), app_id, sender_id, endpoint,
std::move(callback)); expiration_time, std::move(callback));
if (PushMessagingAppIdentifier::UseInstanceID(app_id)) { if (PushMessagingAppIdentifier::UseInstanceID(app_id)) {
GetInstanceIDDriver()->GetInstanceID(app_id)->ValidateToken( GetInstanceIDDriver()->GetInstanceID(app_id)->ValidateToken(
...@@ -842,6 +857,7 @@ void PushMessagingServiceImpl::DidValidateSubscription( ...@@ -842,6 +857,7 @@ void PushMessagingServiceImpl::DidValidateSubscription(
const std::string& app_id, const std::string& app_id,
const std::string& sender_id, const std::string& sender_id,
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
SubscriptionInfoCallback callback, SubscriptionInfoCallback callback,
bool is_valid) { bool is_valid) {
if (!is_valid) { if (!is_valid) {
...@@ -855,19 +871,20 @@ void PushMessagingServiceImpl::DidValidateSubscription( ...@@ -855,19 +871,20 @@ void PushMessagingServiceImpl::DidValidateSubscription(
GetEncryptionInfoForAppId( GetEncryptionInfoForAppId(
app_id, sender_id, app_id, sender_id,
base::BindOnce(&PushMessagingServiceImpl::DidGetEncryptionInfo, base::BindOnce(&PushMessagingServiceImpl::DidGetEncryptionInfo,
weak_factory_.GetWeakPtr(), endpoint, weak_factory_.GetWeakPtr(), endpoint, expiration_time,
std::move(callback))); std::move(callback)));
} }
void PushMessagingServiceImpl::DidGetEncryptionInfo( void PushMessagingServiceImpl::DidGetEncryptionInfo(
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
SubscriptionInfoCallback callback, SubscriptionInfoCallback callback,
std::string p256dh, std::string p256dh,
std::string auth_secret) const { std::string auth_secret) const {
// I/O errors might prevent the GCM Driver from retrieving a key-pair. // I/O errors might prevent the GCM Driver from retrieving a key-pair.
bool is_valid = !p256dh.empty(); bool is_valid = !p256dh.empty();
std::move(callback).Run( std::move(callback).Run(
is_valid, endpoint, base::nullopt /* expiration_time */, is_valid, endpoint, expiration_time,
std::vector<uint8_t>(p256dh.begin(), p256dh.end()), std::vector<uint8_t>(p256dh.begin(), p256dh.end()),
std::vector<uint8_t>(auth_secret.begin(), auth_secret.end())); std::vector<uint8_t>(auth_secret.begin(), auth_secret.end()));
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/time/time.h"
#include "chrome/browser/push_messaging/push_messaging_notification_manager.h" #include "chrome/browser/push_messaging/push_messaging_notification_manager.h"
#include "chrome/common/buildflags.h" #include "chrome/common/buildflags.h"
#include "components/content_settings/core/browser/content_settings_observer.h" #include "components/content_settings/core/browser/content_settings_observer.h"
...@@ -165,7 +166,7 @@ class PushMessagingServiceImpl : public content::PushMessagingService, ...@@ -165,7 +166,7 @@ class PushMessagingServiceImpl : public content::PushMessagingService,
// Subscribe methods --------------------------------------------------------- // Subscribe methods ---------------------------------------------------------
void DoSubscribe(const PushMessagingAppIdentifier& app_identifier, void DoSubscribe(PushMessagingAppIdentifier app_identifier,
blink::mojom::PushSubscriptionOptionsPtr options, blink::mojom::PushSubscriptionOptionsPtr options,
RegisterCallback callback, RegisterCallback callback,
int render_process_id, int render_process_id,
...@@ -175,6 +176,7 @@ class PushMessagingServiceImpl : public content::PushMessagingService, ...@@ -175,6 +176,7 @@ class PushMessagingServiceImpl : public content::PushMessagingService,
void SubscribeEnd(RegisterCallback callback, void SubscribeEnd(RegisterCallback callback,
const std::string& subscription_id, const std::string& subscription_id,
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth, const std::vector<uint8_t>& auth,
blink::mojom::PushRegistrationStatus status); blink::mojom::PushRegistrationStatus status);
...@@ -198,13 +200,16 @@ class PushMessagingServiceImpl : public content::PushMessagingService, ...@@ -198,13 +200,16 @@ class PushMessagingServiceImpl : public content::PushMessagingService,
// GetSubscriptionInfo methods ----------------------------------------------- // GetSubscriptionInfo methods -----------------------------------------------
void DidValidateSubscription(const std::string& app_id, void DidValidateSubscription(
const std::string& sender_id, const std::string& app_id,
const GURL& endpoint, const std::string& sender_id,
SubscriptionInfoCallback callback, const GURL& endpoint,
bool is_valid); const base::Optional<base::Time>& expiration_time,
SubscriptionInfoCallback callback,
bool is_valid);
void DidGetEncryptionInfo(const GURL& endpoint, void DidGetEncryptionInfo(const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
SubscriptionInfoCallback callback, SubscriptionInfoCallback callback,
std::string p256dh, std::string p256dh,
std::string auth_secret) const; std::string auth_secret) const;
......
...@@ -140,6 +140,18 @@ function documentSubscribePushWithBase64URLEncodedString() { ...@@ -140,6 +140,18 @@ function documentSubscribePushWithBase64URLEncodedString() {
}).catch(sendErrorToTest); }).catch(sendErrorToTest);
} }
function documentSubscribePushGetExpirationTime() {
navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: kApplicationServerKey.buffer
})
.then(function(subscription) {
sendResultToTest(subscription.expirationTime);
});
}).catch(sendErrorToTest);
}
function workerSubscribePush() { function workerSubscribePush() {
// Send the message to the worker for it to subscribe // Send the message to the worker for it to subscribe
navigator.serviceWorker.controller.postMessage({command: 'workerSubscribe'}); navigator.serviceWorker.controller.postMessage({command: 'workerSubscribe'});
...@@ -176,6 +188,15 @@ function GetP256dh() { ...@@ -176,6 +188,15 @@ function GetP256dh() {
}).catch(sendErrorToTest); }).catch(sendErrorToTest);
} }
function GetSubscriptionExpirationTime() {
navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.getSubscription()
.then(function(subscription) {
sendResultToTest(subscription.expirationTime);
});
}).catch(sendErrorToTest);
}
function pushManagerPermissionState() { function pushManagerPermissionState() {
navigator.serviceWorker.ready.then(function(swRegistration) { navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.permissionState({userVisibleOnly: true}) return swRegistration.pushManager.permissionState({userVisibleOnly: true})
......
...@@ -535,7 +535,7 @@ void PushMessagingManager::Core::DidRegister( ...@@ -535,7 +535,7 @@ void PushMessagingManager::Core::DidRegister(
FROM_HERE, ServiceWorkerContext::GetCoreThreadId(), FROM_HERE, ServiceWorkerContext::GetCoreThreadId(),
base::BindOnce(&PushMessagingManager::PersistRegistrationOnSW, base::BindOnce(&PushMessagingManager::PersistRegistrationOnSW,
sw_parent_, std::move(data), push_subscription_id, sw_parent_, std::move(data), push_subscription_id,
endpoint, p256dh, auth, endpoint, expiration_time, p256dh, auth,
subscription_changed subscription_changed
? blink::mojom::PushRegistrationStatus:: ? blink::mojom::PushRegistrationStatus::
SUCCESS_NEW_SUBSCRIPTION_FROM_PUSH_SERVICE SUCCESS_NEW_SUBSCRIPTION_FROM_PUSH_SERVICE
...@@ -555,6 +555,7 @@ void PushMessagingManager::PersistRegistrationOnSW( ...@@ -555,6 +555,7 @@ void PushMessagingManager::PersistRegistrationOnSW(
RegisterData data, RegisterData data,
const std::string& push_subscription_id, const std::string& push_subscription_id,
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth, const std::vector<uint8_t>& auth,
blink::mojom::PushRegistrationStatus status) { blink::mojom::PushRegistrationStatus status) {
...@@ -571,12 +572,13 @@ void PushMessagingManager::PersistRegistrationOnSW( ...@@ -571,12 +572,13 @@ void PushMessagingManager::PersistRegistrationOnSW(
{kPushSenderIdServiceWorkerKey, application_server_key}}, {kPushSenderIdServiceWorkerKey, application_server_key}},
base::BindOnce(&PushMessagingManager::DidPersistRegistrationOnSW, base::BindOnce(&PushMessagingManager::DidPersistRegistrationOnSW,
weak_factory_.GetWeakPtr(), std::move(data), endpoint, weak_factory_.GetWeakPtr(), std::move(data), endpoint,
p256dh, auth, status)); expiration_time, p256dh, auth, status));
} }
void PushMessagingManager::DidPersistRegistrationOnSW( void PushMessagingManager::DidPersistRegistrationOnSW(
RegisterData data, RegisterData data,
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth, const std::vector<uint8_t>& auth,
blink::mojom::PushRegistrationStatus push_registration_status, blink::mojom::PushRegistrationStatus push_registration_status,
...@@ -584,7 +586,7 @@ void PushMessagingManager::DidPersistRegistrationOnSW( ...@@ -584,7 +586,7 @@ void PushMessagingManager::DidPersistRegistrationOnSW(
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
if (service_worker_status == blink::ServiceWorkerStatusCode::kOk) { if (service_worker_status == blink::ServiceWorkerStatusCode::kOk) {
SendSubscriptionSuccess(std::move(data), push_registration_status, endpoint, SendSubscriptionSuccess(std::move(data), push_registration_status, endpoint,
p256dh, auth); expiration_time, p256dh, auth);
} else { } else {
// TODO(johnme): Unregister, so PushMessagingServiceImpl can decrease count. // TODO(johnme): Unregister, so PushMessagingServiceImpl can decrease count.
SendSubscriptionError(std::move(data), SendSubscriptionError(std::move(data),
...@@ -604,6 +606,7 @@ void PushMessagingManager::SendSubscriptionSuccess( ...@@ -604,6 +606,7 @@ void PushMessagingManager::SendSubscriptionSuccess(
RegisterData data, RegisterData data,
blink::mojom::PushRegistrationStatus status, blink::mojom::PushRegistrationStatus status,
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth) { const std::vector<uint8_t>& auth) {
DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId()); DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
...@@ -619,8 +622,8 @@ void PushMessagingManager::SendSubscriptionSuccess( ...@@ -619,8 +622,8 @@ void PushMessagingManager::SendSubscriptionSuccess(
std::move(data.callback) std::move(data.callback)
.Run(status, blink::mojom::PushSubscription::New( .Run(status, blink::mojom::PushSubscription::New(
endpoint, base::nullopt /* expiration_time */, endpoint, expiration_time, std::move(data.options),
std::move(data.options), p256dh, auth)); p256dh, auth));
RecordRegistrationStatus(status); RecordRegistrationStatus(status);
} }
......
...@@ -78,16 +78,19 @@ class PushMessagingManager : public blink::mojom::PushMessaging { ...@@ -78,16 +78,19 @@ class PushMessagingManager : public blink::mojom::PushMessaging {
blink::ServiceWorkerStatusCode service_worker_status); blink::ServiceWorkerStatusCode service_worker_status);
// Called via PostTask from UI thread. // Called via PostTask from UI thread.
void PersistRegistrationOnSW(RegisterData data, void PersistRegistrationOnSW(
const std::string& push_subscription_id, RegisterData data,
const GURL& endpoint, const std::string& push_subscription_id,
const std::vector<uint8_t>& p256dh, const GURL& endpoint,
const std::vector<uint8_t>& auth, const base::Optional<base::Time>& expiration_time,
blink::mojom::PushRegistrationStatus status); const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth,
blink::mojom::PushRegistrationStatus status);
void DidPersistRegistrationOnSW( void DidPersistRegistrationOnSW(
RegisterData data, RegisterData data,
const GURL& endpoint, const GURL& endpoint,
const base::Optional<base::Time>& expiration_time,
const std::vector<uint8_t>& p256dh, const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth, const std::vector<uint8_t>& auth,
blink::mojom::PushRegistrationStatus push_registration_status, blink::mojom::PushRegistrationStatus push_registration_status,
...@@ -97,11 +100,13 @@ class PushMessagingManager : public blink::mojom::PushMessaging { ...@@ -97,11 +100,13 @@ class PushMessagingManager : public blink::mojom::PushMessaging {
void SendSubscriptionError(RegisterData data, void SendSubscriptionError(RegisterData data,
blink::mojom::PushRegistrationStatus status); blink::mojom::PushRegistrationStatus status);
// Called both from "SW core" thread, and via PostTask from UI thread. // Called both from "SW core" thread, and via PostTask from UI thread.
void SendSubscriptionSuccess(RegisterData data, void SendSubscriptionSuccess(
blink::mojom::PushRegistrationStatus status, RegisterData data,
const GURL& endpoint, blink::mojom::PushRegistrationStatus status,
const std::vector<uint8_t>& p256dh, const GURL& endpoint,
const std::vector<uint8_t>& auth); const base::Optional<base::Time>& expiration_time,
const std::vector<uint8_t>& p256dh,
const std::vector<uint8_t>& auth);
void UnsubscribeHavingGottenSenderId( void UnsubscribeHavingGottenSenderId(
UnsubscribeCallback callback, UnsubscribeCallback callback,
......
...@@ -40,8 +40,11 @@ const uint8_t kAuthentication[] = {0xA5, 0xD9, 0x3C, 0x43, 0x0C, 0x00, ...@@ -40,8 +40,11 @@ const uint8_t kAuthentication[] = {0xA5, 0xD9, 0x3C, 0x43, 0x0C, 0x00,
static_assert(sizeof(kAuthentication) == 12, static_assert(sizeof(kAuthentication) == 12,
"The fake authentication key must be at least 12 bytes in size."); "The fake authentication key must be at least 12 bytes in size.");
const int64_t kTestExpirationWindowInDays = 90;
base::Time GetFutureTime() { base::Time GetFutureTime() {
return base::Time::Now() + base::TimeDelta::FromDays(100); return base::Time::Now() +
base::TimeDelta::FromDays(kTestExpirationWindowInDays);
} }
} // anonymous namespace } // anonymous namespace
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
<head> <head>
<title>Stringifying a PushSubscription object includes all object members</title> <title>Stringifying a PushSubscription object includes all object members</title>
<link rel="manifest" href="resources/push_manifest.json"> <link rel="manifest" href="resources/push_manifest.json">
<script src="resources/push-constants.js"></script>
<script src="../resources/testharness.js"></script> <script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script> <script src="../resources/testharnessreport.js"></script>
<script src="../serviceworker/resources/test-helpers.js"></script> <script src="../serviceworker/resources/test-helpers.js"></script>
...@@ -36,9 +37,12 @@ async_test(function(test) { ...@@ -36,9 +37,12 @@ async_test(function(test) {
assert_own_property(reflectedObject, 'endpoint'); assert_own_property(reflectedObject, 'endpoint');
assert_equals(reflectedObject.endpoint, pushSubscription.endpoint); assert_equals(reflectedObject.endpoint, pushSubscription.endpoint);
// Expiration time should be in the expected window
assert_own_property(reflectedObject, 'expirationTime'); assert_own_property(reflectedObject, 'expirationTime');
assert_equals(reflectedObject.expirationTime, null); assert_true(typeof pushSubscription.expirationTime === 'number');
assert_approx_equals(pushSubscription.expirationTime, Date.now() +
EXPIRATION_WINDOW, EXPIRATION_TIME_TOLERANCE,
`Expiration time should be in expected window: ${EXPIRATION_TIME_TOLERANCE} ms`);
assert_own_property(reflectedObject, 'keys'); assert_own_property(reflectedObject, 'keys');
assert_own_property(reflectedObject.keys, 'p256dh'); assert_own_property(reflectedObject.keys, 'p256dh');
assert_own_property(reflectedObject.keys, 'auth'); assert_own_property(reflectedObject.keys, 'auth');
......
...@@ -17,4 +17,8 @@ const VALID_BASE64URL_ENCODED_KEY = "BFVSaqVujqpHlzYQwWY8HmW_oXvuSMnGu78CGFNyHQx ...@@ -17,4 +17,8 @@ const VALID_BASE64URL_ENCODED_KEY = "BFVSaqVujqpHlzYQwWY8HmW_oXvuSMnGu78CGFNyHQx
const INVALID_BASE64URL_ENCODED_KEY = "BJEOX8aRBRLJ1SitNXbDH9Lc5CCIsTE33YwGakcXvoQ5K7KZq13-jxB2vhMTcX9c4-tC0h6CIFifzJhH6cNS!!!" const INVALID_BASE64URL_ENCODED_KEY = "BJEOX8aRBRLJ1SitNXbDH9Lc5CCIsTE33YwGakcXvoQ5K7KZq13-jxB2vhMTcX9c4-tC0h6CIFifzJhH6cNS!!!"
const INVALID_BASE64_ENCODED_KEY = "BJEOX8aRBRLJ1SitNXbDH9Lc5CCIsTE33YwGakcXvoQ5K7KZq13+jxB2vhMTcX9c4+tC0h6CIFifzJhH6cNS/wQ=" const INVALID_BASE64_ENCODED_KEY = "BJEOX8aRBRLJ1SitNXbDH9Lc5CCIsTE33YwGakcXvoQ5K7KZq13+jxB2vhMTcX9c4+tC0h6CIFifzJhH6cNS/wQ="
\ No newline at end of file
const EXPIRATION_WINDOW = 90 * 24 * 60 * 60 * 1000;
const EXPIRATION_TIME_TOLERANCE = 24 * 60 * 60 * 1000;
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
<head> <head>
<title>subscribe() succeeds when permission is granted and resolves with a valid subscription</title> <title>subscribe() succeeds when permission is granted and resolves with a valid subscription</title>
<link rel="manifest" href="resources/push_manifest.json"> <link rel="manifest" href="resources/push_manifest.json">
<script src="resources/push-constants.js"></script>
<script src="../resources/testharness.js"></script> <script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script> <script src="../resources/testharnessreport.js"></script>
<script src="../serviceworker/resources/test-helpers.js"></script> <script src="../serviceworker/resources/test-helpers.js"></script>
...@@ -31,11 +32,12 @@ async_test(function(test) { ...@@ -31,11 +32,12 @@ async_test(function(test) {
assert_idl_attribute(pushSubscription, 'endpoint'); assert_idl_attribute(pushSubscription, 'endpoint');
assert_equals(typeof pushSubscription.endpoint, 'string'); assert_equals(typeof pushSubscription.endpoint, 'string');
// Expiration time should be in the expected window
assert_idl_attribute(pushSubscription, 'expirationTime'); assert_idl_attribute(pushSubscription, 'expirationTime');
// TODO(viviy): check for not null after passing expiration time in assert_true(typeof pushSubscription.expirationTime === 'number');
// PushMessagingManager assert_approx_equals(pushSubscription.expirationTime, Date.now() +
assert_equals(pushSubscription.expirationTime, null); EXPIRATION_WINDOW, EXPIRATION_TIME_TOLERANCE,
`Expiration time should be in expected window: ${EXPIRATION_TIME_TOLERANCE} ms`);
try { try {
var endpointUrl = new URL(pushSubscription.endpoint); var endpointUrl = new URL(pushSubscription.endpoint);
} catch(e) { } catch(e) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment