1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/attribution_reporting/aggregation_keys.h"
#include <algorithm>
#include <optional>
#include <string>
#include <utility>
#include "base/check.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_functions.h"
#include "base/types/expected.h"
#include "base/types/expected_macros.h"
#include "base/values.h"
#include "components/attribution_reporting/constants.h"
#include "components/attribution_reporting/parsing_utils.h"
#include "components/attribution_reporting/source_registration_error.mojom.h"
#include "third_party/abseil-cpp/absl/numeric/int128.h"
namespace attribution_reporting {
namespace {
using ::attribution_reporting::mojom::SourceRegistrationError;
bool AggregationKeyIdHasValidLength(const std::string& key) {
return key.size() <= AggregationKeys::kMaxBytesPerAggregationKeyId;
}
bool IsValid(const AggregationKeys::Keys& keys) {
return keys.size() <= kMaxAggregationKeysPerSource &&
std::ranges::all_of(keys, [](const auto& key) {
return AggregationKeyIdHasValidLength(key.first);
});
}
void RecordAggregatableKeysPerSource(base::HistogramBase::Sample32 count) {
const int kExclusiveMaxHistogramValue = 101;
static_assert(
kMaxAggregationKeysPerSource < kExclusiveMaxHistogramValue,
"Bump the version for histogram Conversions.AggregatableKeysPerSource");
base::UmaHistogramCounts100("Conversions.AggregatableKeysPerSource", count);
}
} // namespace
// static
std::optional<AggregationKeys> AggregationKeys::FromKeys(Keys keys) {
if (!IsValid(keys)) {
return std::nullopt;
}
return AggregationKeys(std::move(keys));
}
// static
base::expected<AggregationKeys, SourceRegistrationError>
AggregationKeys::FromJSON(const base::Value* value) {
if (!value) {
return AggregationKeys();
}
const base::Value::Dict* dict = value->GetIfDict();
if (!dict) {
return base::unexpected(
SourceRegistrationError::kAggregationKeysDictInvalid);
}
const size_t num_keys = dict->size();
if (num_keys > kMaxAggregationKeysPerSource) {
return base::unexpected(
SourceRegistrationError::kAggregationKeysDictInvalid);
}
RecordAggregatableKeysPerSource(num_keys);
Keys::container_type keys;
keys.reserve(num_keys);
for (auto [key_id, maybe_string_value] : *dict) {
if (!AggregationKeyIdHasValidLength(key_id)) {
return base::unexpected(
SourceRegistrationError::kAggregationKeysKeyTooLong);
}
ASSIGN_OR_RETURN(
absl::uint128 key, ParseAggregationKeyPiece(maybe_string_value),
[](ParseError) {
return SourceRegistrationError::kAggregationKeysValueInvalid;
});
keys.emplace_back(key_id, key);
}
return AggregationKeys(Keys(base::sorted_unique, std::move(keys)));
}
AggregationKeys::AggregationKeys(Keys keys) : keys_(std::move(keys)) {
CHECK(IsValid(keys_));
}
AggregationKeys::AggregationKeys() = default;
AggregationKeys::~AggregationKeys() = default;
AggregationKeys::AggregationKeys(const AggregationKeys&) = default;
AggregationKeys::AggregationKeys(AggregationKeys&&) = default;
AggregationKeys& AggregationKeys::operator=(const AggregationKeys&) = default;
AggregationKeys& AggregationKeys::operator=(AggregationKeys&&) = default;
base::Value::Dict AggregationKeys::ToJson() const {
base::Value::Dict dict;
for (const auto& [key, value] : keys_) {
dict.Set(key, HexEncodeAggregationKey(value));
}
return dict;
}
} // namespace attribution_reporting
|