1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "extensions/common/permissions/api_permission_set.h"
6
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/values.h"
11 #include "extensions/common/error_utils.h"
12 #include "extensions/common/manifest_constants.h"
13 #include "extensions/common/permissions/permissions_info.h"
14
15 namespace extensions {
16
17 namespace errors = manifest_errors;
18
19 namespace {
20
CreateAPIPermission(const std::string & permission_str,const base::Value * permission_value,APIPermissionSet::ParseSource source,APIPermissionSet * api_permissions,base::string16 * error,std::vector<std::string> * unhandled_permissions)21 bool CreateAPIPermission(
22 const std::string& permission_str,
23 const base::Value* permission_value,
24 APIPermissionSet::ParseSource source,
25 APIPermissionSet* api_permissions,
26 base::string16* error,
27 std::vector<std::string>* unhandled_permissions) {
28
29 const APIPermissionInfo* permission_info =
30 PermissionsInfo::GetInstance()->GetByName(permission_str);
31 if (permission_info) {
32 scoped_ptr<APIPermission> permission(
33 permission_info->CreateAPIPermission());
34 if (source != APIPermissionSet::kAllowInternalPermissions &&
35 permission_info->is_internal()) {
36 // An internal permission specified in permissions list is an error.
37 if (error) {
38 *error = ErrorUtils::FormatErrorMessageUTF16(
39 errors::kPermissionNotAllowedInManifest, permission_str);
40 }
41 return false;
42 }
43
44 std::string error_details;
45 if (!permission->FromValue(permission_value, &error_details,
46 unhandled_permissions)) {
47 if (error) {
48 if (error_details.empty()) {
49 *error = ErrorUtils::FormatErrorMessageUTF16(
50 errors::kInvalidPermission,
51 permission_info->name());
52 } else {
53 *error = ErrorUtils::FormatErrorMessageUTF16(
54 errors::kInvalidPermissionWithDetail,
55 permission_info->name(),
56 error_details);
57 }
58 return false;
59 }
60 LOG(WARNING) << "Parse permission failed.";
61 } else {
62 api_permissions->insert(permission.release());
63 }
64 return true;
65 }
66
67 if (unhandled_permissions)
68 unhandled_permissions->push_back(permission_str);
69 else
70 LOG(WARNING) << "Unknown permission[" << permission_str << "].";
71
72 return true;
73 }
74
ParseChildPermissions(const std::string & base_name,const base::Value * permission_value,APIPermissionSet::ParseSource source,APIPermissionSet * api_permissions,base::string16 * error,std::vector<std::string> * unhandled_permissions)75 bool ParseChildPermissions(const std::string& base_name,
76 const base::Value* permission_value,
77 APIPermissionSet::ParseSource source,
78 APIPermissionSet* api_permissions,
79 base::string16* error,
80 std::vector<std::string>* unhandled_permissions) {
81 if (permission_value) {
82 const base::ListValue* permissions;
83 if (!permission_value->GetAsList(&permissions)) {
84 if (error) {
85 *error = ErrorUtils::FormatErrorMessageUTF16(
86 errors::kInvalidPermission, base_name);
87 return false;
88 }
89 LOG(WARNING) << "Permission value is not a list.";
90 // Failed to parse, but since error is NULL, failures are not fatal so
91 // return true here anyway.
92 return true;
93 }
94
95 for (size_t i = 0; i < permissions->GetSize(); ++i) {
96 std::string permission_str;
97 if (!permissions->GetString(i, &permission_str)) {
98 // permission should be a string
99 if (error) {
100 *error = ErrorUtils::FormatErrorMessageUTF16(
101 errors::kInvalidPermission,
102 base_name + '.' + base::IntToString(i));
103 return false;
104 }
105 LOG(WARNING) << "Permission is not a string.";
106 continue;
107 }
108
109 if (!CreateAPIPermission(
110 base_name + '.' + permission_str, NULL, source,
111 api_permissions, error, unhandled_permissions))
112 return false;
113 }
114 }
115
116 return CreateAPIPermission(base_name, NULL, source,
117 api_permissions, error, NULL);
118 }
119
120 } // namespace
121
insert(APIPermission::ID id)122 void APIPermissionSet::insert(APIPermission::ID id) {
123 const APIPermissionInfo* permission_info =
124 PermissionsInfo::GetInstance()->GetByID(id);
125 DCHECK(permission_info);
126 insert(permission_info->CreateAPIPermission());
127 }
128
insert(APIPermission * permission)129 void APIPermissionSet::insert(APIPermission* permission) {
130 BaseSetOperators<APIPermissionSet>::insert(permission);
131 }
132
133 // static
ParseFromJSON(const base::ListValue * permissions,APIPermissionSet::ParseSource source,APIPermissionSet * api_permissions,base::string16 * error,std::vector<std::string> * unhandled_permissions)134 bool APIPermissionSet::ParseFromJSON(
135 const base::ListValue* permissions,
136 APIPermissionSet::ParseSource source,
137 APIPermissionSet* api_permissions,
138 base::string16* error,
139 std::vector<std::string>* unhandled_permissions) {
140 for (size_t i = 0; i < permissions->GetSize(); ++i) {
141 std::string permission_str;
142 const base::Value* permission_value = NULL;
143 if (!permissions->GetString(i, &permission_str)) {
144 const base::DictionaryValue* dict = NULL;
145 // permission should be a string or a single key dict.
146 if (!permissions->GetDictionary(i, &dict) || dict->size() != 1) {
147 if (error) {
148 *error = ErrorUtils::FormatErrorMessageUTF16(
149 errors::kInvalidPermission, base::IntToString(i));
150 return false;
151 }
152 LOG(WARNING) << "Permission is not a string or single key dict.";
153 continue;
154 }
155 base::DictionaryValue::Iterator it(*dict);
156 permission_str = it.key();
157 permission_value = &it.value();
158 }
159
160 // Check if this permission is a special case where its value should
161 // be treated as a list of child permissions.
162 if (PermissionsInfo::GetInstance()->HasChildPermissions(permission_str)) {
163 if (!ParseChildPermissions(permission_str, permission_value, source,
164 api_permissions, error, unhandled_permissions))
165 return false;
166 continue;
167 }
168
169 if (!CreateAPIPermission(permission_str, permission_value, source,
170 api_permissions, error, unhandled_permissions))
171 return false;
172 }
173 return true;
174 }
175
AddImpliedPermissions()176 void APIPermissionSet::AddImpliedPermissions() {
177 // The fileSystem.write and fileSystem.directory permissions imply
178 // fileSystem.writeDirectory.
179 // TODO(sammc): Remove this. See http://crbug.com/284849.
180 if (ContainsKey(map(), APIPermission::kFileSystemWrite) &&
181 ContainsKey(map(), APIPermission::kFileSystemDirectory)) {
182 insert(APIPermission::kFileSystemWriteDirectory);
183 }
184 }
185
186 } // namespace extensions
187