/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "nsISupports.idl"

interface nsIFile;
interface nsITransferable;
interface nsIURI;
webidl BrowsingContext;
webidl DataTransfer;
webidl DragEvent;
webidl WindowGlobalParent;

[scriptable, uuid(06e6a60f-3a2b-41fa-a63b-fea7a7f71649)]
interface nsIContentAnalysisAcknowledgement : nsISupports
{
  // These values must stay synchronized with ContentAnalysisAcknowledgement
  // in analysis.proto!
  // Acknowledgement of analysis response.
  cenum Result: 32 {
    eSuccess = 1, // The response was handled as specified by the agent.
    eInvalidResponse = 2, // The response from the agent was not properly formatted.
    eTooLate = 3, // The response from the agent was too late.
  };

  readonly attribute nsIContentAnalysisAcknowledgement_Result result;

  // These values must stay synchronized with ContentAnalysisAcknowledgement
  // in analysis.proto!
  // The final action that the browser took with this request.
  cenum FinalAction : 32 {
    eUnspecified = 0,
    eAllow = 1,
    eReportOnly = 2,
    eWarn = 3,
    eBlock = 4,
  };

  readonly attribute nsIContentAnalysisAcknowledgement_FinalAction finalAction;
};

[scriptable, builtinclass, uuid(9679545f-4256-4c90-9654-90292c355d25)]
interface nsIContentAnalysisResult : nsISupports
{
  [infallible] readonly attribute boolean shouldAllowContent;
};

[scriptable, builtinclass, uuid(89088c61-15f6-4ace-a880-a1b5ea47ca66)]
interface nsIContentAnalysisResponse : nsIContentAnalysisResult
{
  // These values must stay synchronized with ContentAnalysisResponse
  // in analysis.proto!
  // Action requested in response to a successful analysis.
  //
  // This must also stay in sync with ParamTraits<nsIContentAnalysisResponse::Action> in
  // ContentAnalysisIPCTypes.h!
  cenum Action : 32 {
    eUnspecified = 0,
    eReportOnly = 1,
    eWarn = 2,
    eBlock = 3,
    // Values that do not appear in analysis.proto
    eAllow = 1000,
    eCanceled = 1001,
  };

  cenum CancelError : 32 {
    eUserInitiated = 0,
    eNoAgent = 1,
    eInvalidAgentSignature = 2,
    eErrorOther = 3,
    eOtherRequestInGroupCancelled = 4,
    eShutdown = 5,
    eTimeout = 6,
  };

  [infallible] readonly attribute nsIContentAnalysisResponse_Action action;

  // If action is eCanceled, this is the error explaining why the request was canceled,
  // or eUserInitiated if the user canceled it.
  [infallible] readonly attribute nsIContentAnalysisResponse_CancelError cancelError;

  // Identifier for the corresponding nsIContentAnalysisRequest
  readonly attribute ACString requestToken;
  readonly attribute ACString userActionId;

  // Whether this is a cached result that wasn't actually sent to the DLP agent.
  // This indicates that the request was a duplicate of a previously sent one,
  // so any dialogs (for block/warn) should not be shown.
  [infallible] readonly attribute boolean isCachedResponse;

  // Whether this is a synthesizic response from Firefox (as opposed to a response
  // from a DLP agent).
  // Synthetic responses ignore browser.contentanalysis.show_blocked_result and
  // always show a blocked result for blocked content, since there is no agent
  // that could have shown one for us.
  [infallible] readonly attribute boolean isSyntheticResponse;

  /**
   * Acknowledge receipt of an analysis response.
   * If false is passed for aAutoAcknowledge to AnalyzeContentRequest,
   * the caller is responsible for calling this after successful
   * resolution of the promise.
   */
  void acknowledge(in nsIContentAnalysisAcknowledgement aCaa);
};

[scriptable, uuid(48d31df1-204d-42ce-a57f-f156bb870d89)]
interface nsIClientDownloadResource : nsISupports
{
  readonly attribute AString url;

  // These values must stay synchronized with ClientDownloadResource
  // in analysis.proto!
  // The final URL of the download payload.  The resource URL should
  // correspond to the URL field above.
  const unsigned long DOWNLOAD_URL = 0;
  // A redirect URL that was fetched before hitting the final DOWNLOAD_URL.
  const unsigned long DOWNLOAD_REDIRECT = 1;
  // The final top-level URL of the tab that triggered the download.
  const unsigned long TAB_URL = 2;
  // A redirect URL thas was fetched before hitting the final TAB_URL.
  const unsigned long TAB_REDIRECT = 3;
  // The document URL for a PPAPI plugin instance that initiated the download.
  // This is the document.url for the container element for the plugin
  // instance.
  const unsigned long PPAPI_DOCUMENT = 4;
  // The plugin URL for a PPAPI plugin instance that initiated the download.
  const unsigned long PPAPI_PLUGIN = 5;

  readonly attribute unsigned long type;
};

/**
 * A nsIContentAnalysisRequest represents a request (or multiple requests)
 * that the browser consult any required content analysis resources (like
 * external data-loss prevention applications) to determine if the attempted
 * operation should be permitted to complete.
 */
[scriptable, uuid(c11a6636-da2a-4afc-bdd1-0bcae2310e6d)]
interface nsIContentAnalysisRequest : nsISupports
{
  // These values must stay synchronized with ContentAnalysisRequest
  // in analysis.proto!
  // Type of analysis being requested.
  // For meaning, see analysis.proto in the content analysis module.
  cenum AnalysisType : 32 {
    eUnspecified = 0,
    eFileDownloaded = 1,
    eFileAttached = 2,
    eBulkDataEntry = 3,
    ePrint = 4,
    eFileTransfer = 5,
    eDataCopied = 6,
  };
  readonly attribute nsIContentAnalysisRequest_AnalysisType analysisType;

  // These values must stay synchronized with ContentAnalysisRequest.Reason
  // in analysis.proto!
  // Indicates the exact reason the request was created
  cenum Reason : 32 {
    eUnknown = 0,
    // Only possible for the eFileAttached and eBulkDataEntry AnalysisType's
    eClipboardPaste = 1,
    eDragAndDrop = 2,

    // Only possible for the eFileAttached AnalysisType
    eFilePickerDialog = 3,

    // Only possible for the ePrint AnalysisType
    ePrintPreviewPrint = 4,
    eSystemDialogPrint = 5,

    // Only possible for the eFileDownloaded AnalysisType
    eNormalDownload = 6,
    eSaveAsDownload = 7,

    // Only possible for the eDataCopied AnalysisType
    eClipboardCopy = 8,
  };
  readonly attribute nsIContentAnalysisRequest_Reason reason;

  // Enumeration of what operation is happening, to be displayed to the user
  cenum OperationType : 32 {
    eClipboard = 0,
    eDroppedText = 1,
    eOperationPrint = 2,
    eUpload = 3,
    eDownload = 4,
  };
  readonly attribute nsIContentAnalysisRequest_OperationType operationTypeForDisplay;
  // Required if operationTypeForDisplay is eUpload or eDownload.
  readonly attribute AString fileNameForDisplay;

  // ContentAnalysis will analyze the contents of this DataTransfer.  May
  // contain multiple items that require analysis, or none.
  // Only one of dataTransfer, transferable, textContent or filePath may be
  // defined.
  attribute DataTransfer dataTransfer;

  // ContentAnalysis will analyze the contents of this nsITransferable.  May
  // contain multiple items that require analysis, or none.
  // Only one of dataTransfer, transferable, textContent or filePath may be
  // defined.
  readonly attribute nsITransferable transferable;

  // Text content to analyze.
  // Only one of dataTransfer, transferable, textContent or filePath may be
  // defined.
  readonly attribute AString textContent;

  // Name of file to analyze.
  // Only one of dataTransfer, transferable, textContent or filePath may be
  // defined.
  readonly attribute AString filePath;

  // The printed data to analyze, in PDF format. Used by backends that read the
  // PDF bytes directly; the external-agent backend builds the Windows
  // shared-memory HANDLE it sends to the agent from these bytes.
  Array<octet> getPrintData();

  // Name of the printer being printed to.
  readonly attribute AString printerName;

  // The URL containing the file download/upload or to which web content is
  // being uploaded.
  readonly attribute nsIURI url;

  // Sha256 digest of file. Callers may pass in an empty string to have the
  // content analysis code calculate this.
  readonly attribute ACString sha256Digest;

  // URLs involved in the download (empty for non-downloads).
  readonly attribute Array<nsIClientDownloadResource> resources;

  // Email address of user.
  readonly attribute AString email;

  // Unique identifier for this request.  For internal use only.
  attribute ACString requestToken;

  // The window associated with this request
  readonly attribute WindowGlobalParent windowGlobalParent;

  // The user_action_id of this request. By default, this is equal to
  // the requestToken.  Will be set by ContentAnalysis if not assigned.
  attribute ACString userActionId;

  // The number of requests associated with this user_action_id. By default,
  // this is 1.  For internal use only.
  attribute int64_t userActionRequestsCount;

  // The WindowGlobalParent that was the source of the data in the request, or
  // null if unknown.
  readonly attribute WindowGlobalParent sourceWindowGlobal;

  // What to multiply the timeout for this request by. Only needed if there are
  // requests with multiple userActionIds that are logically grouped together.
  attribute uint32_t timeoutMultiplier;

  // Tests set this to allow reliably cancelling requests without that
  // triggering CA to skip sending to the agent.  Outside of tests, that is
  // a race where the winner is unimportant.  This must not be set outside
  // of tests.
  attribute boolean testOnlyIgnoreCanceledAndAlwaysSubmitToAgent;
};

[scriptable, builtinclass, uuid(cb09fc88-118c-411b-aa89-2e1bc5e3eba6)]
interface nsIContentAnalysisCallback : nsISupports
{
  void contentResult(in nsIContentAnalysisResult aResult);

  void error(in nsresult aResult);
};

[scriptable, builtinclass, uuid(a430f6ef-a526-4055-8a82-7741ea757367)]
interface nsIContentAnalysisDiagnosticInfo : nsISupports
{
  [infallible] readonly attribute boolean connectedToAgent;
  readonly attribute AString agentPath;
  [infallible] readonly attribute boolean failedSignatureVerification;
  [infallible] readonly attribute long long requestCount;
};

[scriptable, uuid(61497587-2bba-4a88-acd3-3fbb2cedf163)]
interface nsIContentAnalysis : nsISupports
{
  /**
   * True if content analysis should be consulted. Must only be accessed from
   * the parent process's main thread.
   */
  readonly attribute boolean isActive;

  /**
   * True if content analysis might be active, and False if content analysis
   * is definitely not active. Reading this property is guaranteed
   * to work from a content process, and can be used to avoid having to call
   * into the parent process to determine whether content analysis is actually
   * active.
   */
  readonly attribute boolean mightBeActive;

  %{C++
  /**
   * Static way to get the mightBeActive property.
   */
  static bool MightBeActive();
  %}

  /**
   * True if content-analysis activation was determined by enterprise policy,
   * as opposed to enabled with the `allow-content-analysis` command-line
   * parameter.
   */
  attribute boolean isSetByEnterprisePolicy;

  /**
   * Consults content analysis server, if any, to request a permission
   * decision for a network operation.  Allows blocking downloading/
   * uploading/printing/etc, based on the request.
   * Consultation with the content analysis tool follows the conventional
   * request, response, acknowledgement protocol.
   *
   * The resulting Promise resolves to a nsIContentAnalysisResult,
   * which may take some time to get from the analysis server.  It will
   * be rejected, with an string error description, if any error occurs.
   *
   * Requests may assign a user action ID if desired.  If that is done
   * then all requests must have the same ID or the function will return
   * an error.
   *
   * @param aCars
   *         The requests to analyze.
   * @param aAutoAcknowledge
   *         Whether to send an acknowledge message to the agent after the agent sends a response.
   *         Passing false means that the caller is responsible for
   *         calling nsIContentAnalysisResponse::acknowledge() if the Promise is resolved.
   * @return A promise that will resolve to a nsIContentAnalysisResult
   */
  [implicit_jscontext]
  Promise analyzeContentRequests(in Array<nsIContentAnalysisRequest> aCars,
                                 in boolean aAutoAcknowledge);

  /**
   * Same functionality as AnalyzeContentRequests(), but more convenient to call
   * from C++ since it takes a callback instead of returning a Promise.
   *
   * @param aCars
   *        The requests to analyze.
   * @param aAutoAcknowledge
   *        Whether to send an acknowledge message to the agent after the agent sends a response.
   *        Passing false means that the caller is responsible for
   *        calling nsIContentAnalysisResponse::acknowledge() if nsIContentAnalysisCallback::contentResult()
   *        is called.
   * @param callback
   *        Callbacks to be called when the agent sends a response message (or when there is an error).
   */
  void analyzeContentRequestsCallback(in Array<nsIContentAnalysisRequest> aCars,
                                      in boolean aAutoAcknowledge,
                                      in nsIContentAnalysisCallback callback);

  /**
   * Same functionality as analyzeContentRequests(), but only accepts one request
   * that must have a DataTransfer specified, and any files in the DataTransfer
   * will be analyzed in a batch mode where individual files can be blocked
   * without the whole request being rejected.
   *
   * @param aCar
   *         The request to analyze, which must have a DataTransfer specified.
   * @param aAutoAcknowledge
   *         Whether to send an acknowledge message to the agent after the agent sends a response.
   *         Passing false means that the caller is responsible for
   *         calling nsIContentAnalysisResponse::acknowledge() if the Promise is resolved.
   * @return A promise that will resolve to an array
   *         [array of files allowed, {shouldAllowRequest}]
   */
  [implicit_jscontext]
  Promise analyzeBatchContentRequest(in nsIContentAnalysisRequest aCar,
                                     in boolean aAutoAcknowledge);
  /**
   * Internal helper for 'analyzeContentRequest*' methods.  This is abstracted
   * so that it can be mocked in tests.  Do not call this.
   *
   * @param aRequest
   *        The request to analyze.
   * @param aAutoAcknowledge
   *        See analyzeContentRequestsCallback.
   * @param aCallback
   *        Callback to be called when the agent sends a response message (or
   *        when there is an error).
   */
  void analyzeContentRequestPrivate(
    in nsIContentAnalysisRequest aRequest, in boolean aAutoAcknowledge,
    in nsIContentAnalysisCallback aCallback);

  /**
   * Cancels the request that is in progress. This may not actually cancel the request
   * with the analysis server, but it means that Gecko will immediately act like the request
   * was denied.
   *
   * @param aUserActionId
   *        The user action ID for the request to cancel.
   */
  void cancelRequestsByUserAction(in ACString aUserActionId);

  /**
   * Like cancelRequestsByUserAction but does the same for any other user
   * actions when aUserActionId is part of a "compound action" ("batch mode")
   * -- one actually made up of several user actions.  See
   * ContentAnalysis::CheckUploadsInBatchMode for an explanation.
   *
   * @param aUserActionId
   *        The primary user action ID for the batch request to cancel.
   */
  void cancelAllRequestsAssociatedWithUserAction(in ACString aUserActionId);

  /**
   * Indicates that the user has responded to a WARN dialog. aAllowContent represents
   * whether the user wants to allow the request to go through.
   */
  void respondToWarnDialog(in ACString aRequestToken, in boolean aAllowContent);

  /**
   * Cancels all outstanding DLP requests. Used on shutdown.
   *
   * @param aForbidFutureRequests
   *        Block CA from ever sending future requests to agent.
   */
  void cancelAllRequests([optional] in boolean aForbidFutureRequests);

  /**
   * Test-only function that pretends that "-allow-content-analysis" was
   * given to Gecko on the command line.
   */
  void testOnlySetCACmdLineArg(in boolean aVal);

  /**
   * Gets diagnostic information about content analysis. Returns a
   * nsIContentAnalysisDiagnosticInfo via the returned promise.
   */
  [implicit_jscontext]
  Promise getDiagnosticInfo();

  /**
   * Gets the URI to use for the passed-in browsing context. This correctly
   * handles iframes.
   */
  nsIURI getURIForBrowsingContext(in BrowsingContext aBrowsingContext);

  /**
   * Gets the URI to use for the passed-in drop event. This correctly
   * handles iframes.
   */
  nsIURI getURIForDropEvent(in DragEvent aEvent);

  /**
   * Sets the cached response from analyzing the whole clipboard.
   *
   * @param aURI
   *        The URI of the page that requested the clipboard.
   * @param aSequenceNumber
   *        The native sequence number of the clipboard.
   * @param aAction
   *        The Content Analysis result from analyzing the clipboard data.
   */
  void setCachedResponse(in nsIURI aURI, in int32_t aSequenceNumber,
    in nsIContentAnalysisResponse_Action aAction);

  /**
   * Gets the cached response from analyzing the whole clipboard.
   *
   * @param aURI
   *        The URI of the page that requested the clipboard.
   * @param aSequenceNumber
   *        The native sequence number of the clipboard.
   * @param aAction
   *        The Content Analysis result from analyzing the clipboard data.
   * @param aIsValid
   *        Whether aAction is valid. (i.e. whether we have cached data)
   */
  void getCachedResponse(in nsIURI aURI, in int32_t aSequenceNumber,
    out nsIContentAnalysisResponse_Action aAction, out boolean aIsValid);

  /**
   * Show a dialog to indicate to the user that the given request was blocked.
   * This is only used when the request is blocked without needing to consult
   * the agent.
   *
   * This is abstracted so that it can be mocked in tests.  Do not call this.
   *
   * @param aRequest  The blocked request
   */
  void showBlockedRequestDialog(in nsIContentAnalysisRequest aRequest);

  /**
   * Make an nsIContentAnalysisResponse object.  For use in tests only.
   *
   * @param aAction        The response action
   * @param aToken         The request token
   * @param aUserActionID  The user action ID
   */
  nsIContentAnalysisResponse makeResponseForTest(
      in nsIContentAnalysisResponse_Action aAction,
      in ACString aToken,
      in ACString aUserActionId);

  /**
   * Send CancelRequests to agent on a background thread.
   *
   * This is abstracted so that it can be mocked in tests.  Do not call this.
   *
   * @param aUserActionId     The user action ID
   */
  void sendCancelToAgent(in ACString aUserActionId);

  /**
   * Force the content analysis client to be recreated. For use in tests only.
   */
  void forceRecreateClientForTest();
};

/**
 * A single Content Analysis rule passed to the built-in DLP module
 */
[scriptable, uuid(b7e6d5c4-3a2f-4e1d-8c9b-0a1f2e3d4c5b)]
interface nsIContentAnalysisRule : nsISupports {
  // Values for `verdict`
  const octet REPORT = 0;
  const octet WARN = 1;
  const octet BLOCK = 2;

  // Stable rule identifier (config "Name").
  readonly attribute AString name;

  // Operations this rule applies to, as nsIContentAnalysisRequest.AnalysisType
  // values. Empty means it applies to all operations.
  readonly attribute Array<unsigned long> operations;

  // Hosts the rule applies to (config "Domains"); a request matches when its URL
  // host equals one of these or is a subdomain of it. Empty means any host.
  readonly attribute Array<AString> domains;

  // Regular expressions tested against the request content; the rule matches if any
  // one matches. Empty means no content restriction.
  readonly attribute Array<AString> contentPatterns;

  // The action to apply on a match; one of the constants above.
  readonly attribute octet verdict;

  // Optional user-facing message (config "Message"); empty if none.
  readonly attribute AString message;
};

/**
 * Runs an in-process WebAssembly DLP module. Implemented in JS
 * (ContentAnalysisWasmRunner.sys.mjs). The parent-process service reads and
 * signature-checks the module out of the configured extension, then compiles and
 * runs it in a content process (via the ContentAnalysisWasm actor) because the
 * parent process forbids wasm compilation. The C++ WasmModuleBackend calls this.
 */
[scriptable, uuid(909ea37a-71a0-4454-82ec-98a64087fe22)]
interface nsIContentAnalysisWasmRunner : nsISupports {
  /**
   * Analyze a request asynchronously.
   *
   * @param aRequestBytes  Serialized content_analysis.sdk.ContentAnalysisRequest.
   * @param aContentBytes  Bytes for file_path/print_data content,
   *                       or empty for inline text_content requests.
   * @param aRules         DLP rules to evaluate. The runner marshals these into the
   *                       module's FfiRule ABI.
   * @return A Promise that resolves with the serialized
   *         content_analysis.sdk.ContentAnalysisResponse (as an Array<octet>), or
   *         rejects if the module is unavailable or the extension is not acceptably
   *         signed.
   */
  Promise analyze(in Array<octet> aRequestBytes,
                  in Array<octet> aContentBytes,
                  in Array<nsIContentAnalysisRule> aRules);
};
