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 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
|
// Copyright 2019 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/child_accounts/time_limits/app_time_policy_helpers.h"
#include <utility>
#include "base/logging.h"
#include "base/notreached.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/ash/child_accounts/time_limits/app_types.h"
namespace ash {
namespace app_time {
namespace policy {
const char kUrlList[] = "url_list";
const char kAppList[] = "app_list";
const char kAppId[] = "app_id";
const char kAppType[] = "app_type";
const char kAppLimitsArray[] = "app_limits";
const char kAppInfoDict[] = "app_info";
const char kRestrictionEnum[] = "restriction";
const char kDailyLimitInt[] = "daily_limit_mins";
const char kLastUpdatedString[] = "last_updated_millis";
const char kResetAtDict[] = "reset_at";
const char kHourInt[] = "hour";
const char kMinInt[] = "minute";
const char kActivityReportingEnabled[] = "activity_reporting_enabled";
apps::AppType PolicyStringToAppType(const std::string& app_type) {
if (app_type == "ARC")
return apps::AppType::kArc;
if (app_type == "BOREALIS")
return apps::AppType::kBorealis;
// After the splitting of kChromeApp from the kExtension type in which
// the original kExtension was renamed to kChromeApp (crrev.com/c/3314469),
// the subsequent kExtension type refers to Chrome browser extensions only.
// The legacy kChromeApp policy string remains unchanged.
if (app_type == "BROWSER-EXTENSION")
return apps::AppType::kExtension;
if (app_type == "BRUSCHETTA")
return apps::AppType::kBruschetta;
if (app_type == "CROSTINI")
return apps::AppType::kCrostini;
if (app_type == "EXTENSION")
return apps::AppType::kChromeApp;
if (app_type == "PLUGIN-VM")
return apps::AppType::kPluginVm;
if (app_type == "REMOTE")
return apps::AppType::kRemote;
if (app_type == "SYSTEM-WEB")
return apps::AppType::kSystemWeb;
if (app_type == "WEB")
return apps::AppType::kWeb;
// TODO(crbug.com/373972275): remove LACROS-BROWSER, BUILT-IN,
// LACROS-CHROME-APP and LACROS-EXTENSION once it's guaranteed that old
// LACROS-CHROME-APP and LACROS-EXTENSION entries got purged as it looks like
// they come from disk (PerfService).
if (app_type == "UNKNOWN" || app_type == "BUILT-IN" ||
app_type == "LACROS-EXTENSION" || app_type == "LACROS-CHROME-APP" ||
app_type == "LACROS-BROWSER") {
return apps::AppType::kUnknown;
}
NOTREACHED();
}
std::string AppTypeToPolicyString(apps::AppType app_type) {
switch (app_type) {
case apps::AppType::kArc:
return "ARC";
case apps::AppType::kBorealis:
return "BOREALIS";
case apps::AppType::kExtension:
return "BROWSER-EXTENSION";
case apps::AppType::kBruschetta:
return "BRUSCHETTA";
case apps::AppType::kCrostini:
return "CROSTINI";
case apps::AppType::kChromeApp:
return "EXTENSION";
case apps::AppType::kPluginVm:
return "PLUGIN-VM";
case apps::AppType::kRemote:
return "REMOTE";
case apps::AppType::kSystemWeb:
return "SYSTEM-WEB";
case apps::AppType::kWeb:
return "WEB";
case apps::AppType::kUnknown:
return "UNKNOWN";
}
NOTREACHED();
}
AppRestriction PolicyStringToAppRestriction(const std::string& restriction) {
if (restriction == "BLOCK")
return AppRestriction::kBlocked;
if (restriction == "TIME_LIMIT")
return AppRestriction::kTimeLimit;
NOTREACHED();
}
std::string AppRestrictionToPolicyString(const AppRestriction& restriction) {
switch (restriction) {
case AppRestriction::kBlocked:
return "BLOCK";
case AppRestriction::kTimeLimit:
return "TIME_LIMIT";
default:
NOTREACHED();
}
}
std::optional<AppId> AppIdFromDict(const base::Value::Dict* dict) {
if (!dict) {
return std::nullopt;
}
const std::string* id = dict->FindString(kAppId);
if (!id || id->empty()) {
DLOG(ERROR) << "Invalid id.";
return std::nullopt;
}
const std::string* type_string = dict->FindString(kAppType);
if (!type_string || type_string->empty()) {
DLOG(ERROR) << "Invalid type.";
return std::nullopt;
}
return AppId(PolicyStringToAppType(*type_string), *id);
}
base::Value::Dict AppIdToDict(const AppId& app_id) {
base::Value::Dict dict;
dict.Set(kAppId, base::Value(app_id.app_id()));
dict.Set(kAppType, base::Value(AppTypeToPolicyString(app_id.app_type())));
return dict;
}
std::optional<AppId> AppIdFromAppInfoDict(const base::Value::Dict* dict) {
if (!dict) {
return std::nullopt;
}
const base::Value::Dict* app_info = dict->FindDict(kAppInfoDict);
if (!app_info) {
DLOG(ERROR) << "Invalid app info dictionary.";
return std::nullopt;
}
return AppIdFromDict(app_info);
}
std::optional<AppLimit> AppLimitFromDict(const base::Value::Dict& dict) {
const std::string* restriction_string = dict.FindString(kRestrictionEnum);
if (!restriction_string || restriction_string->empty()) {
DLOG(ERROR) << "Invalid restriction.";
return std::nullopt;
}
const AppRestriction restriction =
PolicyStringToAppRestriction(*restriction_string);
std::optional<int> daily_limit_mins = dict.FindInt(kDailyLimitInt);
if ((restriction == AppRestriction::kTimeLimit && !daily_limit_mins) ||
(restriction == AppRestriction::kBlocked && daily_limit_mins)) {
DLOG(ERROR) << "Invalid restriction.";
return std::nullopt;
}
std::optional<base::TimeDelta> daily_limit;
if (daily_limit_mins) {
daily_limit = base::Minutes(*daily_limit_mins);
if (daily_limit &&
(*daily_limit < base::Hours(0) || *daily_limit > base::Hours(24))) {
DLOG(ERROR) << "Invalid daily limit.";
return std::nullopt;
}
}
const std::string* last_updated_string = dict.FindString(kLastUpdatedString);
int64_t last_updated_millis;
if (!last_updated_string || last_updated_string->empty() ||
!base::StringToInt64(*last_updated_string, &last_updated_millis)) {
DLOG(ERROR) << "Invalid last updated time.";
return std::nullopt;
}
const base::Time last_updated =
base::Time::UnixEpoch() + base::Milliseconds(last_updated_millis);
return AppLimit(restriction, daily_limit, last_updated);
}
base::Value::Dict AppLimitToDict(const AppLimit& limit) {
base::Value::Dict dict;
dict.Set(kRestrictionEnum,
base::Value(AppRestrictionToPolicyString(limit.restriction())));
if (limit.daily_limit())
dict.Set(kDailyLimitInt, base::Value(limit.daily_limit()->InMinutes()));
const std::string last_updated_string = base::NumberToString(
(limit.last_updated() - base::Time::UnixEpoch()).InMilliseconds());
dict.Set(kLastUpdatedString, base::Value(last_updated_string));
return dict;
}
std::optional<base::TimeDelta> ResetTimeFromDict(
const base::Value::Dict& dict) {
const base::Value* reset_dict = dict.Find(kResetAtDict);
if (!reset_dict || !reset_dict->is_dict()) {
DLOG(ERROR) << "Invalid reset time dictionary.";
return std::nullopt;
}
std::optional<int> hour = reset_dict->GetDict().FindInt(kHourInt);
if (!hour) {
DLOG(ERROR) << "Invalid reset hour.";
return std::nullopt;
}
std::optional<int> minutes = reset_dict->GetDict().FindInt(kMinInt);
if (!minutes) {
DLOG(ERROR) << "Invalid reset minutes.";
return std::nullopt;
}
const int hour_in_mins = base::Hours(1).InMinutes();
return base::Minutes(hour.value() * hour_in_mins + minutes.value());
}
base::Value::Dict ResetTimeToDict(int hour, int minutes) {
base::Value::Dict dict;
dict.Set(kHourInt, base::Value(hour));
dict.Set(kMinInt, base::Value(minutes));
return dict;
}
std::optional<bool> ActivityReportingEnabledFromDict(
const base::Value::Dict& dict) {
return dict.FindBool(kActivityReportingEnabled);
}
std::map<AppId, AppLimit> AppLimitsFromDict(const base::Value::Dict& dict) {
std::map<AppId, AppLimit> app_limits;
const base::Value::List* limits_array = dict.FindList(kAppLimitsArray);
if (!limits_array) {
DLOG(ERROR) << "Invalid app limits list.";
return app_limits;
}
for (const base::Value& app_limits_dict : *limits_array) {
if (!app_limits_dict.is_dict()) {
DLOG(ERROR) << "Invalid app limits entry. ";
continue;
}
std::optional<AppId> app_id =
AppIdFromAppInfoDict(&app_limits_dict.GetDict());
if (!app_id) {
DLOG(ERROR) << "Invalid app id.";
continue;
}
std::optional<AppLimit> app_limit =
AppLimitFromDict(app_limits_dict.GetDict());
if (!app_limit) {
DLOG(ERROR) << "Invalid app limit.";
continue;
}
app_limits.emplace(*app_id, *app_limit);
}
return app_limits;
}
} // namespace policy
} // namespace app_time
} // namespace ash
|