// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/common/permissions/api_permission_set.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/permissions/permissions_info.h"
namespace extensions {
namespace errors = manifest_errors;
namespace {
bool CreateAPIPermission(
const std::string& permission_str,
const base::Value* permission_value,
APIPermissionSet::ParseSource source,
APIPermissionSet* api_permissions,
string16* error,
std::vector<std::string>* unhandled_permissions) {
const APIPermissionInfo* permission_info =
PermissionsInfo::GetInstance()->GetByName(permission_str);
if (permission_info) {
scoped_ptr<APIPermission> permission(
permission_info->CreateAPIPermission());
if (source != APIPermissionSet::kAllowInternalPermissions &&
permission_info->is_internal()) {
// An internal permission specified in permissions list is an error.
if (error) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kPermissionNotAllowedInManifest, permission_str);
}
return false;
}
if (!permission->FromValue(permission_value)) {
if (error) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidPermission, permission_info->name());
return false;
}
LOG(WARNING) << "Parse permission failed.";
} else {
api_permissions->insert(permission.release());
}
return true;
}
if (unhandled_permissions)
unhandled_permissions->push_back(permission_str);
else
LOG(WARNING) << "Unknown permission[" << permission_str << "].";
return true;
}
bool ParseChildPermissions(const std::string& base_name,
const base::Value* permission_value,
APIPermissionSet::ParseSource source,
APIPermissionSet* api_permissions,
string16* error,
std::vector<std::string>* unhandled_permissions) {
if (permission_value) {
const base::ListValue* permissions;
if (!permission_value->GetAsList(&permissions)) {
if (error) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidPermission, base_name);
return false;
}
LOG(WARNING) << "Permission value is not a list.";
// Failed to parse, but since error is NULL, failures are not fatal so
// return true here anyway.
return true;
}
for (size_t i = 0; i < permissions->GetSize(); ++i) {
std::string permission_str;
if (!permissions->GetString(i, &permission_str)) {
// permission should be a string
if (error) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidPermission,
base_name + '.' + base::IntToString(i));
return false;
}
LOG(WARNING) << "Permission is not a string.";
continue;
}
if (!CreateAPIPermission(
base_name + '.' + permission_str, NULL, source,
api_permissions, error, unhandled_permissions))
return false;
}
}
return CreateAPIPermission(base_name, NULL, source,
api_permissions, error, NULL);
}
} // namespace
void APIPermissionSet::insert(APIPermission::ID id) {
const APIPermissionInfo* permission_info =
PermissionsInfo::GetInstance()->GetByID(id);
insert(permission_info->CreateAPIPermission());
}
void APIPermissionSet::insert(APIPermission* permission) {
BaseSetOperators<APIPermissionSet>::insert(permission);
}
// static
bool APIPermissionSet::ParseFromJSON(
const base::ListValue* permissions,
APIPermissionSet::ParseSource source,
APIPermissionSet* api_permissions,
string16* error,
std::vector<std::string>* unhandled_permissions) {
for (size_t i = 0; i < permissions->GetSize(); ++i) {
std::string permission_str;
const base::Value* permission_value = NULL;
if (!permissions->GetString(i, &permission_str)) {
const base::DictionaryValue* dict = NULL;
// permission should be a string or a single key dict.
if (!permissions->GetDictionary(i, &dict) || dict->size() != 1) {
if (error) {
*error = ErrorUtils::FormatErrorMessageUTF16(
errors::kInvalidPermission, base::IntToString(i));
return false;
}
LOG(WARNING) << "Permission is not a string or single key dict.";
continue;
}
base::DictionaryValue::Iterator it(*dict);
permission_str = it.key();
permission_value = &it.value();
}
// Check if this permission is a special case where its value should
// be treated as a list of child permissions.
if (PermissionsInfo::GetInstance()->HasChildPermissions(permission_str)) {
if (!ParseChildPermissions(permission_str, permission_value, source,
api_permissions, error, unhandled_permissions))
return false;
continue;
}
if (!CreateAPIPermission(permission_str, permission_value, source,
api_permissions, error, unhandled_permissions))
return false;
}
return true;
}
void APIPermissionSet::AddImpliedPermissions() {
// The fileSystem.write and fileSystem.directory permissions imply
// fileSystem.writeDirectory.
// TODO(sammc): Remove this. See http://crbug.com/284849.
if (ContainsKey(map(), APIPermission::kFileSystemWrite) &&
ContainsKey(map(), APIPermission::kFileSystemDirectory)) {
insert(APIPermission::kFileSystemWriteDirectory);
}
}
} // namespace extensions