blob: 9a8831e0e68292da5ba1c5f5a001fad5420278b5 [file] [log] [blame]
// 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 "components/enterprise/idle/idle_timeout_policy_handler.h"
#include <string>
#include "base/json/values_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/browsing_data/core/browsing_data_policies_utils.h"
#include "components/enterprise/idle/action_type.h"
#include "components/enterprise/idle/idle_pref_names.h"
#include "components/policy/core/browser/configuration_policy_handler.h"
#include "components/policy/core/browser/policy_error_map.h"
#include "components/policy/core/common/policy_logger.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/schema.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_value_map.h"
#include "components/strings/grit/components_strings.h"
namespace enterprise_idle {
namespace {
// If `other_policy_name` is unset, adds an error to `errors` and returns false.
bool CheckOtherPolicySet(const policy::PolicyMap& policies,
const std::string& this_policy_name,
const std::string& other_policy_name,
policy::PolicyErrorMap* errors) {
if (policies.GetValueUnsafe(other_policy_name)) {
return true;
}
errors->AddError(this_policy_name, IDS_POLICY_DEPENDENCY_ERROR_ANY_VALUE,
other_policy_name);
return false;
}
bool CheckPolicyScopeSupported(const policy::PolicyMap& policies,
const std::string& policy_name,
policy::PolicyErrorMap* errors) {
// The policies will not be supported as user policies on iOS until we clear
// data on sign out for managed users which requires new UI.
#if BUILDFLAG(IS_IOS)
bool is_user_policy =
policies.Get(policy_name)->scope == policy::POLICY_SCOPE_USER;
if (is_user_policy) {
errors->AddError(policy_name,
IDS_POLICY_NOT_SUPPORTED_AS_USER_POLICY_ON_IOS);
}
return !is_user_policy;
#else
// Return true on all other platforms.
return true;
#endif // BUILDFLAG(IS_IOS)
}
} // namespace
IdleTimeoutPolicyHandler::IdleTimeoutPolicyHandler()
: policy::IntRangePolicyHandler(policy::key::kIdleTimeout,
prefs::kIdleTimeout,
1,
INT_MAX,
true) {}
IdleTimeoutPolicyHandler::~IdleTimeoutPolicyHandler() = default;
void IdleTimeoutPolicyHandler::ApplyPolicySettings(
const policy::PolicyMap& policies,
PrefValueMap* prefs) {
const base::Value* value =
policies.GetValue(policy_name(), base::Value::Type::INTEGER);
DCHECK(value);
// Apply a minimum of 1.
base::TimeDelta time_delta = base::Minutes(std::max(value->GetInt(), 1));
prefs->SetValue(prefs::kIdleTimeout, base::TimeDeltaToValue(time_delta));
}
bool IdleTimeoutPolicyHandler::CheckPolicySettings(
const policy::PolicyMap& policies,
policy::PolicyErrorMap* errors) {
// Nothing to do if unset.
if (!policies.GetValueUnsafe(policy_name())) {
return false;
}
// Check that it's an integer, and that it's >= 1.
if (!policy::IntRangePolicyHandler::CheckPolicySettings(policies, errors)) {
return false;
}
// If IdleTimeoutActions is unset, add an error and do nothing.
if (!CheckOtherPolicySet(policies, policy_name(),
policy::key::kIdleTimeoutActions, errors)) {
return false;
}
if (!CheckPolicyScopeSupported(policies, policy_name(), errors)) {
return false;
}
return true;
}
IdleTimeoutActionsPolicyHandler::IdleTimeoutActionsPolicyHandler(
policy::Schema schema)
: policy::SchemaValidatingPolicyHandler(
policy::key::kIdleTimeoutActions,
schema.GetKnownProperty(policy::key::kIdleTimeoutActions),
policy::SCHEMA_ALLOW_UNKNOWN_AND_INVALID_LIST_ENTRY) {}
IdleTimeoutActionsPolicyHandler::~IdleTimeoutActionsPolicyHandler() = default;
void IdleTimeoutActionsPolicyHandler::ApplyPolicySettings(
const policy::PolicyMap& policies,
PrefValueMap* prefs) {
const base::Value* policy_value =
policies.GetValue(policy_name(), base::Value::Type::LIST);
DCHECK(policy_value);
// Convert strings to integers (from the ActionType enum).
base::Value::List converted_actions;
for (const base::Value& action : policy_value->GetList()) {
if (!action.is_string()) {
continue;
}
if (std::optional<ActionType> action_type =
NameToActionType(action.GetString())) {
converted_actions.Append(static_cast<int>(action_type.value()));
}
}
prefs->SetValue(prefs::kIdleTimeoutActions,
base::Value(std::move(converted_actions)));
std::string log_message = browsing_data::DisableSyncTypes(
forced_disabled_sync_types_, prefs, policy_name());
if (!log_message.empty()) {
LOG_POLICY(INFO, POLICY_PROCESSING) << log_message;
}
#if BUILDFLAG(IS_IOS)
// Set the `kIdleTimeoutPolicyAppliesToUserOnly`pref if the policy is set as a
// user policy. This will determine whether data should be cleared for
// `TimePeriod::ALL_TIME` or only for the time the user was signed in.
bool user_policy =
policies.Get(policy_name())->scope == policy::POLICY_SCOPE_USER;
prefs->SetBoolean(prefs::kIdleTimeoutPolicyAppliesToUserOnly, user_policy);
#endif // BUILDFLAG(IS_IOS)
}
bool IdleTimeoutActionsPolicyHandler::CheckPolicySettings(
const policy::PolicyMap& policies,
policy::PolicyErrorMap* errors) {
// Nothing to do if unset.
if (!policies.GetValueUnsafe(policy_name())) {
return false;
}
// Check that it's a list of strings, and that they're supported enum values.
// Unsupported enum values are dropped, with a warning on chrome://policy.
if (!policy::SchemaValidatingPolicyHandler::CheckPolicySettings(policies,
errors)) {
return false;
}
// If IdleTimeout is unset, add an error and do nothing.
if (!CheckOtherPolicySet(policies, policy_name(), policy::key::kIdleTimeout,
errors)) {
return false;
}
if (!CheckPolicyScopeSupported(policies, policy_name(), errors)) {
return false;
}
#if !BUILDFLAG(IS_ANDROID)
const base::Value* sync_disabled =
policies.GetValue(policy::key::kSyncDisabled, base::Value::Type::BOOLEAN);
if (sync_disabled && sync_disabled->GetBool()) {
return true;
}
#endif //! BUILDFLAG(IS_ANDROID)
// BrowserSignin policy is not available on ChromeOS.
#if !BUILDFLAG(IS_CHROMEOS)
const auto* browser_signin_disabled = policies.GetValue(
policy::key::kBrowserSignin, base::Value::Type::INTEGER);
if (browser_signin_disabled && browser_signin_disabled->GetInt() == 0) {
return true;
}
#endif
// Automatically disable sync for the required data types.
const base::Value* value =
policies.GetValue(this->policy_name(), base::Value::Type::LIST);
DCHECK(value);
base::Value::List clear_data_actions;
for (const base::Value& action : value->GetList()) {
if (!action.is_string()) {
continue;
}
std::string clear_data_action =
GetActionBrowsingDataTypeName(action.GetString());
if (!clear_data_action.empty()) {
clear_data_actions.Append(clear_data_action);
}
}
forced_disabled_sync_types_ = browsing_data::GetSyncTypesForClearBrowsingData(
base::Value(std::move(clear_data_actions)));
return true;
}
// TODO(esalma): Move this logic to `ApplyPolicySettings()` after fixing
// crbug.com/1435069.
void IdleTimeoutActionsPolicyHandler::PrepareForDisplaying(
policy::PolicyMap* policies) const {
policy::PolicyMap::Entry* entry = policies->GetMutable(policy_name());
if (!entry || forced_disabled_sync_types_.empty()) {
return;
}
// `PolicyConversionsClient::GetPolicyValue()` doesn't support
// MessageType::kInfo in the PolicyErrorMap, so add the message to the policy
// when it is prepared to be displayed on chrome://policy.
entry->AddMessage(policy::PolicyMap::MessageType::kInfo,
IDS_POLICY_BROWSING_DATA_DEPENDENCY_APPLIED_INFO,
{base::UTF8ToUTF16(UserSelectableTypeSetToString(
forced_disabled_sync_types_))});
}
} // namespace enterprise_idle