// Copyright 2020 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";

package enterprise_connectors;

option optimize_for = LITE_RUNTIME;

// For ClientDownloadRequest.
import "components/safe_browsing/core/common/proto/csd.proto";

// Which connector is calling BinaryUploadService so that the proper rules can
// be triggered.  BinaryUploadService also uses this value to find the URL that
// the payload should be uploaded to.
//
// The values in this enum can be extended in future versions of Chrome to
// support new analysis connectors.
enum AnalysisConnector {
  ANALYSIS_CONNECTOR_UNSPECIFIED = 0;
  FILE_DOWNLOADED = 1;
  FILE_ATTACHED = 2;
  BULK_DATA_ENTRY = 3;
  PRINT = 4;
  FILE_TRANSFER = 5;
  DATA_COPIED = 6;
  NETWORK_REQUEST = 7;
}

message ContentMetaData {
  // The URL containing the file download/upload or to which web content is
  // being uploaded.
  optional string url = 1;

  // Name of file on user system (if applicable).
  optional string filename = 2;

  // Sha256 digest of file.
  optional string digest = 3;

  // Specifically for the download case.
  optional safe_browsing.ClientDownloadRequest csd = 4;

  // Optional email address of user.  This field may be empty if the user
  // is not signed in.
  optional string email = 5;

  // MimeType of the field as detected by Chrome.
  optional string content_type = 6;

  // Source information, e.g., url or path.
  optional string source = 7;

  // Destination information, e.g., url or path.
  optional string destination = 8;

  // Name of tab title.
  optional string tab_title = 9;

  // URL of the tab. Only different from `url` for downloads.
  optional string tab_url = 10;

  // Empty for non-print actions.
  message PrintMetadata {
    optional string printer_name = 1;

    enum PrinterType {
      UNKNOWN = 0;
      CLOUD = 1;
      LOCAL = 2;
    }
    optional PrinterType printer_type = 2;
  }
  optional PrintMetadata print_metadata = 11;

  // Password for an encrypted archive.
  optional bytes decryption_key = 12;

  // Contains copied text source details for text paste event.
  message CopiedTextSource {
    // Holds URL from where data was copied.
    optional string url = 1;

    enum CopiedTextSourceType {
      UNSPECIFIED = 0;
      INCOGNITO = 1;
      CLIPBOARD = 2;
      OTHER_PROFILE = 3;
      SAME_PROFILE = 4;
      GEMINI_IN_CHROME = 5;
    }
    // Holds Chrome context of copied data.
    optional CopiedTextSourceType context = 2;
  }
  optional CopiedTextSource copied_text_source = 13;

  repeated safe_browsing.ReferrerChainEntry referrer_chain = 14;

  // The email of the currently active user in the content area. Only populated
  // for Workspace sites.
  optional string content_area_account_email = 15;

  // The email of the active user in the content area of the copy source. Only
  // populated for paste events when the copy source is Workspace sites.
  optional string source_content_area_account_email = 17;

  // The parent URL chain of the frame from which the action was triggered,
  // ordered from current frame URL to tab URL, inclusive.
  repeated string frame_url_chain = 16;

  // File size in bytes. Only populated for file scanning events.
  optional uint64 file_size = 18;
}

message ClientMetadata {
  // Describes the browser uploading a scan request.
  message Browser {
    optional string browser_id = 1;
    optional string user_agent = 2;
    optional string chrome_version = 3;

    // This is omitted on scans triggered at the profile level.
    optional string machine_user = 4;
  }
  optional Browser browser = 1;

  // Describes the device uploading a scan request. This is omitted on scans
  // triggered at the profile level.
  message Device {
    optional string dm_token = 1;
    optional string client_id = 2;
    optional string os_version = 3;
    optional string os_platform = 4;
    optional string name = 5;
    optional string device_fqdn = 6;
    optional string network_name = 7;
  }
  optional Device device = 2;

  // Describes the profile uploading a scan request.
  message Profile {
    optional string dm_token = 1;
    optional string gaia_email = 2;
    optional string profile_path = 3;
    optional string profile_name = 4;
    optional string client_id = 5;

    reserved 6;
  }
  optional Profile profile = 3;

  // True if the request comes from a Managed Guest Session on ChromeOS. False
  // in all other cases.
  optional bool is_chrome_os_managed_guest_session = 4;
}

// Analysis request sent from chrome to backend.
// The proto here is the source of truth; the copy in the LCAC Github repo
// should always be in sync with it
// (https://github.com/chromium/content_analysis_sdk/blob/main/proto/content_analysis/sdk/analysis.proto)
message ContentAnalysisRequest {
  // The TokenID for Enterprise-enrolled devices.  This identifies a specific
  // chrome instance.
  optional string device_token = 1;

  reserved 2;

  // Token used to correlate requests and responses. This is different than the
  // FCM token in that it is unique for each request.
  optional string request_token = 5;

  // Which enterprise connector fired this request.
  optional AnalysisConnector analysis_connector = 9;

  // Information about the data that triggered the content analysis request.
  optional ContentMetaData request_data = 10;

  // The tags configured for the URL that triggered the content analysis.
  repeated string tags = 11;

  // Additional information about the browser, device or profile so events can
  // be reported with device/user identifiable information.
  optional ClientMetadata client_metadata = 12;

  oneof content_data {
    // The text content to analyze in local content analysis request. This field
    // is mutually exclusive with file_path.
    string text_content = 13;

    // The full path to the file to analyze in local content analysis request.
    // The path is expressed in a platform dependent way. This field is mutually
    // exclusive with text_content.
    string file_path = 14;
  }

  // The absolute deadline (timestamp in UTC Epoch time) that Chrome will wait
  // until a response from the agent is received.
  optional int64 expires_at = 15;

  // ID for keeping track of analysis requests that belong to the same user
  // action.
  optional string user_action_id = 16;

  // Count of analysis requests that belong to the same user action.
  optional int64 user_action_requests_count = 17;

  // Indicates the exact reason the request was created, ie which user action
  // led to a data transfer.
  enum Reason {
    UNKNOWN = 0;

    // Only possible for the `FILE_ATTACHED` and `BULK_DATA_ENTRY` actions.
    CLIPBOARD_PASTE = 1;
    DRAG_AND_DROP = 2;

    // Only possible for the `FILE_ATTACHED` action.
    FILE_PICKER_DIALOG = 3;

    // Only possible for the `PRINT` analysis connector.
    PRINT_PREVIEW_PRINT = 4;
    SYSTEM_DIALOG_PRINT = 5;

    // Only possible for the `FILE_DOWNLOADED` analysis connector.
    NORMAL_DOWNLOAD = 6;
    SAVE_AS_DOWNLOAD = 7;
    CLIPBOARD_COPY = 8;
  }
  optional Reason reason = 19;

  // Indicates whether request is blocking until verdict given.
  optional bool blocking = 20;

  reserved 21;

  // Local IP addresses of the device.
  repeated string local_ips = 22;

  // Indicates whether the request is for content that is encrypted.
  optional bool is_content_encrypted = 23;

  // If true, the content hash is given during the finalize call rather than
  // the initial upload, only for larger files.
  optional bool content_hash_in_final_call = 24;

  // If true, the request originates from mobile browser.
  optional bool is_mobile = 25;

  // Reserved to make sure there is no overlap with DeepScanningClientRequest.
  reserved 3, 4, 6 to 8;
}

// Scanning response sent from backend to Chrome.
message ContentAnalysisResponse {
  // Token used to correlate requests and responses. Corresponds to field in
  // ContentAnalysisRequest with the same name.
  optional string request_token = 1;

  // Represents the analysis result from a given tag.
  message Result {
    optional string tag = 1;

    // The status of this result.
    enum Status {
      STATUS_UNKNOWN = 0;
      SUCCESS = 1;
      FAILURE = 2;
    }
    optional Status status = 2;

    message CustomMessage {
      option deprecated = true;

      // An admin-provided url that should lead to a page where the user can
      // learn more about the restrictions in place in their organization.
      optional string learn_more_url = 1;
      // An admin-provided message that will be shown to the user when a scan
      // results is not clean. This message should not be more than 200
      // characters long.
      optional string message = 2;
    }

    // Identifies the detection rules that were triggered by the analysis.
    // Only relevant when status is SUCCESS.
    message TriggeredRule {
      enum Action {
        ACTION_UNSPECIFIED = 0;
        REPORT_ONLY = 1;
        WARN = 2;
        BLOCK = 3;
        FORCE_SAVE_TO_CLOUD = 4;
        JUSTIFICATION_REQUIRED = 5;
        KEEP_IN_MANAGED_CHROME = 6;
      }
      optional Action action = 1;
      optional string rule_name = 2;
      optional string rule_id = 3;

      // This represents text segment in a custom message defined for DLP
      // rule. For ex: “Please learn more (here)[link] and (here)[link]"
      // is broken into 4 segments.
      message CustomRuleMessageSegment {
        // Required. Text to be displayed in this segment.
        optional string text = 1;

        // Optional. Link to external resource, such as a company's
        // communication policy. This is supposed to be hyperlink on text
        // field above.
        optional string link = 2;
      }

      // This represents the custom rule message defined by admins to be shown
      // to users if the rule is triggered.
      message CustomRuleMessage {
        // Ordered list of text segments comprised of plain text and URLs. These
        // combined represent the custom rule message.
        repeated CustomRuleMessageSegment message_segments = 1;
      }

      // This field contains a custom message that is specific to the rules
      // triggered by this scan, if any. This messages can be shown in addition
      // to the OU-based message found in the client-side policy or at the
      // top-level of the Result message.
      optional CustomMessage custom_message = 4 [deprecated = true];
      // Matched URL Category of the URL.
      optional string url_category = 5;

      // If provided, this field contains a custom message that should be
      // displayed instead of the default one. This is set by admins in Rule
      // definition UI. This is set by admins in Rule definition UI.
      optional CustomRuleMessage custom_rule_message = 6;

      enum ForceSaveToCloudDestination {
        UNSPECIFIED = 0;
        CORP_G_DRIVE = 1;
        CORP_ONEDRIVE = 2;
      }

      optional ForceSaveToCloudDestination force_save_to_cloud_destination = 7;
    }

    repeated TriggeredRule triggered_rules = 3;

    reserved 4, 5, 6;

    // This field is meant to override the OU-based custom messages set in the
    // client-side policies. When the result requires a
    // warning, if this field has a value it's the one that will be displayed to
    // the user, otherwise the client-side policy's custom message will be used.
    // TODO(b/316008309): Cleanup code once new custom message rolled out.
    optional CustomMessage custom_message = 7 [deprecated = true];

    enum StatusErrorMessage {
      STATUS_ERROR_MESSAGE_UNSPECIFIED = 0;
      DECRYPTION_FAILED = 1;
    }
    optional StatusErrorMessage status_error_message = 8;
  }
  repeated Result results = 4;

  // Reserved to make sure there is no overlap with DeepScanningClientResponse.
  reserved 2 to 3;
}

// An Acknowledgement is sent by the browser following the receipt of a response
// from the agent.
message ContentAnalysisAcknowledgement {
  // Token used to correlate with the corresponding request and response.
  optional string request_token = 1;

  // The action taken by google Chrome with the content analysis response.
  enum Status {
    // The response was handled as specified by the agent.
    SUCCESS = 1;

    // The response from the agent was not properly formatted.
    INVALID_RESPONSE = 2;

    // The response from the agent was too late and Google Chrome took the
    // default action.
    TOO_LATE = 3;
  }
  optional Status status = 2;

  // The final action that chrome took with this request.  This may be different
  // from the action specified in the response if the response was too late or
  // if the original request was part of a user action whose overall final
  // differed from the action of this particular request.
  enum FinalAction {
    ACTION_UNSPECIFIED = 0;
    ALLOW = 1;
    REPORT_ONLY = 2;
    WARN = 3;
    BLOCK = 4;
    KEEP_IN_MANAGED_CHROME = 5;
  }
  optional FinalAction final_action = 3;
}
