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
|
// 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.
#include "chrome/browser/ash/policy/dlp/dlp_files_event_storage.h"
#include "base/containers/flat_map.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
#include "components/enterprise/data_controls/core/browser/dlp_histogram_helper.h"
namespace policy {
DlpFilesEventStorage::DlpFilesEventStorage(base::TimeDelta cooldown_timeout,
size_t entries_num_limit)
: cooldown_delta_(cooldown_timeout),
task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
entries_num_limit_(entries_num_limit) {}
DlpFilesEventStorage::~DlpFilesEventStorage() = default;
DlpFilesEventStorage::EventEntry::EventEntry(base::TimeTicks timestamp)
: timestamp(timestamp) {}
DlpFilesEventStorage::EventEntry::~EventEntry() = default;
bool DlpFilesEventStorage::StoreEventAndCheckIfItShouldBeReported(
FileId file_id,
const DlpFileDestination& dst) {
if (entries_num_ == entries_num_limit_) {
// If we end up here we probably have already spammed the server with a lot
// of events, better to stop for a while.
return false;
}
const base::TimeTicks now = base::TimeTicks::Now();
const auto file_it = events_.find(file_id);
if (file_it == events_.end()) { // Check for new (file_id, dst) pair
InsertNewFileAndDestinationPair(file_id, dst, now);
return true;
}
auto dst_it = file_it->second.find(dst);
if (dst_it == file_it->second.end()) { // Check for new dst for this file_id
AddDestinationToFile(file_it, file_id, dst, now);
// Skip reporting if we don't know the destination (i.e., it is
// kUnknownComponent) and at least an entry for `file_id` is stored in
// `events_`.
return (dst.component().has_value() &&
dst.component().value() !=
data_controls::Component::kUnknownComponent) ||
dst.url().has_value();
}
// Found existing (file_id, dst) pair, update it
UpdateFileAndDestinationPair(dst_it, now);
const auto time_diff = now - dst_it->second.timestamp;
// Record the time difference between two identical file events.
base::UmaHistogramTimes(data_controls::GetDlpHistogramPrefix() +
data_controls::dlp::kSameFileEventTimeDiffUMA,
time_diff);
// Report only if enough time has passed.
return time_diff > cooldown_delta_;
}
base::TimeDelta DlpFilesEventStorage::GetDeduplicationCooldownForTesting()
const {
return cooldown_delta_;
}
std::size_t DlpFilesEventStorage::GetSizeForTesting() const {
return entries_num_;
}
void DlpFilesEventStorage::SetTaskRunnerForTesting(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
task_runner_ = task_runner;
}
void DlpFilesEventStorage::AddDestinationToFile(
EventsMap::iterator file_it,
FileId file_id,
const DlpFileDestination& dst,
const base::TimeTicks timestamp) {
const auto [it, _] = file_it->second.emplace(dst, timestamp);
StartEvictionTimer(file_id, dst, it->second);
entries_num_++;
data_controls::DlpCountHistogram(data_controls::dlp::kActiveFileEventsCount,
entries_num_, entries_num_limit_);
}
void DlpFilesEventStorage::InsertNewFileAndDestinationPair(
FileId file_id,
const DlpFileDestination& dst,
const base::TimeTicks timestamp) {
const auto [file_it, _] =
events_.emplace(file_id, std::map<DlpFileDestination, EventEntry>());
const auto [dst_it, __] = file_it->second.emplace(dst, timestamp);
StartEvictionTimer(file_id, dst, dst_it->second);
entries_num_++;
data_controls::DlpCountHistogram(data_controls::dlp::kActiveFileEventsCount,
entries_num_, entries_num_limit_);
}
void DlpFilesEventStorage::UpdateFileAndDestinationPair(
DestinationsMap::iterator dst_it,
const base::TimeTicks timestamp) {
dst_it->second.timestamp = timestamp;
DCHECK(dst_it->second.eviction_timer.IsRunning());
dst_it->second.eviction_timer.Reset();
data_controls::DlpCountHistogram(data_controls::dlp::kActiveFileEventsCount,
entries_num_, entries_num_limit_);
}
void DlpFilesEventStorage::StartEvictionTimer(FileId file_id,
const DlpFileDestination& dst,
EventEntry& event_value) {
event_value.eviction_timer.SetTaskRunner(task_runner_);
event_value.eviction_timer.Start(
FROM_HERE, cooldown_delta_,
base::BindOnce(&DlpFilesEventStorage::OnEvictionTimerUp,
base::Unretained(this), file_id, dst));
}
void DlpFilesEventStorage::OnEvictionTimerUp(FileId file_id,
DlpFileDestination dst) {
auto event_it = events_.find(file_id);
DCHECK(event_it != events_.end());
DCHECK(event_it->second.count(dst));
event_it->second.erase(std::move(dst));
if (event_it->second.empty()) {
events_.erase(event_it);
}
--entries_num_;
}
} // namespace policy
|