blob: 0b86c7997099511375f0e4837e2bc040d8ac504c [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/source_registration.h"
#include <stdint.h>
#include <string>
#include <utility>
#include "base/check.h"
#include "base/json/json_reader.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/values.h"
#include "components/attribution_reporting/aggregation_keys.h"
#include "components/attribution_reporting/destination_set.h"
#include "components/attribution_reporting/filters.h"
#include "components/attribution_reporting/parsing_utils.h"
#include "components/attribution_reporting/source_registration_error.mojom.h"
#include "components/attribution_reporting/suitable_origin.h"
#include "mojo/public/cpp/bindings/default_construct_tag.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace attribution_reporting {
namespace {
using ::attribution_reporting::mojom::SourceRegistrationError;
constexpr char kAggregatableReportWindow[] = "aggregatable_report_window";
constexpr char kAggregationKeys[] = "aggregation_keys";
constexpr char kDestination[] = "destination";
constexpr char kEventReportWindow[] = "event_report_window";
constexpr char kExpiry[] = "expiry";
constexpr char kFilterData[] = "filter_data";
constexpr char kSourceEventId[] = "source_event_id";
absl::optional<base::TimeDelta> ParseTimeDeltaInSeconds(
const base::Value::Dict& registration,
base::StringPiece key) {
if (absl::optional<int64_t> seconds = ParseInt64(registration, key))
return base::Seconds(*seconds);
return absl::nullopt;
}
void SerializeTimeDeltaInSeconds(base::Value::Dict& dict,
base::StringPiece key,
absl::optional<base::TimeDelta> value) {
if (value) {
SerializeInt64(dict, key, value->InSeconds());
}
}
} // namespace
void RecordSourceRegistrationError(mojom::SourceRegistrationError error) {
base::UmaHistogramEnumeration("Conversions.SourceRegistrationError2", error);
}
SourceRegistration::SourceRegistration(mojo::DefaultConstruct::Tag tag)
: destination_set(tag) {}
SourceRegistration::SourceRegistration(DestinationSet destination_set)
: destination_set(std::move(destination_set)) {}
SourceRegistration::~SourceRegistration() = default;
SourceRegistration::SourceRegistration(const SourceRegistration&) = default;
SourceRegistration& SourceRegistration::operator=(const SourceRegistration&) =
default;
SourceRegistration::SourceRegistration(SourceRegistration&&) = default;
SourceRegistration& SourceRegistration::operator=(SourceRegistration&&) =
default;
// static
base::expected<SourceRegistration, SourceRegistrationError>
SourceRegistration::Parse(base::Value::Dict registration) {
base::expected<DestinationSet, SourceRegistrationError> destination_set =
DestinationSet::FromJSON(registration.Find(kDestination));
if (!destination_set.has_value()) {
return base::unexpected(destination_set.error());
}
SourceRegistration result(std::move(*destination_set));
base::expected<FilterData, SourceRegistrationError> filter_data =
FilterData::FromJSON(registration.Find(kFilterData));
if (!filter_data.has_value())
return base::unexpected(filter_data.error());
result.filter_data = std::move(*filter_data);
base::expected<AggregationKeys, SourceRegistrationError> aggregation_keys =
AggregationKeys::FromJSON(registration.Find(kAggregationKeys));
if (!aggregation_keys.has_value())
return base::unexpected(aggregation_keys.error());
result.aggregation_keys = std::move(*aggregation_keys);
result.source_event_id =
ParseUint64(registration, kSourceEventId).value_or(0);
result.priority = ParsePriority(registration);
result.expiry = ParseTimeDeltaInSeconds(registration, kExpiry);
result.event_report_window =
ParseTimeDeltaInSeconds(registration, kEventReportWindow);
result.aggregatable_report_window =
ParseTimeDeltaInSeconds(registration, kAggregatableReportWindow);
result.debug_key = ParseDebugKey(registration);
result.debug_reporting = ParseDebugReporting(registration);
return result;
}
// static
base::expected<SourceRegistration, SourceRegistrationError>
SourceRegistration::Parse(base::StringPiece json) {
base::expected<SourceRegistration, SourceRegistrationError> source =
base::unexpected(SourceRegistrationError::kInvalidJson);
absl::optional<base::Value> value =
base::JSONReader::Read(json, base::JSON_PARSE_RFC);
if (value) {
if (value->is_dict()) {
source = Parse(std::move(*value).TakeDict());
} else {
source = base::unexpected(SourceRegistrationError::kRootWrongType);
}
}
if (!source.has_value()) {
RecordSourceRegistrationError(source.error());
}
return source;
}
base::Value::Dict SourceRegistration::ToJson() const {
base::Value::Dict dict;
dict.Set(kDestination, destination_set.ToJson());
if (!filter_data.filter_values().empty()) {
dict.Set(kFilterData, filter_data.ToJson());
}
if (!aggregation_keys.keys().empty()) {
dict.Set(kAggregationKeys, aggregation_keys.ToJson());
}
SerializeUint64(dict, kSourceEventId, source_event_id);
SerializePriority(dict, priority);
SerializeTimeDeltaInSeconds(dict, kExpiry, expiry);
SerializeTimeDeltaInSeconds(dict, kEventReportWindow, event_report_window);
SerializeTimeDeltaInSeconds(dict, kAggregatableReportWindow,
aggregatable_report_window);
SerializeDebugKey(dict, debug_key);
SerializeDebugReporting(dict, debug_reporting);
return dict;
}
} // namespace attribution_reporting