chromium/components/reporting/proto/synced/record.proto

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

syntax = "proto2";

option optimize_for = LITE_RUNTIME;

package reporting;

import "components/reporting/proto/synced/health.proto";
import "components/reporting/proto/synced/record_constants.proto";

// Record represents the data sent from the Reporting Client.
message Record {
  // Record data as enqueued with an ReportQueue::Enqueue call (required).
  // Data structure requirements are set by the destination. For destinations
  // expecting a proto - the proto will be MessageLite::SerializeToString(), and
  // will be DeserializedFromString() in the destination handler, prior to being
  // forwarded.
  optional bytes data = 1;

  // The destination associated with this request as set with the
  // ReportQueueConfiguration (required).
  optional Destination destination = 2;

  // The DMToken associated with this request as set with the
  // ReportQueueConfiuguration (required, if this is user token).
  optional string dm_token = 3;

  // When the record was submitted to ReportQueue::Enqueue.
  // Represents UTC time since Unix epoch 1970-01-01T00:00:00Z in microseconds,
  // to match Spanner timestamp format.
  optional int64 timestamp_us = 4;

  // Reserved space specified by ReportQueueConfiguration (unless it is 0).
  // Note that this field is cleared while enqueuing the event.
  optional int64 reserved_space = 5;

  // Record is tracking progress of some external activity;
  // its unencrypted copy needs to be attached to the EncryptedRecord
  // for uploader to be able to re-enqueue it.
  // Note that this field is cleared while enqueuing the event.
  optional bool needs_local_unencrypted_copy = 6;

  // Additional metadata about the source enqueueing the record.
  optional SourceInfo source_info = 7;
}

// Source metadata used to identify the source that enqueues a given record.
// Especially useful when there are multiple sources that can enqueue similar
// records.
message SourceInfo {
  enum Source {
    SOURCE_UNSPECIFIED = 0;

    // Ash browser.
    ASH = 1;

    // Lacros browser.
    LACROS = 2;
  }

  // Source enqueueing the record (required).
  optional Source source = 1;

  // Version metadata about the source.
  optional string source_version = 2;
}

// A Record with it's digest and the digest of the previous record.
message WrappedRecord {
  // Record (required)
  // Data provided by the Reporting Client.
  optional Record record = 1;

  // Record Digest (required)
  // SHA256 hash used to validate that the record has been retrieved without
  // being manipulated while it was on the device or during transfer.
  optional bytes record_digest = 2;

  // Last record digest (required)
  // Created by client and used by server to verify that the sequence of records
  // has not been tampered with.
  optional bytes last_record_digest = 3;
}

// Information about how the record was encrypted.
message EncryptionInfo {
  // Encryption key (optional).
  // Represents the client's X25519 public key used along with the server's
  // private key (identified by |public_key_id|) for shared secret recreation by
  // the server to compose the symmetric key used for |encrypted_wrapped_record|
  // encryption. Is transmitted in plaintext.
  optional bytes encryption_key = 1;

  // Public key id (optional)
  // Hash of the public key used to do encryption. Used to identity the server
  // private key for decryption. If no key_id is present,
  // |encrypted_wrapped_record| is transmitted in plaintext (which has become a
  // test-only feature).
  optional int64 public_key_id = 2;
}

// Tracking information for what order a record appears in.
message SequenceInformation {
  // Sequencing ID (monotonic number, required)
  // Tracks records processing progress and is used for confirming that this
  // and all prior records have been processed. Always starts from zero, and
  // increases by one each time in a perfect world. If the same number is
  // encountered more than once, only one instance needs to be processed. If
  // certain number is absent when higher are encountered, it indicates that
  // some records have been lost and there is a gap in the records stream (what
  // to do with that is a decision that the caller needs to make).
  optional int64 sequencing_id = 1;

  // Generation ID (required). Generated randomly anew for each user + device +
  // priority combination when previous record digest is not found at startup
  // (e.g. after powerwash). A new `generation_id` indicates the server should
  // expect a `sequencing_id` of 0. Not unique -- the key space of user + device
  // + priority combinations is too large for 64 bits.
  optional int64 generation_id = 2;

  // Priority (required)
  // Generation IDs are per Priority.
  optional Priority priority = 3;

  // Generation GUID (required for unmanaged devices). Unique per combination of
  // user + device + priority. Behaves the same way as `generation_id` but is
  // large enough to serve as a GUID across all user + device + priority
  // combinations. Used as a key on the server to retrieve
  // `SequenceInformation`.
  optional string generation_guid = 4;
}

// Envelope for the |WrappedRecord| and associated metadata as it is stored on
// disk and sent to the server.
message EncryptedRecord {
  // Encrypted Wrapped Record (required)
  // |WrappedRecord| encrypted with the symmetric key. When absent, indicates
  // gap - respective record is irreparably corrupt or missing from Storage, and
  // server side should log it as such and no longer expect client to deliver
  // it. Otherwise, must be present.
  optional bytes encrypted_wrapped_record = 1;

  // Must be present to facilitate decryption of encrypted record.
  // If missing, the record is either not encrypted or missing.
  optional EncryptionInfo encryption_info = 2;

  // Sequence information (required). Must be present to allow
  // tracking and confirmation of the events by server.
  optional SequenceInformation sequence_information = 3;

  // Compression information (optional).
  optional CompressionInformation compression_information = 4;

  optional SequenceInformation sequencing_information = 5 [deprecated = true];

  optional ERPHealthData erp_health_data = 6;

  // In special cases (e.g. `LOG_UPLOAD` events) this field is an unencrypted
  // copy of original `Record`. It is only attached to `EncryptedRecord` in
  // Storage and is eliminated by ERP uploader before sending the records to the
  // server. Using `record_copy` the uploader is able to post a new event for
  // the same `Destination` and modify upload tracking part of it.
  optional Record record_copy = 7;
}

// Tracking information for what compression is used.
message CompressionInformation {
  // Compression algorithms available for use
  enum CompressionAlgorithm {
    COMPRESSION_NONE = 0;
    COMPRESSION_SNAPPY = 1;
  }

  // Compression algorithm that is used if the record was
  // compressed before being wrapped (optional).
  optional CompressionAlgorithm compression_algorithm = 1;
}

// Encryption public key as delivered from the server and stored in Storage.
// Signature ensures the key was actually sent by the server and not manipulated
// afterwards.
message SignedEncryptionInfo {
  // Public asymmetric key (required).
  optional bytes public_asymmetric_key = 1;

  // Public key id (required).
  // Identifies private key matching |public_asymmetric_key| for the server.
  // Matches Encryptor::PublicKeyId.
  optional int32 public_key_id = 2;

  // Signature of |public_asymmetric_key| (required).
  // Verified by client against a well-known signature.
  optional bytes signature = 3;
}

// List of blocked destinations delivered from the server, this list is already
// processed by the browser to check for OS version compliance.
message ListOfBlockedDestinations {
  repeated Destination destinations = 1;
}