// Copyright 2021 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_CHROMEOS_POLICY_DLP_DLP_CONFIDENTIAL_CONTENTS_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONFIDENTIAL_CONTENTS_H_
#include <list>
#include <string>
#include <vector>
#include "base/containers/flat_set.h"
#include "base/ranges/algorithm.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_rules_manager.h"
#include "ui/gfx/image/image_skia.h"
#include "url/gurl.h"
namespace aura {
class Window;
} // namespace aura
namespace content {
class WebContents;
} // namespace content
namespace policy {
// Keeps track of title and corresponding icon of a WebContents object.
// Used to cache and later show information about observed confidential contents
// to the user.
struct DlpConfidentialContent {
DlpConfidentialContent() = delete;
// Constructs DlpConfidentialContent from the title and icon obtained from
// |web_contents|, which cannot be null.
explicit DlpConfidentialContent(content::WebContents* web_contents);
// Constructs DlpConfidentialContent from the title and icon obtained from
// |window|, which cannot be null and |url|.
DlpConfidentialContent(aura::Window* window, const GURL& url);
DlpConfidentialContent(const DlpConfidentialContent& other);
DlpConfidentialContent& operator=(const DlpConfidentialContent& other);
~DlpConfidentialContent() = default;
// Contents with the same url are considered equal, ignoring the ref (part
// after #).
bool operator==(const DlpConfidentialContent& other) const;
bool operator!=(const DlpConfidentialContent& other) const;
bool operator<(const DlpConfidentialContent& other) const;
bool operator<=(const DlpConfidentialContent& other) const;
bool operator>(const DlpConfidentialContent& other) const;
bool operator>=(const DlpConfidentialContent& other) const;
gfx::ImageSkia icon;
std::u16string title;
GURL url;
};
// Provides basic functions for storing and working with DLP confidential
// contents.
class DlpConfidentialContents {
public:
DlpConfidentialContents();
explicit DlpConfidentialContents(
const std::vector<content::WebContents*>& web_contents);
DlpConfidentialContents(const DlpConfidentialContents& other);
DlpConfidentialContents& operator=(const DlpConfidentialContents& other);
~DlpConfidentialContents();
friend bool operator==(const DlpConfidentialContents& a,
const DlpConfidentialContents& b) {
return a.contents_ == b.contents_;
}
friend bool operator!=(const DlpConfidentialContents& a,
const DlpConfidentialContents& b) {
return !(a == b);
}
// Returns true if all the elements in |a| and |b| are equal (i.e. have the
// same url) and the same title, and false otherwise. Useful to detect changes
// in titles, even if the set of the confidential contents hasn't changed.
friend bool EqualWithTitles(const DlpConfidentialContents& a,
const DlpConfidentialContents& b) {
return base::ranges::equal(
a.contents_, b.contents_,
[](const DlpConfidentialContent& x, const DlpConfidentialContent& y) {
return x == y && x.title == y.title;
});
}
// Returns a reference to the underlying content container.
base::flat_set<DlpConfidentialContent>& GetContents();
// Returns a const reference to the underlying content container.
const base::flat_set<DlpConfidentialContent>& GetContents() const;
// Converts |web_contents| to a DlpConfidentialContent and adds it to the
// underlying container.
void Add(content::WebContents* web_contents);
// Same for |window| and |url| pair.
void Add(aura::Window* window, const GURL& url);
// Removes all stored confidential content, if there was any, and adds
// |web_contents| converted to a DlpConfidentialContent.
void ClearAndAdd(content::WebContents* web_contents);
// Same for |window| and |url| pair.
void ClearAndAdd(aura::Window* web_contents, const GURL& url);
// Returns whether there is any content stored or not.
bool IsEmpty() const;
// Adds all content stored in |other| to the underlying container, without
// duplicates.
void InsertOrUpdate(const DlpConfidentialContents& other);
private:
base::flat_set<DlpConfidentialContent> contents_;
};
// Used to avoid warning the user for an action and content that they already
// acknowledged and bypassed a warning for, by caching these contents for a
// certain amount of time.
//
// Automatically evicts entries after a timeout.
// If the number of cached entries exceeds a predefined limits, evicts the
// oldest entry from the cache.
class DlpConfidentialContentsCache {
public:
DlpConfidentialContentsCache();
DlpConfidentialContentsCache(const DlpConfidentialContentsCache& other) =
delete;
DlpConfidentialContentsCache& operator=(
const DlpConfidentialContentsCache& other) = delete;
~DlpConfidentialContentsCache();
// Creates and stores an entry from |web_contents| and |restriction|.
void Cache(const DlpConfidentialContent& content,
DlpRulesManager::Restriction restriction);
// Returns true if there is a cached entry corresponding to |web_contents| and
// |restriction|.
// Useful to avoid converting |web_contents| to a DlpConfidentialContent
// unnecessarily.
bool Contains(content::WebContents* web_contents,
DlpRulesManager::Restriction restriction) const;
// Returns true if there is a cached entry corresponding to |content| and
// |restriction|.
bool Contains(const DlpConfidentialContent& content,
DlpRulesManager::Restriction restriction) const;
// Returns the number of cached entries, useful for testing.
size_t GetSizeForTesting() const;
// Returns the duration for which the entries are kept in the cache.
static base::TimeDelta GetCacheTimeout();
// Used only in tests to inject a task runner for time control.
void SetTaskRunnerForTesting(
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
private:
struct Entry {
Entry() = delete;
Entry(const DlpConfidentialContent& content,
DlpRulesManager::Restriction restriction,
base::TimeTicks timestamp);
Entry(const Entry& other) = delete;
Entry& operator=(const Entry& other) = delete;
~Entry();
DlpConfidentialContent content;
DlpRulesManager::Restriction restriction;
base::TimeTicks created_at;
base::OneShotTimer eviction_timer;
};
// Starts the |entry|'s eviction timer.
void StartEvictionTimer(Entry* entry);
// Evicts an entry corresponding to |content| if it exists, no-op otherwise.
void OnEvictionTimerUp(const DlpConfidentialContent& content);
std::list<std::unique_ptr<Entry>> entries_;
const size_t cache_size_limit_;
// Used to evict cache entries after the timeout.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
};
} // namespace policy
#endif // CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONFIDENTIAL_CONTENTS_H_