blob: a44cef72f909de328c12beb519b64f4399defe6c [file] [log] [blame]
// Copyright 2023 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/aggregatable_trigger_config.h"
#include <stddef.h>
#include <optional>
#include <string>
#include <utility>
#include "base/check.h"
#include "base/notreached.h"
#include "base/types/expected.h"
#include "base/types/expected_macros.h"
#include "base/values.h"
#include "components/attribution_reporting/aggregatable_filtering_id_max_bytes.h"
#include "components/attribution_reporting/constants.h"
#include "components/attribution_reporting/source_registration_time_config.mojom.h"
#include "components/attribution_reporting/trigger_registration_error.mojom.h"
namespace attribution_reporting {
namespace {
using ::attribution_reporting::mojom::SourceRegistrationTimeConfig;
using ::attribution_reporting::mojom::TriggerRegistrationError;
base::expected<SourceRegistrationTimeConfig, TriggerRegistrationError>
ParseAggregatableSourceRegistrationTime(const base::Value* value) {
if (!value) {
return SourceRegistrationTimeConfig::kExclude;
}
const std::string* str = value->GetIfString();
if (!str) {
return base::unexpected(
TriggerRegistrationError::
kAggregatableSourceRegistrationTimeValueInvalid);
}
if (*str == kSourceRegistrationTimeInclude) {
return SourceRegistrationTimeConfig::kInclude;
}
if (*str == kSourceRegistrationTimeExclude) {
return SourceRegistrationTimeConfig::kExclude;
}
return base::unexpected(TriggerRegistrationError::
kAggregatableSourceRegistrationTimeValueInvalid);
}
std::string SerializeAggregatableSourceRegistrationTime(
SourceRegistrationTimeConfig config) {
switch (config) {
case SourceRegistrationTimeConfig::kInclude:
return kSourceRegistrationTimeInclude;
case SourceRegistrationTimeConfig::kExclude:
return kSourceRegistrationTimeExclude;
}
}
bool IsTriggerContextIdValid(const std::string& s) {
return s.length() <= kMaxTriggerContextIdLength;
}
bool IsTriggerContextIdAllowed(
SourceRegistrationTimeConfig source_registration_time_config) {
switch (source_registration_time_config) {
case SourceRegistrationTimeConfig::kExclude:
return true;
case SourceRegistrationTimeConfig::kInclude:
return false;
}
}
bool IsMaxBytesAllowed(
AggregatableFilteringIdsMaxBytes max_bytes,
SourceRegistrationTimeConfig source_registration_time_config) {
switch (source_registration_time_config) {
case SourceRegistrationTimeConfig::kExclude:
return true;
case SourceRegistrationTimeConfig::kInclude:
return max_bytes.IsDefault();
}
NOTREACHED();
}
bool IsValid(SourceRegistrationTimeConfig source_registration_time_config,
const std::optional<std::string>& trigger_context_id,
AggregatableFilteringIdsMaxBytes max_bytes) {
const bool trigger_context_id_valid =
!trigger_context_id.has_value() ||
(IsTriggerContextIdValid(*trigger_context_id) &&
IsTriggerContextIdAllowed(source_registration_time_config));
return trigger_context_id_valid &&
IsMaxBytesAllowed(max_bytes, source_registration_time_config);
}
base::expected<std::optional<std::string>, TriggerRegistrationError>
ParseTriggerContextId(base::Value* value) {
if (!value) {
return std::nullopt;
}
std::string* s = value->GetIfString();
if (!s || !IsTriggerContextIdValid(*s)) {
return base::unexpected(
TriggerRegistrationError::kTriggerContextIdInvalidValue);
}
return std::move(*s);
}
} // namespace
// static
base::expected<AggregatableTriggerConfig, TriggerRegistrationError>
AggregatableTriggerConfig::Parse(base::Value::Dict& dict) {
ASSIGN_OR_RETURN(SourceRegistrationTimeConfig source_registration_time_config,
ParseAggregatableSourceRegistrationTime(
dict.Find(kAggregatableSourceRegistrationTime)));
ASSIGN_OR_RETURN(std::optional<std::string> trigger_context_id,
ParseTriggerContextId(dict.Find(kTriggerContextId)));
if (trigger_context_id.has_value() &&
!IsTriggerContextIdAllowed(source_registration_time_config)) {
return base::unexpected(
TriggerRegistrationError::
kTriggerContextIdInvalidSourceRegistrationTimeConfig);
}
AggregatableFilteringIdsMaxBytes max_bytes;
ASSIGN_OR_RETURN(max_bytes, AggregatableFilteringIdsMaxBytes::Parse(dict));
if (!IsMaxBytesAllowed(max_bytes, source_registration_time_config)) {
return base::unexpected(
TriggerRegistrationError::
kAggregatableFilteringIdsMaxBytesInvalidSourceRegistrationTimeConfig);
}
return AggregatableTriggerConfig(source_registration_time_config,
std::move(trigger_context_id), max_bytes);
}
// static
std::optional<AggregatableTriggerConfig> AggregatableTriggerConfig::Create(
SourceRegistrationTimeConfig source_registration_time_config,
std::optional<std::string> trigger_context_id,
AggregatableFilteringIdsMaxBytes max_bytes) {
if (!IsValid(source_registration_time_config, trigger_context_id,
max_bytes)) {
return std::nullopt;
}
return AggregatableTriggerConfig(source_registration_time_config,
std::move(trigger_context_id), max_bytes);
}
AggregatableTriggerConfig::AggregatableTriggerConfig() = default;
AggregatableTriggerConfig::AggregatableTriggerConfig(
SourceRegistrationTimeConfig source_registration_time_config,
std::optional<std::string> trigger_context_id,
AggregatableFilteringIdsMaxBytes max_bytes)
: source_registration_time_config_(source_registration_time_config),
trigger_context_id_(std::move(trigger_context_id)),
aggregatable_filtering_id_max_bytes_(max_bytes) {
CHECK(IsValid(source_registration_time_config_, trigger_context_id_,
aggregatable_filtering_id_max_bytes_));
}
AggregatableTriggerConfig::AggregatableTriggerConfig(
const AggregatableTriggerConfig&) = default;
AggregatableTriggerConfig& AggregatableTriggerConfig::operator=(
const AggregatableTriggerConfig&) = default;
AggregatableTriggerConfig::AggregatableTriggerConfig(
AggregatableTriggerConfig&&) = default;
AggregatableTriggerConfig& AggregatableTriggerConfig::operator=(
AggregatableTriggerConfig&&) = default;
AggregatableTriggerConfig::~AggregatableTriggerConfig() = default;
void AggregatableTriggerConfig::Serialize(base::Value::Dict& dict) const {
dict.Set(kAggregatableSourceRegistrationTime,
SerializeAggregatableSourceRegistrationTime(
source_registration_time_config_));
if (trigger_context_id_.has_value()) {
dict.Set(kTriggerContextId, *trigger_context_id_);
}
aggregatable_filtering_id_max_bytes_.Serialize(dict);
}
bool AggregatableTriggerConfig::ShouldCauseAReportToBeSentUnconditionally()
const {
return trigger_context_id_.has_value() ||
!aggregatable_filtering_id_max_bytes_.IsDefault();
}
} // namespace attribution_reporting