Skip to content

Commit

Permalink
[ads] Followup to "Send HTTP response status for landed events as par…
Browse files Browse the repository at this point in the history
…t of the confirmation token redemption" #36752
  • Loading branch information
tmancey committed Sep 11, 2024
1 parent 9218d9d commit eaf85f0
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 15 deletions.
2 changes: 2 additions & 0 deletions components/brave_ads/core/internal/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ static_library("internal") {
"common/logging_util_internal.cc",
"common/logging_util_internal.h",
"common/net/http/http_status_code.h",
"common/net/http/http_status_code_util.cc",
"common/net/http/http_status_code_util.h",
"common/platform/platform_helper.cc",
"common/platform/platform_helper.h",
"common/platform/platform_helper_types.h",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Included when redeeming an anonymous confirmation token:
| transactionId | {"transactionId":"c14d370c-1178-4c73-8385-1cfa17200646"} | A unique id for the transaction, which is not linkable between confirmation token redemptions. |
| type | {"type":"view"} | Action or interaction that occurred within an advertisement, such as a user clicking the ad.<br><br>Supported types:<br><br>- view<br>- click<br>- landed<br>- conversion<br>- media_play[^1]<br>- media_25[^1]<br>- media_100[^1]<br>- upvote<br>- downvote<br>- flag<br>- bookmark &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
| confirmation token | {"blindedPaymentTokens": ["Ev5JE4/9TZI/5TqyN9JWfJ1To0HBwQw2rWeAPcdjX3Q="],<br> "publicKey": "RJ2i/o/pZkrH+i0aGEMY1G9FXtd7Q7gfRi3YdNRnDDk="} | See [security and privacy model for ad confirmations](https://github.com/brave/brave-browser/wiki/Security-and-privacy-model-for-ad-confirmations). |
| user data | {"buildChannel":"nightly",<br>"catalog":[{"id":"29e5c8bc0ba319069980bb390d8e8f9b58c05a20"}],<br>"conversion":[{"action":"view"}],<br>"createdAtTimestamp":"2020-11-18T12:00:00.000Z",<br>"httpResponseStatus":"errorPage",<br>"platform":"windows",<br>"rotatingHash":"I6KM54gXOrWqRHyrD518LmhePLHpIk4KSgCKOl0e3sc=",<br>"segment":"sports",<br>"studies":[{"group":"GroupA","name":"BraveAds.FooStudy"},{"group":"GroupB","name":"BraveAds.BarStudy"}],<br>"versionNumber":"1.2.3.4"} | See [user data](../../user_data/README.md#brave-rewards-users). |
| user data | {"buildChannel":"nightly",<br>"catalog":[{"id":"29e5c8bc0ba319069980bb390d8e8f9b58c05a20"}],<br>"conversion":[{"action":"view"}],<br>"createdAtTimestamp":"2020-11-18T12:00:00.000Z",<br>"httpResponseStatus":"5xx",<br>"platform":"windows",<br>"rotatingHash":"I6KM54gXOrWqRHyrD518LmhePLHpIk4KSgCKOl0e3sc=",<br>"segment":"sports",<br>"studies":[{"group":"GroupA","name":"BraveAds.FooStudy"},{"group":"GroupB","name":"BraveAds.BarStudy"}],<br>"versionNumber":"1.2.3.4"} | See [user data](../../user_data/README.md#brave-rewards-users). |

Please add to it!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Included as part of the "confirmation token" payload. See [Brave Rewards user co
| conversion.envelope[^2] | {"conversion":[{"envelope":<br>{"alg":"crypto_box_curve25519xsalsa20poly1305",<br>"ciphertext":"3f8a8aeb5e1e4b1a8e7b4e3f8a8aeb5e1e4b1a8e7b4e3f8a8aeb5e1e4b1a8e7b",<br>"epk":"d1f2e3d4c5b6a79887a6b5c4d3e2f1d1f2e3d4c5b6a79887a6",<br>"nonce":"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"}}]} | Allow advertisers to affirm that conversions are legitimate by wrapping an identifier with an additional layer of encryption to protect its integrity. Also, see https://ads-help.brave.com/campaign-performance/reporting#verifiable-ad-conversions-vac. |
| createdAtTimestamp | {"createdAtTimestamp":"2020-11-18T12:00:00.000Z"} | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) timestamp with fixed values for minutes, seconds, milliseconds and timezone. |
| diagnosticId[^1][^2] | {"diagnosticId":"c1298fde-7fdb-401f-a3ce-0b58fe86e6e2"} | Diagnostic id from [brave://rewards-internals](brave://rewards-internals) to assist in troubleshooting issues. This is only included if it has been set manually by the user, for example, at the request of Brave Support in order to troubleshoot a problem. |
| httpResponseStatus[^2] | {"httpResponseStatus":"errorPage"} | Indicates whether landing on a page resulted in an error page. This is only included if an error occurred. |
| httpResponseStatus[^2] | {"httpResponseStatus":"404"} | Indicates the landing page HTTP status code, where privacy-preserving status codes are fixed to include only the status code class. |
| platform | {"platform":"windows"} | Operating system. |
| rotatingHash[^2] | {"rotatingHash":"j9D7eKSoPLYNfxkG2Mx+SbgKJ9hcKg1QwDB8B5qxlpk="} | Hashed device identifier that is unique to each ad and rotated several times a day. This is used for rate-limiting purposes. |
| segment[^2] | {"segment":"sports"} | Advertising taxonomy for the chosen ad. Also see, https://ads-help.brave.com/campaign-performance/targeting. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "brave/components/brave_ads/core/internal/account/user_data/fixed/page_land_user_data.h"

#include "brave/components/brave_ads/core/internal/common/net/http/http_status_code_util.h"
#include "brave/components/brave_ads/core/internal/settings/settings.h"
#include "brave/components/brave_ads/core/internal/tabs/tab_info.h"

Expand All @@ -13,7 +14,6 @@ namespace brave_ads {
namespace {

constexpr char kHttpResponseStatusKey[] = "httpResponseStatus";
constexpr char kHttpErrorPageResponseStatus[] = "errorPage";

} // namespace

Expand All @@ -24,9 +24,8 @@ base::Value::Dict BuildPageLandUserData(const TabInfo& tab) {

base::Value::Dict user_data;

if (tab.is_error_page) {
user_data.Set(kHttpResponseStatusKey, kHttpErrorPageResponseStatus);
}
user_data.Set(kHttpResponseStatusKey,
ToPrivacyPreservingHttpStatusCode(tab.http_status_code));

return user_data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,27 @@ TEST_F(BraveAdsPageLandUserDataTest,
EXPECT_EQ(base::test::ParseJsonDict(
R"(
{
"httpResponseStatus": "errorPage"
"httpResponseStatus": "404"
})"),
user_data);
}

TEST_F(BraveAdsPageLandUserDataTest,
DoNotBuildPageLandUserDataForHttpResponseStatusNonErrorPage) {
BuildPageLandUserDataForPrivacyPreservingHttpResponseStatusErrorPage) {
// Act
const base::Value::Dict user_data = BuildPageLandUserData(
TabInfo{/*id=*/1,
/*is_visible=*/true,
/*redirect_chain=*/{GURL("https://brave.com")}, net::HTTP_OK,
/*is_playing_media=*/
false});
const base::Value::Dict user_data = BuildPageLandUserData(TabInfo{
/*id=*/1,
/*is_visible=*/true,
/*redirect_chain=*/{GURL("https://brave.com")}, net::HTTP_LOOP_DETECTED,
/*is_playing_media=*/false});

// Assert
EXPECT_THAT(user_data, ::testing::IsEmpty());
EXPECT_EQ(base::test::ParseJsonDict(
R"(
{
"httpResponseStatus": "5xx"
})"),
user_data);
}

TEST_F(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* Copyright (c) 2024 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/common/net/http/http_status_code_util.h"

#include "base/containers/fixed_flat_set.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"

namespace brave_ads {

namespace {

constexpr auto kAllowedHttpStatusCodes = base::MakeFixedFlatSet<int>({
400, // Bad Request.
401, // Unauthorized.
403, // Forbidden.
404, // Not Found.
408, // Request Timeout.
429, // Too Many Requests.
451, // Unavailable For Legal Reasons.
500, // Internal Server Error.
502, // Bad Gateway.
503, // Service Unavailable.
504 // Gateway Timeout.
});

std::string ToPrivacyPreservingHttpStatusCodeClass(
const int http_status_code_class) {
return base::StringPrintf("%dxx", http_status_code_class);
}

} // namespace

std::string ToPrivacyPreservingHttpStatusCode(const int http_status_code) {
const int http_status_code_class = http_status_code / 100;

// Check if the HTTP status code is in the allowed list of privacy-preserving
// codes.
if (const auto iter = kAllowedHttpStatusCodes.find(http_status_code);
iter != kAllowedHttpStatusCodes.cend()) {
// If the HTTP status code is allowed, return it as a string.
return base::NumberToString(http_status_code);
}

// If the HTTP status code is not allowed, return a privacy-preserving status
// code based on the class of the original status code.
return ToPrivacyPreservingHttpStatusCodeClass(http_status_code_class);
}

} // namespace brave_ads
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* Copyright (c) 2024 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_COMMON_NET_HTTP_HTTP_STATUS_CODE_UTIL_H_
#define BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_COMMON_NET_HTTP_HTTP_STATUS_CODE_UTIL_H_

#include <string>

namespace brave_ads {

std::string ToPrivacyPreservingHttpStatusCode(int http_status_code);

} // namespace brave_ads

#endif // BRAVE_COMPONENTS_BRAVE_ADS_CORE_INTERNAL_COMMON_NET_HTTP_HTTP_STATUS_CODE_UTIL_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* Copyright (c) 2024 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/common/net/http/http_status_code_util.h"

#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"

// npm run test -- brave_unit_tests --filter=BraveAds*

namespace brave_ads {

TEST(BraveAdsHttpStatusCodeUtilTest, ToPrivacyPreservingHttpStatusCode) {
// Act & Assert
for (int i = 100; i <= 599; ++i) {
const std::string privacy_preserving_http_status_code =
ToPrivacyPreservingHttpStatusCode(i);
if (i == 400 || // Bad Request.
i == 401 || // Unauthorized.
i == 403 || // Forbidden.
i == 404 || // Not Found.
i == 408 || // Request Timeout.
i == 429 || // Too Many Requests.
i == 451 || // Unavailable For Legal Reasons.
i == 500 || // Internal Server Error.
i == 502 || // Bad Gateway.
i == 503 || // Service Unavailable.
i == 504) { // Gateway Timeout.
EXPECT_EQ(base::NumberToString(i), privacy_preserving_http_status_code);
} else {
EXPECT_EQ(base::StringPrintf("%dxx", /*http_status_code_class*/ i / 100),
privacy_preserving_http_status_code);
}
}
}

} // namespace brave_ads
1 change: 1 addition & 0 deletions components/brave_ads/core/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ source_set("brave_ads_unit_tests") {
"//brave/components/brave_ads/core/internal/common/country_code/country_code_unittest.cc",
"//brave/components/brave_ads/core/internal/common/crypto/crypto_util_unittest.cc",
"//brave/components/brave_ads/core/internal/common/locale/locale_util_unittest.cc",
"//brave/components/brave_ads/core/internal/common/net/http/http_status_code_util_unittest.cc",
"//brave/components/brave_ads/core/internal/common/platform/platform_helper_mock.cc",
"//brave/components/brave_ads/core/internal/common/platform/platform_helper_mock.h",
"//brave/components/brave_ads/core/internal/common/resources/country_components_test_constants.h",
Expand Down

0 comments on commit eaf85f0

Please sign in to comment.