blob: 0f1672e36d00f21a4f298f26fc51cea33619f681 [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/attribution_reporting/attribution_aggregation_keys.h"
#include <string>
#include <utility>
#include "base/check.h"
#include "base/ranges/algorithm.h"
#include "base/strings/abseil_string_number_conversions.h"
#include "base/values.h"
#include "content/browser/attribution_reporting/attribution_reporting.pb.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/attribution_reporting/constants.h"
namespace content {
// static
absl::optional<AttributionAggregationKeys> AttributionAggregationKeys::FromKeys(
Keys keys) {
bool is_valid =
keys.size() <= blink::kMaxAttributionAggregationKeysPerSourceOrTrigger &&
base::ranges::all_of(keys, [](const auto& key) {
return key.first.size() <=
blink::kMaxBytesPerAttributionAggregationKeyId;
});
return is_valid
? absl::make_optional(AttributionAggregationKeys(std::move(keys)))
: absl::nullopt;
}
// static
absl::optional<AttributionAggregationKeys> AttributionAggregationKeys::FromJSON(
const base::Value* value) {
// TODO(johnidel): Consider logging registration JSON metrics here.
if (!value)
return AttributionAggregationKeys();
const base::Value::Dict* dict = value->GetIfDict();
if (!dict)
return absl::nullopt;
const size_t num_keys = dict->size();
if (num_keys > blink::kMaxAttributionAggregationKeysPerSourceOrTrigger)
return absl::nullopt;
Keys::container_type keys;
keys.reserve(num_keys);
for (auto [key_id, value] : *dict) {
if (key_id.size() > blink::kMaxBytesPerAttributionAggregationKeyId)
return absl::nullopt;
const std::string* s = value.GetIfString();
if (!s)
return absl::nullopt;
absl::uint128 key;
if (!base::HexStringToUInt128(*s, &key))
return absl::nullopt;
keys.emplace_back(key_id, key);
}
return AttributionAggregationKeys(Keys(base::sorted_unique, std::move(keys)));
}
// static
absl::optional<AttributionAggregationKeys>
AttributionAggregationKeys::Deserialize(const std::string& str) {
proto::AttributionAggregatableSource msg;
if (!msg.ParseFromString(str))
return absl::nullopt;
Keys::container_type keys;
keys.reserve(msg.keys().size());
for (const auto& [id, key] : msg.keys()) {
if (!key.has_high_bits() || !key.has_low_bits())
return absl::nullopt;
keys.emplace_back(id, absl::MakeUint128(key.high_bits(), key.low_bits()));
}
return FromKeys(std::move(keys));
}
AttributionAggregationKeys::AttributionAggregationKeys(Keys keys)
: keys_(std::move(keys)) {}
AttributionAggregationKeys::AttributionAggregationKeys() = default;
AttributionAggregationKeys::~AttributionAggregationKeys() = default;
AttributionAggregationKeys::AttributionAggregationKeys(
const AttributionAggregationKeys&) = default;
AttributionAggregationKeys::AttributionAggregationKeys(
AttributionAggregationKeys&&) = default;
AttributionAggregationKeys& AttributionAggregationKeys::operator=(
const AttributionAggregationKeys&) = default;
AttributionAggregationKeys& AttributionAggregationKeys::operator=(
AttributionAggregationKeys&&) = default;
std::string AttributionAggregationKeys::Serialize() const {
proto::AttributionAggregatableSource msg;
for (const auto& [id, key] : keys_) {
proto::AttributionAggregationKey key_msg;
key_msg.set_high_bits(absl::Uint128High64(key));
key_msg.set_low_bits(absl::Uint128Low64(key));
(*msg.mutable_keys())[id] = std::move(key_msg);
}
std::string str;
bool success = msg.SerializeToString(&str);
DCHECK(success);
return str;
}
} // namespace content