1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
|
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_WARNING_DATA_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_WARNING_DATA_H_
#include <optional>
#include <vector>
#include "base/supports_user_data.h"
#include "base/time/time.h"
#include "components/safe_browsing/core/common/proto/csd.pb.h"
namespace download {
class DownloadItem;
}
// Per DownloadItem data for storing warning events on download warnings. The
// data is only set if a warning is shown. These events are added to Safe
// Browsing reports.
class DownloadItemWarningData : public base::SupportsUserData::Data {
public:
// The surface that the warning is shown. See
// go/chrome-download-warning-surfaces for details.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class WarningSurface {
// Applicable actions: DISCARD, OPEN_SUBPAGE
BUBBLE_MAINPAGE = 1,
// Applicable actions: PROCEED, DISCARD, DISMISS, CLOSE, BACK,
// PROCEED_DEEP_SCAN, ACCEPT_DEEP_SCAN, OPEN_LEARN_MORE_LINK
BUBBLE_SUBPAGE = 2,
// Applicable actions: DISCARD, KEEP, PROCEED, ACCEPT_DEEP_SCAN
// PROCEED on the downloads page indicates saving a "suspicious" download
// directly, without going through the prompt. In contrast, KEEP indicates
// opening the prompt, for a "dangerous" download.
DOWNLOADS_PAGE = 3,
// Applicable actions: PROCEED, CANCEL
DOWNLOAD_PROMPT = 4,
// Applicable actions: OPEN_SUBPAGE
// Note: This is only used on Lacros. DownloadItemWarningData is only
// applied for v2 notifications on ChromeOS Lacros, not for the legacy
// ChromeOS notifications used on ChromeOS Ash and on Lacros pre-v2. Other
// platforms do not have desktop notifications for downloads.
// TODO(chlily): CLOSE should be logged as well but there is currently no
// way to tell when a download is dangerous on the Ash side, which handles
// the notification close.
DOWNLOAD_NOTIFICATION = 5,
kMaxValue = DOWNLOAD_NOTIFICATION
};
// Users action on the warning surface.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class WarningAction {
// The warning is shown. This is a special action that may not be triggered
// by user. We will use the first instance of this action as the anchor to
// track the latency of other actions.
SHOWN = 0,
// The user clicks proceed, which means the user decides to bypass the
// warning. This is a terminal action.
// Note that this corresponds to DownloadCommands::Command::KEEP, despite
// the confusing naming.
PROCEED = 1,
// The user clicks discard, which means the user decides to obey the
// warning and the dangerous download is deleted from disk.
DISCARD = 2,
// The user has clicked the keep button on the surface, which causes another
// surface (e.g. download prompt) to be displayed. This is not a terminal
// action.
KEEP = 3,
// The user has clicked the close button on the surface.
CLOSE = 4,
// The user clicks cancel on the download prompt.
CANCEL = 5,
// The user has dismissed the bubble by clicking anywhere outside
// the bubble.
DISMISS = 6,
// The user has clicked the back button on the bubble subpage to go back
// to the bubble main page.
BACK = 7,
// The user has opened the download bubble subpage.
OPEN_SUBPAGE = 8,
// The user clicks proceed on a prompt for deep scanning.
PROCEED_DEEP_SCAN = 9,
// The user clicks the learn more link on the bubble subpage.
OPEN_LEARN_MORE_LINK = 10,
// The user accepts starting a deep scan.
ACCEPT_DEEP_SCAN = 11,
kMaxValue = ACCEPT_DEEP_SCAN
};
struct WarningActionEvent {
WarningSurface surface;
WarningAction action;
// The latency between when the warning is shown for the first time and when
// this event has happened.
int64_t action_latency_msec;
// A terminal action means that the warning disappears after this event,
// the download is either deleted or saved.
bool is_terminal_action = false;
WarningActionEvent(WarningSurface surface,
WarningAction action,
int64_t action_latency_msec,
bool is_terminal_action);
// Serializes the surface, action, and action_latency_msec into a string
// in a colon-separated format such as "DOWNLOADS_PAGE:DISCARD:10000".
std::string ToString() const;
};
// Enum representing the trigger of the scan request.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// LINT.IfChange
enum class DeepScanTrigger {
// The trigger is unknown.
TRIGGER_UNKNOWN = 0,
// The trigger is the standard prompt in the download bubble,
// shown for Advanced Protection or Enhanced Protection users.
TRIGGER_CONSUMER_PROMPT = 1,
// The trigger is the enterprise policy.
TRIGGER_POLICY = 2,
// The trigger is the encrypted archive prompt in the download
// bubble, which requires the password as well as the file.
TRIGGER_ENCRYPTED_CONSUMER_PROMPT = 3,
// The trigger is automatic deep scanning, with no prompt, which
// applies only to Enhanced Protection users.
TRIGGER_IMMEDIATE_DEEP_SCAN = 4,
kMaxValue = TRIGGER_IMMEDIATE_DEEP_SCAN,
};
// LINT.ThenChange(/tools/metrics/histograms/metadata/sb_client/enums.xml)
~DownloadItemWarningData() override;
// Gets all warning actions associated with this `download`. Returns an
// empty vector if there's no warning data or there is no warning shown for
// this `download`.
static std::vector<WarningActionEvent> GetWarningActionEvents(
const download::DownloadItem* download);
// Adds an `action` triggered on `surface` for `download`. It may not be
// added if `download` is not dangerous, null or the length of events
// associated with this `download` exceeds the limit.
static void AddWarningActionEvent(download::DownloadItem* download,
WarningSurface surface,
WarningAction action);
// Returns whether the download was an encrypted archive at the
// top-level (i.e. the encryption was not within a nested archive).
static bool IsTopLevelEncryptedArchive(
const download::DownloadItem* download);
static void SetIsTopLevelEncryptedArchive(
download::DownloadItem* download,
bool is_top_level_encrypted_archive);
// Returns whether the user has entered an incorrect password for the
// archive.
static bool HasIncorrectPassword(const download::DownloadItem* download);
static void SetHasIncorrectPassword(download::DownloadItem* download,
bool has_incorrect_password);
// Converts an `event` to the Safe Browsing report proto format.
static safe_browsing::ClientSafeBrowsingReportRequest::DownloadWarningAction
ConstructCsbrrDownloadWarningAction(const WarningActionEvent& event);
// Returns whether we have shown a local password decryption prompt for this
// download.
static bool HasShownLocalDecryptionPrompt(
const download::DownloadItem* download);
static void SetHasShownLocalDecryptionPrompt(download::DownloadItem* download,
bool has_shown);
// Returns the reason we initiated deep scanning for the download.
static DeepScanTrigger DownloadDeepScanTrigger(
const download::DownloadItem* download);
static void SetDeepScanTrigger(download::DownloadItem* download,
DeepScanTrigger trigger);
// Returns whether an encrypted archive was fully extracted.
static bool IsFullyExtractedArchive(const download::DownloadItem* download);
static void SetIsFullyExtractedArchive(download::DownloadItem* download,
bool extracted);
// Time and surface of the first SHOWN event. Time will be null if SHOWN has
// not yet been logged. Surface will return nullopt if SHOWN has not yet been
// logged.
static base::Time WarningFirstShownTime(
const download::DownloadItem* download);
static std::optional<WarningSurface> WarningFirstShownSurface(
const download::DownloadItem* download);
private:
DownloadItemWarningData();
template <typename F, typename V>
static V GetWithDefault(const download::DownloadItem* download,
F&& f,
V&& default_value);
static DownloadItemWarningData* GetOrCreate(download::DownloadItem* download);
std::vector<WarningActionEvent> ActionEvents() const;
static const char kKey[];
base::Time warning_first_shown_time_;
std::optional<WarningSurface> warning_first_shown_surface_ = std::nullopt;
std::vector<WarningActionEvent> action_events_;
bool is_top_level_encrypted_archive_ = false;
bool has_incorrect_password_ = false;
bool has_shown_local_decryption_prompt_ = false;
bool fully_extracted_archive_ = false;
// Whether a "shown" event has been logged for the Downloads Page for this
// download. Not persisted across restarts.
bool logged_downloads_page_shown_ = false;
DeepScanTrigger deep_scan_trigger_ = DeepScanTrigger::TRIGGER_UNKNOWN;
};
#endif // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_ITEM_WARNING_DATA_H_
|