910e62b5创建于 1月15日历史提交
// 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