blob: 1e48e9f08cc61817f53fee89fbc889931736a694 [file] [log] [blame]
// 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/trigger_registration.h"
#include <utility>
#include <vector>
#include "base/functional/function_ref.h"
#include "base/json/json_reader.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_piece.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "components/aggregation_service/aggregation_service.mojom.h"
#include "components/aggregation_service/parsing_utils.h"
#include "components/attribution_reporting/aggregatable_dedup_key.h"
#include "components/attribution_reporting/aggregatable_trigger_data.h"
#include "components/attribution_reporting/aggregatable_values.h"
#include "components/attribution_reporting/event_trigger_data.h"
#include "components/attribution_reporting/filters.h"
#include "components/attribution_reporting/parsing_utils.h"
#include "components/attribution_reporting/trigger_registration_error.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace attribution_reporting {
namespace {
using ::aggregation_service::mojom::AggregationCoordinator;
using ::attribution_reporting::mojom::TriggerRegistrationError;
constexpr char kAggregationCoordinatorIdentifier[] =
"aggregation_coordinator_identifier";
constexpr char kAggregatableDeduplicationKeys[] =
"aggregatable_deduplication_keys";
constexpr char kAggregatableTriggerData[] = "aggregatable_trigger_data";
constexpr char kAggregatableValues[] = "aggregatable_values";
constexpr char kEventTriggerData[] = "event_trigger_data";
base::expected<AggregationCoordinator, TriggerRegistrationError>
ParseAggregationCoordinator(const base::Value* value) {
// The default value is used for backward compatibility prior to this
// attribute being added, but ideally this would invalidate the registration
// if other aggregatable fields were present.
if (!value)
return AggregationCoordinator::kDefault;
const std::string* str = value->GetIfString();
if (!str) {
return base::unexpected(
TriggerRegistrationError::kAggregationCoordinatorWrongType);
}
absl::optional<AggregationCoordinator> aggregation_coordinator =
aggregation_service::ParseAggregationCoordinator(*str);
if (!aggregation_coordinator.has_value()) {
return base::unexpected(
TriggerRegistrationError::kAggregationCoordinatorUnknownValue);
}
return *aggregation_coordinator;
}
template <typename T>
void SerializeListIfNotEmpty(base::Value::Dict& dict,
base::StringPiece key,
const std::vector<T>& vec) {
if (vec.empty()) {
return;
}
base::Value::List list;
for (const auto& value : vec) {
list.Append(value.ToJson());
}
dict.Set(key, std::move(list));
}
template <typename T>
base::expected<std::vector<T>, TriggerRegistrationError> ParseList(
base::Value* input_value,
TriggerRegistrationError wrong_type,
base::FunctionRef<base::expected<T, TriggerRegistrationError>(base::Value&)>
build_element) {
if (!input_value) {
return {};
}
base::Value::List* list = input_value->GetIfList();
if (!list) {
return base::unexpected(wrong_type);
}
std::vector<T> vec;
vec.reserve(list->size());
for (auto& value : *list) {
base::expected<T, TriggerRegistrationError> element = build_element(value);
if (!element.has_value()) {
return base::unexpected(element.error());
}
vec.push_back(std::move(*element));
}
return vec;
}
} // namespace
// static
base::expected<TriggerRegistration, TriggerRegistrationError>
TriggerRegistration::Parse(base::Value::Dict registration) {
auto filters = FilterPair::FromJSON(registration);
if (!filters.has_value())
return base::unexpected(filters.error());
auto aggregatable_dedup_keys = ParseList<AggregatableDedupKey>(
registration.Find(kAggregatableDeduplicationKeys),
TriggerRegistrationError::kAggregatableDedupKeyListWrongType,
&AggregatableDedupKey::FromJSON);
if (!aggregatable_dedup_keys.has_value()) {
return base::unexpected(aggregatable_dedup_keys.error());
}
auto event_triggers = ParseList<EventTriggerData>(
registration.Find(kEventTriggerData),
TriggerRegistrationError::kEventTriggerDataListWrongType,
&EventTriggerData::FromJSON);
if (!event_triggers.has_value())
return base::unexpected(event_triggers.error());
auto aggregatable_trigger_data = ParseList<AggregatableTriggerData>(
registration.Find(kAggregatableTriggerData),
TriggerRegistrationError::kAggregatableTriggerDataListWrongType,
&AggregatableTriggerData::FromJSON);
if (!aggregatable_trigger_data.has_value())
return base::unexpected(aggregatable_trigger_data.error());
auto aggregatable_values =
AggregatableValues::FromJSON(registration.Find(kAggregatableValues));
if (!aggregatable_values.has_value())
return base::unexpected(aggregatable_values.error());
auto aggregation_coordinator = ParseAggregationCoordinator(
registration.Find(kAggregationCoordinatorIdentifier));
if (!aggregation_coordinator.has_value())
return base::unexpected(aggregation_coordinator.error());
absl::optional<uint64_t> debug_key = ParseDebugKey(registration);
bool debug_reporting = ParseDebugReporting(registration);
return TriggerRegistration(
std::move(*filters), debug_key, std::move(*aggregatable_dedup_keys),
std::move(*event_triggers), std::move(*aggregatable_trigger_data),
std::move(*aggregatable_values), debug_reporting,
*aggregation_coordinator);
}
// static
base::expected<TriggerRegistration, TriggerRegistrationError>
TriggerRegistration::Parse(base::StringPiece json) {
base::expected<TriggerRegistration, TriggerRegistrationError> trigger =
base::unexpected(TriggerRegistrationError::kInvalidJson);
absl::optional<base::Value> value =
base::JSONReader::Read(json, base::JSON_PARSE_RFC);
if (value) {
if (value->is_dict()) {
trigger = Parse(std::move(*value).TakeDict());
} else {
trigger = base::unexpected(TriggerRegistrationError::kRootWrongType);
}
}
if (!trigger.has_value()) {
base::UmaHistogramEnumeration("Conversions.TriggerRegistrationError4",
trigger.error());
}
return trigger;
}
TriggerRegistration::TriggerRegistration() = default;
TriggerRegistration::TriggerRegistration(
FilterPair filters,
absl::optional<uint64_t> debug_key,
std::vector<AggregatableDedupKey> aggregatable_dedup_keys,
std::vector<EventTriggerData> event_triggers,
std::vector<AggregatableTriggerData> aggregatable_trigger_data,
AggregatableValues aggregatable_values,
bool debug_reporting,
aggregation_service::mojom::AggregationCoordinator aggregation_coordinator)
: filters(std::move(filters)),
debug_key(debug_key),
aggregatable_dedup_keys(std::move(aggregatable_dedup_keys)),
event_triggers(std::move(event_triggers)),
aggregatable_trigger_data(aggregatable_trigger_data),
aggregatable_values(std::move(aggregatable_values)),
debug_reporting(debug_reporting),
aggregation_coordinator(aggregation_coordinator) {}
TriggerRegistration::~TriggerRegistration() = default;
TriggerRegistration::TriggerRegistration(const TriggerRegistration&) = default;
TriggerRegistration& TriggerRegistration::operator=(
const TriggerRegistration&) = default;
TriggerRegistration::TriggerRegistration(TriggerRegistration&&) = default;
TriggerRegistration& TriggerRegistration::operator=(TriggerRegistration&&) =
default;
base::Value::Dict TriggerRegistration::ToJson() const {
base::Value::Dict dict;
filters.SerializeIfNotEmpty(dict);
SerializeListIfNotEmpty(dict, kAggregatableDeduplicationKeys,
aggregatable_dedup_keys);
SerializeListIfNotEmpty(dict, kEventTriggerData, event_triggers);
SerializeListIfNotEmpty(dict, kAggregatableTriggerData,
aggregatable_trigger_data);
if (!aggregatable_values.values().empty()) {
dict.Set(kAggregatableValues, aggregatable_values.ToJson());
}
SerializeDebugKey(dict, debug_key);
SerializeDebugReporting(dict, debug_reporting);
dict.Set(kAggregationCoordinatorIdentifier,
aggregation_service::SerializeAggregationCoordinator(
aggregation_coordinator));
return dict;
}
} // namespace attribution_reporting