chromium/chrome/browser/ash/policy/dlp/dlp_files_event_storage.h

// 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_ASH_POLICY_DLP_DLP_FILES_EVENT_STORAGE_H_
#define CHROME_BROWSER_ASH_POLICY_DLP_DLP_FILES_EVENT_STORAGE_H_

#include <sys/types.h>
#include <map>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_file_destination.h"

namespace policy {

// Stores file events and filters most non-user-initiated duplicate events.
class DlpFilesEventStorage {
 public:
  // File are identified by a pair of inode number and crtime
  // (creation time).
  typedef std::pair<ino64_t, time_t> FileId;

  DlpFilesEventStorage(base::TimeDelta cooldown_timeout, size_t entries_limit);
  DlpFilesEventStorage(const DlpFilesEventStorage& other) = delete;
  DlpFilesEventStorage(DlpFilesEventStorage&& other) = delete;
  ~DlpFilesEventStorage();

  // Upserts an event entry into `events_` and returns true if
  // enough time has passed from a previous call to
  // `StoreEventAndCheckIfItShouldBeReported` with the same `file_id` and `dst`.
  // When `dst` has `dst.component` equal to
  // `DlpRulesManager::Component::kUnknownComponent` and `dst.url_or_path` not
  // set, `StoreEventAndCheckIfItShouldBeReported` returns true only if no other
  // recent previous call has been performed with the same `file_id` and any
  // `dst`. Finally, it returns false also when the current number of entries
  // in `events_` is `entries_limit_`.
  bool StoreEventAndCheckIfItShouldBeReported(FileId file_id,
                                              const DlpFileDestination& dst);

  // Returns the time during which an event is filtered if an exactly similar
  // one has been already received.
  base::TimeDelta GetDeduplicationCooldownForTesting() const;

  // Returns the number of events that are no more than `cooldown_delta_` old.
  size_t GetSizeForTesting() const;

  // Used in tests to inject a task runner for time control.
  void SetTaskRunnerForTesting(
      scoped_refptr<base::SingleThreadTaskRunner> task_runner);

 private:
  // Contains the information stored for every (file_id, destination) entry in
  // `events_`.
  struct EventEntry {
    explicit EventEntry(base::TimeTicks timestamp);
    ~EventEntry();
    // When the associated entry pair was upserted.
    base::TimeTicks timestamp;
    // Used to evict the entry when expired.
    base::OneShotTimer eviction_timer;
  };

  using DestinationsMap = std::map<DlpFileDestination, EventEntry>;
  using EventsMap = base::flat_map<FileId, DestinationsMap>;

  // Adds a new destination for an existing file_id.
  void AddDestinationToFile(EventsMap::iterator file_it,
                            FileId file_id,
                            const DlpFileDestination& dst,
                            const base::TimeTicks timestamp);

  // Inserts a new (file_id, destination) pair.
  void InsertNewFileAndDestinationPair(FileId file_id,
                                       const DlpFileDestination& dst,
                                       const base::TimeTicks timestamp);

  // Updates an existing (file_id, destination) pair.
  void UpdateFileAndDestinationPair(DestinationsMap::iterator dst_it,
                                    const base::TimeTicks timestamp);

  // Starts the eviction timer for an (file_id, destination) pair. When the
  // timer runs out of time, it calls `OnEvictionTimerUp`.
  void StartEvictionTimer(FileId file_id,
                          const DlpFileDestination& dst,
                          EventEntry& event_value);

  // Removes the given (file_id, destination) pair from `events_`.
  void OnEvictionTimerUp(FileId file_id, DlpFileDestination dst);

  EventsMap events_;

  const base::TimeDelta cooldown_delta_;

  // Used to evict entries when expired.
  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  size_t entries_num_ = 0;
  const size_t entries_num_limit_;
};

}  // namespace policy

#endif  // CHROME_BROWSER_ASH_POLICY_DLP_DLP_FILES_EVENT_STORAGE_H_