From fcd07f9e38b140580e1c05c98a9dd371332a1361 Mon Sep 17 00:00:00 2001 From: aseren <86598290+aseren@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:52:25 -0500 Subject: [PATCH] Validate conversions when loading from database (uplift to 1.59.x) (#20312) --- components/brave_ads/core/internal/BUILD.gn | 2 + .../queue/conversion_queue_database_table.cc | 13 ++++ .../conversion_queue_item_validation_util.cc | 76 +++++++++++++++++++ .../conversion_queue_item_validation_util.h | 20 +++++ ...ion_queue_item_validation_util_unittest.cc | 63 +++++++++++++++ components/brave_ads/core/test/BUILD.gn | 1 + 6 files changed, 175 insertions(+) create mode 100644 components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.cc create mode 100644 components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.h create mode 100644 components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util_unittest.cc diff --git a/components/brave_ads/core/internal/BUILD.gn b/components/brave_ads/core/internal/BUILD.gn index 9fdd6ba3000e..95dff37f279d 100644 --- a/components/brave_ads/core/internal/BUILD.gn +++ b/components/brave_ads/core/internal/BUILD.gn @@ -499,6 +499,8 @@ static_library("internal") { "conversions/queue/queue_item/conversion_queue_item_util.cc", "conversions/queue/queue_item/conversion_queue_item_util.h", "conversions/queue/queue_item/conversion_queue_item_util_constants.h", + "conversions/queue/queue_item/conversion_queue_item_validation_util.cc", + "conversions/queue/queue_item/conversion_queue_item_validation_util.h", "conversions/resource/conversion_resource.cc", "conversions/resource/conversion_resource.h", "conversions/resource/conversion_resource_constants.h", diff --git a/components/brave_ads/core/internal/conversions/queue/conversion_queue_database_table.cc b/components/brave_ads/core/internal/conversions/queue/conversion_queue_database_table.cc index ea4f4becf1c6..fc8db0e232b6 100644 --- a/components/brave_ads/core/internal/conversions/queue/conversion_queue_database_table.cc +++ b/components/brave_ads/core/internal/conversions/queue/conversion_queue_database_table.cc @@ -8,6 +8,8 @@ #include #include +#include "base/debug/crash_logging.h" +#include "base/debug/dump_without_crashing.h" #include "base/functional/bind.h" #include "base/strings/string_util.h" #include "brave/components/brave_ads/core/internal/client/ads_client_helper.h" @@ -20,6 +22,7 @@ #include "brave/components/brave_ads/core/internal/conversions/actions/conversion_action_types.h" #include "brave/components/brave_ads/core/internal/conversions/actions/conversion_action_types_constants.h" #include "brave/components/brave_ads/core/internal/conversions/actions/conversion_action_types_util.h" +#include "brave/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.h" #include "brave/components/brave_ads/core/internal/conversions/types/verifiable_conversion/verifiable_conversion_info.h" #include "brave/components/brave_ads/core/mojom/brave_ads.mojom.h" @@ -139,6 +142,16 @@ void GetCallback(GetConversionQueueCallback callback, for (const auto& record : command_response->result->get_records()) { const ConversionQueueItemInfo conversion_queue_item = GetFromRecord(&*record); + // TODO(https://github.com/brave/brave-browser/issues/33239): Validate all + // Brave Ads data when loading from database + if (!conversion_queue_item.IsValid()) { + SCOPED_CRASH_KEY_STRING256( + "BraveAdsConversion", "invalidFieldsNames", + GetConversionQueueItemInvalidFieldsNames(conversion_queue_item)); + base::debug::DumpWithoutCrashing(); + continue; + } + conversion_queue_items.push_back(conversion_queue_item); } diff --git a/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.cc b/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.cc new file mode 100644 index 000000000000..18ad2addd75d --- /dev/null +++ b/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.cc @@ -0,0 +1,76 @@ +/* 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/conversions/queue/queue_item/conversion_queue_item_validation_util.h" + +#include + +#include "base/strings/string_util.h" +#include "brave/components/brave_ads/core/internal/conversions/conversion/conversion_info.h" +#include "brave/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_info.h" + +namespace brave_ads { + +namespace { + +constexpr char kAdTypeFieldName[] = "ad_type"; +constexpr char kCreativeInstanceIdFieldName[] = "creative_instance_id"; +constexpr char kCreativeSetIdFieldName[] = "creative_set_id"; +constexpr char kCampaignIdFieldName[] = "campaign_id"; +constexpr char kAdvertiserIdFieldName[] = "advertiser_id"; +constexpr char kActionTypeFieldName[] = "action_type"; +constexpr char kProcessAtFieldName[] = "process_at"; +constexpr char kSeparator[] = ","; + +std::vector GetInvalidFieldsNamesList( + const ConversionInfo& conversion_item) { + std::vector invalid_fields; + + if (conversion_item.ad_type == AdType::kUndefined) { + invalid_fields.emplace_back(kAdTypeFieldName); + } + + if (conversion_item.creative_instance_id.empty()) { + invalid_fields.emplace_back(kCreativeInstanceIdFieldName); + } + + if (conversion_item.creative_set_id.empty()) { + invalid_fields.emplace_back(kCreativeSetIdFieldName); + } + + if (conversion_item.campaign_id.empty()) { + invalid_fields.emplace_back(kCampaignIdFieldName); + } + + if (conversion_item.advertiser_id.empty()) { + invalid_fields.emplace_back(kAdvertiserIdFieldName); + } + + if (conversion_item.action_type == ConversionActionType::kUndefined) { + invalid_fields.emplace_back(kActionTypeFieldName); + } + + return invalid_fields; +} + +std::vector GetInvalidFieldsNamesList( + const ConversionQueueItemInfo& conversion_queue_item) { + std::vector invalid_fields = + GetInvalidFieldsNamesList(conversion_queue_item.conversion); + if (conversion_queue_item.process_at.is_null()) { + invalid_fields.emplace_back(kProcessAtFieldName); + } + return invalid_fields; +} + +} // namespace + +std::string GetConversionQueueItemInvalidFieldsNames( + const ConversionQueueItemInfo& conversion_queue_item) { + return base::JoinString(GetInvalidFieldsNamesList(conversion_queue_item), + kSeparator); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.h b/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.h new file mode 100644 index 000000000000..acee50232796 --- /dev/null +++ b/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util.h @@ -0,0 +1,20 @@ +/* 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_CONVERSIONS_QUEUE_QUEUE_ITEM_CONVERSION_QUEUE_ITEM_VALIDATION_UTIL_H_ +#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CONVERSIONS_QUEUE_QUEUE_ITEM_CONVERSION_QUEUE_ITEM_VALIDATION_UTIL_H_ + +#include + +namespace brave_ads { + +struct ConversionQueueItemInfo; + +std::string GetConversionQueueItemInvalidFieldsNames( + const ConversionQueueItemInfo& conversion_queue_item); + +} // namespace brave_ads + +#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_CONVERSIONS_QUEUE_QUEUE_ITEM_CONVERSION_QUEUE_ITEM_VALIDATION_UTIL_H_ diff --git a/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util_unittest.cc b/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util_unittest.cc new file mode 100644 index 000000000000..234f898b54a2 --- /dev/null +++ b/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util_unittest.cc @@ -0,0 +1,63 @@ +/* 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/conversions/queue/queue_item/conversion_queue_item_validation_util.h" + +#include "brave/components/brave_ads/core/internal/ads/ad_unittest_util.h" +#include "brave/components/brave_ads/core/internal/common/unittest/unittest_time_util.h" +#include "brave/components/brave_ads/core/internal/conversions/conversion/conversion_builder.h" +#include "brave/components/brave_ads/core/internal/conversions/conversion/conversion_info.h" +#include "brave/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_unittest_util.h" +#include "brave/components/brave_ads/core/internal/conversions/types/verifiable_conversion/verifiable_conversion_unittest_constants.h" +#include "brave/components/brave_ads/core/internal/user_interaction/ad_events/ad_event_builder.h" +#include "brave/components/brave_ads/core/internal/user_interaction/ad_events/ad_event_info.h" +#include "brave/components/brave_ads/core/public/ad_info.h" +#include "brave/components/brave_ads/core/public/ad_type.h" +#include "testing/gtest/include/gtest/gtest.h" + +// npm run test -- brave_unit_tests --filter=BraveAds* + +namespace brave_ads { + +TEST(BraveAdsValidationUtilTest, InvalidConversionQueueItem) { + // Arrange + const AdInfo ad = BuildAdForTesting(AdType::kNotificationAd, + /*should_use_random_uuids*/ true); + ConversionInfo conversion = BuildConversion( + BuildAdEvent(ad, ConfirmationType::kViewed, /*created_at*/ Now()), + VerifiableConversionInfo{kVerifiableConversionId, + kVerifiableConversionAdvertiserPublicKey}); + conversion.ad_type = AdType::kUndefined; + + ConversionQueueItemList conversion_queue_items = + BuildConversionQueueItemsForTesting(conversion, /*count*/ 1); + conversion_queue_items[0].process_at = base::Time(); + + // Act + + // Assert + EXPECT_EQ("ad_type,process_at", GetConversionQueueItemInvalidFieldsNames( + conversion_queue_items[0])); +} + +TEST(BraveAdsValidationUtilTest, ValidConversionQueueItem) { + // Arrange + const AdInfo ad = BuildAdForTesting(AdType::kNotificationAd, + /*should_use_random_uuids*/ true); + const ConversionInfo conversion = BuildConversion( + BuildAdEvent(ad, ConfirmationType::kViewed, /*created_at*/ Now()), + VerifiableConversionInfo{kVerifiableConversionId, + kVerifiableConversionAdvertiserPublicKey}); + const ConversionQueueItemList conversion_queue_items = + BuildConversionQueueItemsForTesting(conversion, /*count*/ 1); + + // Act + + // Assert + EXPECT_EQ( + "", GetConversionQueueItemInvalidFieldsNames(conversion_queue_items[0])); +} + +} // namespace brave_ads diff --git a/components/brave_ads/core/test/BUILD.gn b/components/brave_ads/core/test/BUILD.gn index aab2d8d759e2..75f9fbe958b7 100644 --- a/components/brave_ads/core/test/BUILD.gn +++ b/components/brave_ads/core/test/BUILD.gn @@ -289,6 +289,7 @@ source_set("brave_ads_unit_tests") { "//brave/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_unittest_util.cc", "//brave/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_unittest_util.h", "//brave/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_util_unittest.cc", + "//brave/components/brave_ads/core/internal/conversions/queue/queue_item/conversion_queue_item_validation_util_unittest.cc", "//brave/components/brave_ads/core/internal/conversions/resource/conversion_resource_unittest.cc", "//brave/components/brave_ads/core/internal/conversions/types/default_conversion/creative_set_conversion_url_pattern/creative_set_conversion_url_pattern_util_unittest.cc", "//brave/components/brave_ads/core/internal/conversions/types/verifiable_conversion/envelope/verifiable_conversion_envelope_unittest_util.cc",