blob: 70e905cdb7e1ad1717c58d3d6458709c86d01d91 [file] [log] [blame]
// 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.
#include "components/enterprise/content/clipboard_restriction_service.h"
#include "components/enterprise/content/pref_names.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/policy/core/common/policy_pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/strings/grit/components_strings.h"
#include "components/url_matcher/url_util.h"
#include "components/user_prefs/user_prefs.h"
#include "content/public/browser/browser_context.h"
#include "ui/base/l10n/l10n_util.h"
ClipboardRestrictionService::ClipboardRestrictionService(
PrefService* pref_service)
: pref_service_(pref_service),
next_id_(0),
enable_url_matcher_(nullptr),
disable_url_matcher_(nullptr) {
pref_change_registrar_.Init(pref_service_);
pref_change_registrar_.Add(
enterprise::content::kCopyPreventionSettings,
base::BindRepeating(&ClipboardRestrictionService::UpdateSettings,
base::Unretained(this)));
UpdateSettings();
}
ClipboardRestrictionService::~ClipboardRestrictionService() = default;
bool ClipboardRestrictionService::IsUrlAllowedToCopy(
const GURL& url,
size_t data_size_in_bytes,
std::u16string* replacement_data) const {
if (!enable_url_matcher_ || !disable_url_matcher_)
return true;
if (data_size_in_bytes < min_data_size_)
return true;
// The copy is allowed in the following scenarios:
// 1. The URL doesn't match a pattern in the enable list
// or
// 2. The URL matches a pattern in the enable list but also matches a pattern
// in the disable list
// Conversely, it is blocked iff it matches a pattern in the enable list and
// doesn't match a pattern in the disable list.
bool is_allowed = enable_url_matcher_->MatchURL(url).empty() ||
disable_url_matcher_->MatchURL(url).size() > 0;
if (!is_allowed && replacement_data) {
*replacement_data = l10n_util::GetStringUTF16(
IDS_ENTERPRISE_COPY_PREVENTION_WARNING_MESSAGE);
}
return is_allowed;
}
void ClipboardRestrictionService::UpdateSettings() {
// This is infrequent enough that this code can teardown the url matcher
// entirely and rebuild it. There's also no state that should be carried over
// from the previous values, so doing it this way makes that semantic clearer.
enable_url_matcher_ = nullptr;
disable_url_matcher_ = nullptr;
if (!pref_service_->IsManagedPreference(
enterprise::content::kCopyPreventionSettings)) {
return;
}
const base::Value::Dict& settings =
pref_service_->GetDict(enterprise::content::kCopyPreventionSettings);
const base::Value::List* enable = settings.FindList(
enterprise::content::kCopyPreventionSettingsEnableFieldName);
const base::Value::List* disable = settings.FindList(
enterprise::content::kCopyPreventionSettingsDisableFieldName);
DCHECK(enable);
DCHECK(disable);
enable_url_matcher_ = std::make_unique<url_matcher::URLMatcher>();
disable_url_matcher_ = std::make_unique<url_matcher::URLMatcher>();
// For the following 2 calls, the second param is a bool called `allow`. In
// this context, we're not concerned about a URL being "allowed" or not, but
// rather with this prevention feature being enabled on a given URL. Because
// of this, pass `true` for patterns in the `enable` list and false for
// patterns in the `disable` list. If the URL Matcher subsequently matches a
// URL as "allowed", it means the prevention feature is active for that URL
// and the copy will be blocked. While confusing, this is mostly to map to the
// same policy format as the content analysis connector, which also has
// "enable" and "disable" lists used in this way.
url_matcher::util::AddFilters(enable_url_matcher_.get(), true, &next_id_,
*enable);
url_matcher::util::AddFilters(disable_url_matcher_.get(), false, &next_id_,
*disable);
absl::optional<int> min_data_size = settings.FindInt(
enterprise::content::kCopyPreventionSettingsMinDataSizeFieldName);
DCHECK(min_data_size);
DCHECK(min_data_size >= 0);
min_data_size_ = *min_data_size;
}
// static
ClipboardRestrictionServiceFactory*
ClipboardRestrictionServiceFactory::GetInstance() {
return base::Singleton<ClipboardRestrictionServiceFactory>::get();
}
// static
ClipboardRestrictionService*
ClipboardRestrictionServiceFactory::GetForBrowserContext(
content::BrowserContext* context) {
return static_cast<ClipboardRestrictionService*>(
GetInstance()->GetServiceForBrowserContext(context, true));
}
ClipboardRestrictionServiceFactory::ClipboardRestrictionServiceFactory()
: BrowserContextKeyedServiceFactory(
"PolicyClipboardRestriction",
BrowserContextDependencyManager::GetInstance()) {}
ClipboardRestrictionServiceFactory::~ClipboardRestrictionServiceFactory() =
default;
content::BrowserContext*
ClipboardRestrictionServiceFactory::GetBrowserContextToUse(
content::BrowserContext* context) const {
return context;
}
KeyedService* ClipboardRestrictionServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new ClipboardRestrictionService(user_prefs::UserPrefs::Get(context));
}