diff --git a/components/brave_ads/core/internal/BUILD.gn b/components/brave_ads/core/internal/BUILD.gn index d82ef6223f8f..10b7353bd1dc 100644 --- a/components/brave_ads/core/internal/BUILD.gn +++ b/components/brave_ads/core/internal/BUILD.gn @@ -23,6 +23,8 @@ source_set("internal") { "account/account_observer.h", "account/account_util.cc", "account/account_util.h", + "account/confirmations/confirmation_dynamic_user_data_builder.cc", + "account/confirmations/confirmation_dynamic_user_data_builder.h", "account/confirmations/confirmation_info.cc", "account/confirmations/confirmation_info.h", "account/confirmations/confirmation_payload_json_writer.cc", @@ -38,6 +40,8 @@ source_set("internal") { "account/confirmations/opted_in_credential_json_writer.h", "account/confirmations/opted_in_info.cc", "account/confirmations/opted_in_info.h", + "account/confirmations/opted_in_user_data_info.cc", + "account/confirmations/opted_in_user_data_info.h", "account/deposits/cash_deposit.cc", "account/deposits/cash_deposit.h", "account/deposits/deposit_builder.cc", diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.cc new file mode 100644 index 000000000000..5fc8880963b3 --- /dev/null +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.cc @@ -0,0 +1,26 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.h" + +#include + +#include "base/functional/callback.h" +#include "base/values.h" +#include "brave/components/brave_ads/core/internal/account/user_data/diagnostic_id_user_data.h" +#include "brave/components/brave_ads/core/internal/account/user_data/system_timestamp_user_data.h" + +namespace brave_ads { + +void ConfirmationDynamicUserDataBuilder::Build( + UserDataBuilderCallback callback) const { + base::Value::Dict user_data; + user_data.Merge(user_data::GetDiagnosticId()); + user_data.Merge(user_data::GetSystemTimestamp()); + + std::move(callback).Run(std::move(user_data)); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.h b/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.h new file mode 100644 index 000000000000..a44369374660 --- /dev/null +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_ACCOUNT_CONFIRMATIONS_CONFIRMATION_DYNAMIC_USER_DATA_BUILDER_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_ACCOUNT_CONFIRMATIONS_CONFIRMATION_DYNAMIC_USER_DATA_BUILDER_H_ + +#include "brave/components/brave_ads/core/internal/account/user_data/user_data_builder_interface.h" + +namespace brave_ads { + +class ConfirmationDynamicUserDataBuilder final + : public UserDataBuilderInterface { + public: + void Build(UserDataBuilderCallback callback) const override; +}; + +} // namespace brave_ads + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_ACCOUNT_CONFIRMATIONS_CONFIRMATION_DYNAMIC_USER_DATA_BUILDER_H_ diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder_unittest.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder_unittest.cc new file mode 100644 index 000000000000..32503624ecce --- /dev/null +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder_unittest.cc @@ -0,0 +1,46 @@ +/* Copyright (c) 2020 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include + +#include "base/functional/bind.h" +#include "base/json/json_writer.h" +#include "base/values.h" +#include "brave/components/brave_ads/common/pref_names.h" +#include "brave/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.h" +#include "brave/components/brave_ads/core/internal/common/unittest/unittest_base.h" +#include "brave/components/brave_ads/core/internal/common/unittest/unittest_mock_util.h" +#include "brave/components/brave_ads/core/internal/common/unittest/unittest_time_util.h" + +// npm run test -- brave_unit_tests --filter=BatAds* + +namespace brave_ads { + +class BatAdsConfirmationDynamicUserDataBuilderTest : public UnitTestBase {}; + +TEST_F(BatAdsConfirmationDynamicUserDataBuilderTest, Build) { + // Arrange + AdsClientHelper::GetInstance()->SetStringPref( + prefs::kDiagnosticId, "c1298fde-7fdb-401f-a3ce-0b58fe86e6e2"); + + const base::Time time = + TimeFromString("November 18 2020 12:34:56.789", /*is_local*/ false); + AdvanceClockTo(time); + + // Act + + // Assert + const ConfirmationDynamicUserDataBuilder user_data_builder; + user_data_builder.Build(base::BindOnce([](base::Value::Dict user_data) { + std::string json; + ASSERT_TRUE(base::JSONWriter::Write(user_data, &json)); + + const std::string expected_json = + R"~({"diagnosticId":"c1298fde-7fdb-401f-a3ce-0b58fe86e6e2","systemTimestamp":"2020-11-18T12:00:00.000Z"})~"; + EXPECT_EQ(expected_json, json); + })); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_payload_json_writer.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_payload_json_writer.cc index 76ade8db5220..abe9eb4708e1 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmation_payload_json_writer.cc +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_payload_json_writer.cc @@ -47,7 +47,9 @@ std::string WriteConfirmationPayload(const ConfirmationInfo& confirmation) { payload.Set(kPublicKeyKey, *value); } - payload.Merge(confirmation.opted_in->user_data.Clone()); + payload.Merge(confirmation.opted_in->user_data.dynamic.Clone()); + + payload.Merge(confirmation.opted_in->user_data.fixed.Clone()); } std::string json; diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_unittest_util.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_unittest_util.cc index 271f177dd8c1..5218c87a748e 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmation_unittest_util.cc +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_unittest_util.cc @@ -18,6 +18,7 @@ #include "brave/components/brave_ads/core/internal/account/confirmations/confirmation_util.h" #include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_credential_json_writer.h" #include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_info.h" +#include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h" #include "brave/components/brave_ads/core/internal/common/logging_util.h" #include "brave/components/brave_ads/core/internal/common/unittest/unittest_time_util.h" #include "brave/components/brave_ads/core/internal/privacy/challenge_bypass_ristretto/blinded_token.h" @@ -29,8 +30,9 @@ namespace brave_ads { namespace { -absl::optional CreateOptedIn(const ConfirmationInfo& confirmation, - const base::Value::Dict& user_data) { +absl::optional CreateOptedIn( + const ConfirmationInfo& confirmation, + const OptedInUserDataInfo& opted_in_user_data) { DCHECK(ShouldRewardUser()); OptedInInfo opted_in; @@ -61,7 +63,7 @@ absl::optional CreateOptedIn(const ConfirmationInfo& confirmation, opted_in.unblinded_token = *unblinded_token; // User data - opted_in.user_data = user_data.Clone(); + opted_in.user_data = opted_in_user_data; // Credential ConfirmationInfo new_confirmation = confirmation; @@ -91,7 +93,7 @@ absl::optional CreateConfirmation( const std::string& creative_instance_id, const ConfirmationType& confirmation_type, const AdType& ad_type, - const base::Value::Dict& user_data) { + const OptedInUserDataInfo& opted_in_user_data) { DCHECK(!created_at.is_null()); DCHECK(!transaction_id.empty()); DCHECK(!creative_instance_id.empty()); @@ -110,7 +112,7 @@ absl::optional CreateConfirmation( } const absl::optional opted_in = - CreateOptedIn(confirmation, user_data); + CreateOptedIn(confirmation, opted_in_user_data); if (!opted_in) { BLOG(0, "Failed to create opted-in"); return absl::nullopt; diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder.cc index fc9151919977..499a8ab53316 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder.cc +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder.cc @@ -15,14 +15,12 @@ #include "brave/components/brave_ads/core/internal/account/user_data/catalog_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/conversion_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/created_at_timestamp_user_data.h" -#include "brave/components/brave_ads/core/internal/account/user_data/diagnostic_id_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/locale_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/mutated_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/odyssey_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/platform_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/rotating_hash_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/studies_user_data.h" -#include "brave/components/brave_ads/core/internal/account/user_data/system_timestamp_user_data.h" #include "brave/components/brave_ads/core/internal/account/user_data/version_number_user_data.h" namespace brave_ads { @@ -46,20 +44,20 @@ void ConfirmationUserDataBuilder::Build( base::Unretained(this), std::move(callback))); } +/////////////////////////////////////////////////////////////////////////////// + void ConfirmationUserDataBuilder::OnGetConversion( UserDataBuilderCallback callback, base::Value::Dict user_data) const { user_data.Merge(user_data::GetBuildChannel()); user_data.Merge(user_data::GetCatalog()); user_data.Merge(user_data::GetCreatedAtTimestamp(created_at_)); - user_data.Merge(user_data::GetDiagnosticId()); user_data.Merge(user_data::GetLocale()); user_data.Merge(user_data::GetMutated()); user_data.Merge(user_data::GetOdyssey()); user_data.Merge(user_data::GetPlatform()); user_data.Merge(user_data::GetRotatingHash(creative_instance_id_)); user_data.Merge(user_data::GetStudies()); - user_data.Merge(user_data::GetSystemTimestamp()); user_data.Merge(user_data::GetVersionNumber()); std::move(callback).Run(std::move(user_data)); diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder_unittest.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder_unittest.cc index bf1d76928843..1dfb3ceeb8ff 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder_unittest.cc +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder_unittest.cc @@ -62,7 +62,7 @@ TEST_F(BatAdsConfirmationUserDataBuilderTest, ASSERT_TRUE(base::JSONWriter::Write(user_data, &json)); const std::string pattern = - R"~({"buildChannel":"release","catalog":\[{"id":"29e5c8bc0ba319069980bb390d8e8f9b58c05a20"}],"countryCode":"US","createdAtTimestamp":"2020-11-18T12:00:00.000Z","mutated":true,"odyssey":"host","platform":"windows","rotating_hash":"p3QDOuQ3HakWNXLBZCP8dktH\+zyu7FsHpKONKhWliJE=","studies":\[],"systemTimestamp":"2020-11-18T12:00:00.000Z","versionNumber":"\d{1,}\.\d{1,}\.\d{1,}\.\d{1,}"})~"; + R"~({"buildChannel":"release","catalog":\[{"id":"29e5c8bc0ba319069980bb390d8e8f9b58c05a20"}],"countryCode":"US","createdAtTimestamp":"2020-11-18T12:00:00.000Z","mutated":true,"odyssey":"host","platform":"windows","rotating_hash":"p3QDOuQ3HakWNXLBZCP8dktH\+zyu7FsHpKONKhWliJE=","studies":\[],"versionNumber":"\d{1,}\.\d{1,}\.\d{1,}\.\d{1,}"})~"; EXPECT_TRUE(RE2::FullMatch(json, pattern)); })); } @@ -95,7 +95,7 @@ TEST_F(BatAdsConfirmationUserDataBuilderTest, ASSERT_TRUE(base::JSONWriter::Write(user_data, &json)); const std::string pattern = - R"~({"buildChannel":"release","catalog":\[{"id":"29e5c8bc0ba319069980bb390d8e8f9b58c05a20"}],"conversionEnvelope":{"alg":"crypto_box_curve25519xsalsa20poly1305","ciphertext":"(.{64})","epk":"(.{44})","nonce":"(.{32})"},"countryCode":"US","createdAtTimestamp":"2020-11-18T12:00:00.000Z","mutated":true,"odyssey":"host","platform":"windows","rotating_hash":"p3QDOuQ3HakWNXLBZCP8dktH\+zyu7FsHpKONKhWliJE=","studies":\[],"systemTimestamp":"2020-11-18T12:00:00.000Z","versionNumber":"\d{1,}\.\d{1,}\.\d{1,}\.\d{1,}"})~"; + R"~({"buildChannel":"release","catalog":\[{"id":"29e5c8bc0ba319069980bb390d8e8f9b58c05a20"}],"conversionEnvelope":{"alg":"crypto_box_curve25519xsalsa20poly1305","ciphertext":"(.{64})","epk":"(.{44})","nonce":"(.{32})"},"countryCode":"US","createdAtTimestamp":"2020-11-18T12:00:00.000Z","mutated":true,"odyssey":"host","platform":"windows","rotating_hash":"p3QDOuQ3HakWNXLBZCP8dktH\+zyu7FsHpKONKhWliJE=","studies":\[],"versionNumber":"\d{1,}\.\d{1,}\.\d{1,}\.\d{1,}"})~"; EXPECT_TRUE(RE2::FullMatch(json, pattern)); })); } diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_util.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_util.cc index 9274b0d11e6a..ef6b39fb1501 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmation_util.cc +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_util.cc @@ -19,6 +19,7 @@ #include "brave/components/brave_ads/core/internal/account/confirmations/confirmation_payload_json_writer.h" #include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_credential_json_writer.h" #include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_info.h" +#include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h" #include "brave/components/brave_ads/core/internal/common/logging_util.h" #include "brave/components/brave_ads/core/internal/deprecated/confirmations/confirmation_state_manager.h" #include "brave/components/brave_ads/core/internal/privacy/challenge_bypass_ristretto/blinded_token.h" @@ -41,7 +42,7 @@ constexpr char kVerificationSignatureKey[] = "signature"; absl::optional CreateOptedIn( privacy::TokenGeneratorInterface* token_generator, const ConfirmationInfo& confirmation, - base::Value::Dict user_data) { + const OptedInUserDataInfo& opted_in_user_data) { DCHECK(token_generator); DCHECK(ShouldRewardUser()); @@ -74,16 +75,28 @@ absl::optional CreateOptedIn( opted_in.unblinded_token = *unblinded_token; // User data - opted_in.user_data = std::move(user_data); + opted_in.user_data = opted_in_user_data; // Credential - ConfirmationInfo new_confirmation = confirmation; - new_confirmation.opted_in = opted_in; + ConfirmationInfo confirmation_copy = confirmation; + confirmation_copy.opted_in = opted_in; + opted_in.credential_base64url = CreateOptedInCredential(confirmation_copy); + + return opted_in; +} + +} // namespace + +absl::optional CreateOptedInCredential( + const ConfirmationInfo& confirmation) { + if (!confirmation.opted_in) { + return absl::nullopt; + } const absl::optional credential = json::writer::WriteOptedInCredential( - *unblinded_token, - json::writer::WriteConfirmationPayload(new_confirmation)); + confirmation.opted_in->unblinded_token, + json::writer::WriteConfirmationPayload(confirmation)); if (!credential) { BLOG(0, "Failed to create opted-in credential"); return absl::nullopt; @@ -93,13 +106,9 @@ absl::optional CreateOptedIn( base::Base64UrlEncode(*credential, base::Base64UrlEncodePolicy::INCLUDE_PADDING, &credential_base64url); - opted_in.credential_base64url = credential_base64url; - - return opted_in; + return credential_base64url; } -} // namespace - absl::optional CreateConfirmation( privacy::TokenGeneratorInterface* token_generator, const base::Time created_at, @@ -107,7 +116,7 @@ absl::optional CreateConfirmation( const std::string& creative_instance_id, const ConfirmationType& confirmation_type, const AdType& ad_type, - base::Value::Dict user_data) { + const OptedInUserDataInfo& opted_in_user_data) { DCHECK(token_generator); DCHECK(!created_at.is_null()); DCHECK(!transaction_id.empty()); @@ -127,7 +136,7 @@ absl::optional CreateConfirmation( } const absl::optional opted_in = - CreateOptedIn(token_generator, confirmation, std::move(user_data)); + CreateOptedIn(token_generator, confirmation, opted_in_user_data); if (!opted_in) { BLOG(0, "Failed to create opted-in"); return absl::nullopt; diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_util.h b/components/brave_ads/core/internal/account/confirmations/confirmation_util.h index 104519bd21ed..01b267047ccd 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmation_util.h +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_util.h @@ -8,7 +8,6 @@ #include -#include "base/values.h" #include "third_party/abseil-cpp/absl/types/optional.h" namespace base { @@ -24,6 +23,10 @@ class TokenGeneratorInterface; class AdType; class ConfirmationType; struct ConfirmationInfo; +struct OptedInUserDataInfo; + +absl::optional CreateOptedInCredential( + const ConfirmationInfo& confirmation); absl::optional CreateConfirmation( privacy::TokenGeneratorInterface* token_generator, @@ -32,7 +35,7 @@ absl::optional CreateConfirmation( const std::string& creative_instance_id, const ConfirmationType& confirmation_type, const AdType& ad_type, - base::Value::Dict user_data); + const OptedInUserDataInfo& opted_in_user_data); bool IsValid(const ConfirmationInfo& confirmation); diff --git a/components/brave_ads/core/internal/account/confirmations/confirmation_util_unittest.cc b/components/brave_ads/core/internal/account/confirmations/confirmation_util_unittest.cc index ea14594e7021..f94fadafe9c7 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmation_util_unittest.cc +++ b/components/brave_ads/core/internal/account/confirmations/confirmation_util_unittest.cc @@ -58,7 +58,7 @@ TEST_F(BatAdsConfirmationUtilTest, CreateConfirmationForNonOptedInUser) { const absl::optional confirmation = CreateConfirmation( token_generator_mock_.get(), /*created_at*/ Now(), kTransactionId, kCreativeInstanceId, ConfirmationType::kViewed, AdType::kNotificationAd, - base::Value::Dict()); + /*user_data*/ {}); ASSERT_TRUE(confirmation); // Assert @@ -88,7 +88,7 @@ TEST_F(BatAdsConfirmationUtilTest, CreateConfirmationForOptedInUser) { const absl::optional confirmation = CreateConfirmation( token_generator_mock_.get(), /*created_at*/ Now(), kTransactionId, kCreativeInstanceId, ConfirmationType::kViewed, AdType::kNotificationAd, - base::Value::Dict()); + /*user_data*/ {}); ASSERT_TRUE(confirmation); // Assert @@ -105,7 +105,7 @@ TEST_F(BatAdsConfirmationUtilTest, FailToCreateConfirmationForOptedInUser) { const absl::optional confirmation = CreateConfirmation( token_generator_mock_.get(), /*created_at*/ Now(), kTransactionId, kCreativeInstanceId, ConfirmationType::kViewed, AdType::kNotificationAd, - base::Value::Dict()); + /*user_data*/ {}); // Assert EXPECT_FALSE(confirmation); diff --git a/components/brave_ads/core/internal/account/confirmations/confirmations.cc b/components/brave_ads/core/internal/account/confirmations/confirmations.cc index 580838583114..3aba695d3df1 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmations.cc +++ b/components/brave_ads/core/internal/account/confirmations/confirmations.cc @@ -10,8 +10,10 @@ #include "base/functional/bind.h" #include "base/time/time.h" #include "brave/components/brave_ads/common/pref_names.h" +#include "brave/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder.h" #include "brave/components/brave_ads/core/internal/account/confirmations/confirmation_user_data_builder.h" #include "brave/components/brave_ads/core/internal/account/confirmations/confirmation_util.h" +#include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h" #include "brave/components/brave_ads/core/internal/account/transactions/transaction_info.h" #include "brave/components/brave_ads/core/internal/account/utility/redeem_unblinded_token/redeem_unblinded_token.h" #include "brave/components/brave_ads/core/internal/ads_client_helper.h" @@ -91,22 +93,13 @@ void Confirmations::Confirm(const TransactionInfo& transaction) { << transaction.id << " and creative instance id " << transaction.creative_instance_id); - const base::Time created_at = base::Time::Now(); - - const ConfirmationUserDataBuilder user_data_builder( - created_at, transaction.creative_instance_id, - transaction.confirmation_type); - user_data_builder.Build( - base::BindOnce(&Confirmations::CreateConfirmationAndRedeemToken, - base::Unretained(this), transaction, created_at)); + ConfirmTransaction(transaction); } void Confirmations::ProcessRetryQueue() { - if (retry_timer_.IsRunning()) { - return; + if (!retry_timer_.IsRunning()) { + Retry(); } - - Retry(); } /////////////////////////////////////////////////////////////////////////////// @@ -135,45 +128,91 @@ void Confirmations::OnRetry() { BLOG(1, "Retry sending failed confirmations"); - const ConfirmationInfo failed_confirmation_copy = - failed_confirmations.front(); - RemoveFromRetryQueue(failed_confirmation_copy); + const ConfirmationInfo confirmation_copy = failed_confirmations.front(); + RemoveFromRetryQueue(confirmation_copy); + + if (confirmation_copy.opted_in) { + return RecreateOptedInDynamicUserDataAndRedeem(confirmation_copy); + } - redeem_unblinded_token_->Redeem(failed_confirmation_copy); + return Redeem(confirmation_copy); } void Confirmations::StopRetrying() { retry_timer_.Stop(); } -void Confirmations::CreateConfirmationAndRedeemToken( +void Confirmations::ConfirmTransaction(const TransactionInfo& transaction) { + BuildDynamicUserDataForTransaction(transaction); +} + +void Confirmations::BuildDynamicUserDataForTransaction( + const TransactionInfo& transaction) { + const ConfirmationDynamicUserDataBuilder user_data_builder; + user_data_builder.Build( + base::BindOnce(&Confirmations::BuildFixedUserDataForTransaction, + base::Unretained(this), transaction)); +} + +void Confirmations::BuildFixedUserDataForTransaction( const TransactionInfo& transaction, - const base::Time& created_at, - base::Value::Dict user_data) { + base::Value::Dict dynamic_opted_in_user_data) { + const ConfirmationUserDataBuilder user_data_builder( + transaction.created_at, transaction.creative_instance_id, + transaction.confirmation_type); + user_data_builder.Build( + base::BindOnce(&Confirmations::CreateAndRedeem, base::Unretained(this), + transaction, std::move(dynamic_opted_in_user_data))); +} + +void Confirmations::CreateAndRedeem( + const TransactionInfo& transaction, + base::Value::Dict dynamic_opted_in_user_data, + base::Value::Dict fixed_opted_in_user_data) { + OptedInUserDataInfo opted_in_user_data; + opted_in_user_data.dynamic = std::move(dynamic_opted_in_user_data); + opted_in_user_data.fixed = std::move(fixed_opted_in_user_data); + const absl::optional confirmation = CreateConfirmation( - token_generator_, created_at, transaction.id, + token_generator_, transaction.created_at, transaction.id, transaction.creative_instance_id, transaction.confirmation_type, - transaction.ad_type, std::move(user_data)); + transaction.ad_type, opted_in_user_data); if (!confirmation) { - BLOG(0, "Failed to confirm confirmation"); + BLOG(0, "Failed to create and redeem confirmation token"); return; } - redeem_unblinded_token_->Redeem(*confirmation); + Redeem(*confirmation); +} + +void Confirmations::RecreateOptedInDynamicUserDataAndRedeem( + const ConfirmationInfo& confirmation) { + const ConfirmationDynamicUserDataBuilder user_data_builder; + user_data_builder.Build( + base::BindOnce(&Confirmations::OnRecreateOptedInDynamicUserDataAndRedeem, + base::Unretained(this), confirmation)); } -void Confirmations::CreateNewConfirmationAndAppendToRetryQueue( +void Confirmations::OnRecreateOptedInDynamicUserDataAndRedeem( const ConfirmationInfo& confirmation, - base::Value::Dict user_data) { - const absl::optional new_confirmation = CreateConfirmation( - token_generator_, confirmation.created_at, confirmation.transaction_id, - confirmation.creative_instance_id, confirmation.type, - confirmation.ad_type, std::move(user_data)); - if (!new_confirmation) { - return AppendToRetryQueue(confirmation); + base::Value::Dict dynamic_opted_in_user_data) { + ConfirmationInfo mutable_confirmation = confirmation; + + if (confirmation.opted_in) { + mutable_confirmation.opted_in->user_data.dynamic = + std::move(dynamic_opted_in_user_data); + + mutable_confirmation.opted_in->credential_base64url = + CreateOptedInCredential(mutable_confirmation); } - AppendToRetryQueue(*new_confirmation); + Redeem(mutable_confirmation); +} + +void Confirmations::Redeem(const ConfirmationInfo& confirmation) { + DCHECK(IsValid(confirmation)); + + redeem_unblinded_token_->Redeem(confirmation); } void Confirmations::OnDidSendConfirmation( @@ -237,16 +276,7 @@ void Confirmations::OnFailedToRedeemUnblindedToken( DCHECK(IsValid(confirmation)); if (should_retry) { - if (!confirmation.was_created) { - const ConfirmationUserDataBuilder user_data_builder( - confirmation.created_at, confirmation.creative_instance_id, - confirmation.type); - user_data_builder.Build(base::BindOnce( - &Confirmations::CreateNewConfirmationAndAppendToRetryQueue, - base::Unretained(this), confirmation)); - } else { - AppendToRetryQueue(confirmation); - } + AppendToRetryQueue(confirmation); } if (delegate_) { diff --git a/components/brave_ads/core/internal/account/confirmations/confirmations.h b/components/brave_ads/core/internal/account/confirmations/confirmations.h index 3d4308dfef7a..da3c887144c6 100644 --- a/components/brave_ads/core/internal/account/confirmations/confirmations.h +++ b/components/brave_ads/core/internal/account/confirmations/confirmations.h @@ -50,13 +50,22 @@ class Confirmations final : public RedeemUnblindedTokenDelegate { void OnRetry(); void StopRetrying(); - void CreateConfirmationAndRedeemToken(const TransactionInfo& transaction, - const base::Time& created_at, - base::Value::Dict user_data); - - void CreateNewConfirmationAndAppendToRetryQueue( + void ConfirmTransaction(const TransactionInfo& transaction); + void BuildDynamicUserDataForTransaction(const TransactionInfo& transaction); + void BuildFixedUserDataForTransaction( + const TransactionInfo& transaction, + base::Value::Dict dynamic_opted_in_user_data); + void CreateAndRedeem(const TransactionInfo& transaction, + base::Value::Dict dynamic_opted_in_user_data, + base::Value::Dict fixed_opted_in_user_data); + + void RecreateOptedInDynamicUserDataAndRedeem( + const ConfirmationInfo& confirmation); + void OnRecreateOptedInDynamicUserDataAndRedeem( const ConfirmationInfo& confirmation, - base::Value::Dict user_data); + base::Value::Dict dynamic_opted_in_user_data); + + void Redeem(const ConfirmationInfo& confirmation); // RedeemUnblindedTokenDelegate: void OnDidSendConfirmation(const ConfirmationInfo& confirmation) override; diff --git a/components/brave_ads/core/internal/account/confirmations/opted_in_info.cc b/components/brave_ads/core/internal/account/confirmations/opted_in_info.cc index a37809d15619..8ca52a8a0fd1 100644 --- a/components/brave_ads/core/internal/account/confirmations/opted_in_info.cc +++ b/components/brave_ads/core/internal/account/confirmations/opted_in_info.cc @@ -15,10 +15,10 @@ OptedInInfo::OptedInInfo(const OptedInInfo& other) { OptedInInfo& OptedInInfo::operator=(const OptedInInfo& other) { if (this != &other) { - unblinded_token = other.unblinded_token; token = other.token; blinded_token = other.blinded_token; - user_data = other.user_data.Clone(); + unblinded_token = other.unblinded_token; + user_data = other.user_data; credential_base64url = other.credential_base64url; } @@ -32,8 +32,9 @@ OptedInInfo& OptedInInfo::operator=(OptedInInfo&& other) noexcept = default; OptedInInfo::~OptedInInfo() = default; bool operator==(const OptedInInfo& lhs, const OptedInInfo& rhs) { - return lhs.unblinded_token == rhs.unblinded_token && lhs.token == rhs.token && - lhs.blinded_token == rhs.blinded_token && + return lhs.token == rhs.token && lhs.blinded_token == rhs.blinded_token && + lhs.unblinded_token == rhs.unblinded_token && + lhs.user_data == rhs.user_data && lhs.credential_base64url == rhs.credential_base64url; } diff --git a/components/brave_ads/core/internal/account/confirmations/opted_in_info.h b/components/brave_ads/core/internal/account/confirmations/opted_in_info.h index e4ebf474e1cb..98175c244af5 100644 --- a/components/brave_ads/core/internal/account/confirmations/opted_in_info.h +++ b/components/brave_ads/core/internal/account/confirmations/opted_in_info.h @@ -8,7 +8,7 @@ #include -#include "base/values.h" +#include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h" #include "brave/components/brave_ads/core/internal/privacy/challenge_bypass_ristretto/blinded_token.h" #include "brave/components/brave_ads/core/internal/privacy/challenge_bypass_ristretto/token.h" #include "brave/components/brave_ads/core/internal/privacy/tokens/unblinded_tokens/unblinded_token_info.h" @@ -30,7 +30,7 @@ struct OptedInInfo final { privacy::cbr::Token token; privacy::cbr::BlindedToken blinded_token; privacy::UnblindedTokenInfo unblinded_token; - base::Value::Dict user_data; + OptedInUserDataInfo user_data; absl::optional credential_base64url; }; diff --git a/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.cc b/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.cc new file mode 100644 index 000000000000..16a91dc4a9c9 --- /dev/null +++ b/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.cc @@ -0,0 +1,44 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#include "brave/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h" + +namespace brave_ads { + +OptedInUserDataInfo::OptedInUserDataInfo() = default; + +OptedInUserDataInfo::OptedInUserDataInfo(const OptedInUserDataInfo& other) { + *this = other; +} + +OptedInUserDataInfo& OptedInUserDataInfo::operator=( + const OptedInUserDataInfo& other) { + if (this != &other) { + dynamic = other.dynamic.Clone(); + fixed = other.fixed.Clone(); + } + + return *this; +} + +OptedInUserDataInfo::OptedInUserDataInfo(OptedInUserDataInfo&& other) noexcept = + default; + +OptedInUserDataInfo& OptedInUserDataInfo::operator=( + OptedInUserDataInfo&& other) noexcept = default; + +OptedInUserDataInfo::~OptedInUserDataInfo() = default; + +bool operator==(const OptedInUserDataInfo& lhs, + const OptedInUserDataInfo& rhs) { + return lhs.dynamic == rhs.dynamic && lhs.fixed == rhs.fixed; +} + +bool operator!=(const OptedInUserDataInfo& lhs, + const OptedInUserDataInfo& rhs) { + return !(lhs == rhs); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h b/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h new file mode 100644 index 000000000000..1960c7c9529d --- /dev/null +++ b/components/brave_ads/core/internal/account/confirmations/opted_in_user_data_info.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * 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 https://mozilla.org/MPL/2.0/. */ + +#ifndef BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_ACCOUNT_CONFIRMATIONS_OPTED_IN_USER_DATA_INFO_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_ACCOUNT_CONFIRMATIONS_OPTED_IN_USER_DATA_INFO_H_ + +#include "base/values.h" + +namespace brave_ads { + +struct OptedInUserDataInfo final { + OptedInUserDataInfo(); + + OptedInUserDataInfo(const OptedInUserDataInfo& other); + OptedInUserDataInfo& operator=(const OptedInUserDataInfo& other); + + OptedInUserDataInfo(OptedInUserDataInfo&& other) noexcept; + OptedInUserDataInfo& operator=(OptedInUserDataInfo&& other) noexcept; + + ~OptedInUserDataInfo(); + + base::Value::Dict dynamic; + base::Value::Dict fixed; +}; + +bool operator==(const OptedInUserDataInfo& lhs, const OptedInUserDataInfo& rhs); +bool operator!=(const OptedInUserDataInfo& lhs, const OptedInUserDataInfo& rhs); + +} // namespace brave_ads + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_ACCOUNT_CONFIRMATIONS_OPTED_IN_USER_DATA_INFO_H_ diff --git a/components/brave_ads/core/internal/deprecated/confirmations/confirmation_state_manager.cc b/components/brave_ads/core/internal/deprecated/confirmations/confirmation_state_manager.cc index 6b24e9ba7cf8..760756fbb82f 100644 --- a/components/brave_ads/core/internal/deprecated/confirmations/confirmation_state_manager.cc +++ b/components/brave_ads/core/internal/deprecated/confirmations/confirmation_state_manager.cc @@ -120,7 +120,7 @@ base::Value::Dict GetFailedConfirmationsAsDictionary( // User data confirmation_dict.Set("user_data", - confirmation.opted_in->user_data.Clone()); + confirmation.opted_in->user_data.fixed.Clone()); // Credential if (!confirmation.opted_in->credential_base64url) { @@ -296,9 +296,9 @@ absl::optional ConfirmationStateManager::GetOptedIn( } } - // User data + // User data (opted_in.user_data.dynamic is recreated when redeeming a token) if (const base::Value::Dict* const value = dict.FindDict("user_data")) { - opted_in.user_data = value->Clone(); + opted_in.user_data.fixed = value->Clone(); } else { return absl::nullopt; } diff --git a/components/brave_ads/core/test/BUILD.gn b/components/brave_ads/core/test/BUILD.gn index ce1705733d52..2ea0e37776b2 100644 --- a/components/brave_ads/core/test/BUILD.gn +++ b/components/brave_ads/core/test/BUILD.gn @@ -13,6 +13,7 @@ source_set("brave_ads_unit_tests") { sources = [ "//brave/components/brave_ads/core/internal/account/account_unittest.cc", "//brave/components/brave_ads/core/internal/account/account_util_unittest.cc", + "//brave/components/brave_ads/core/internal/account/confirmations/confirmation_dynamic_user_data_builder_unittest.cc", "//brave/components/brave_ads/core/internal/account/confirmations/confirmation_payload_json_writer_unittest.cc", "//brave/components/brave_ads/core/internal/account/confirmations/confirmation_unittest_util.cc", "//brave/components/brave_ads/core/internal/account/confirmations/confirmation_unittest_util.h",