// 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;
}