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.
5 #include "extensions/common/permissions/api_permission_set.h"
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"
15 namespace extensions
{
17 namespace errors
= manifest_errors
;
21 // Helper object that is implicitly constructible from both a PermissionID and
22 // from an APIPermission::ID.
23 struct PermissionIDCompareHelper
{
24 PermissionIDCompareHelper(const PermissionID
& id
) : id(id
.id()) {}
25 PermissionIDCompareHelper(const APIPermission::ID id
) : id(id
) {}
30 bool CreateAPIPermission(
31 const std::string
& permission_str
,
32 const base::Value
* permission_value
,
33 APIPermissionSet::ParseSource source
,
34 APIPermissionSet
* api_permissions
,
35 base::string16
* error
,
36 std::vector
<std::string
>* unhandled_permissions
) {
38 const APIPermissionInfo
* permission_info
=
39 PermissionsInfo::GetInstance()->GetByName(permission_str
);
40 if (permission_info
) {
41 scoped_ptr
<APIPermission
> permission(
42 permission_info
->CreateAPIPermission());
43 if (source
!= APIPermissionSet::kAllowInternalPermissions
&&
44 permission_info
->is_internal()) {
45 // An internal permission specified in permissions list is an error.
47 *error
= ErrorUtils::FormatErrorMessageUTF16(
48 errors::kPermissionNotAllowedInManifest
, permission_str
);
53 std::string error_details
;
54 if (!permission
->FromValue(permission_value
, &error_details
,
55 unhandled_permissions
)) {
57 if (error_details
.empty()) {
58 *error
= ErrorUtils::FormatErrorMessageUTF16(
59 errors::kInvalidPermission
,
60 permission_info
->name());
62 *error
= ErrorUtils::FormatErrorMessageUTF16(
63 errors::kInvalidPermissionWithDetail
,
64 permission_info
->name(),
69 LOG(WARNING
) << "Parse permission failed.";
71 api_permissions
->insert(permission
.release());
76 if (unhandled_permissions
)
77 unhandled_permissions
->push_back(permission_str
);
79 LOG(WARNING
) << "Unknown permission[" << permission_str
<< "].";
84 bool ParseChildPermissions(const std::string
& base_name
,
85 const base::Value
* permission_value
,
86 APIPermissionSet::ParseSource source
,
87 APIPermissionSet
* api_permissions
,
88 base::string16
* error
,
89 std::vector
<std::string
>* unhandled_permissions
) {
90 if (permission_value
) {
91 const base::ListValue
* permissions
;
92 if (!permission_value
->GetAsList(&permissions
)) {
94 *error
= ErrorUtils::FormatErrorMessageUTF16(
95 errors::kInvalidPermission
, base_name
);
98 LOG(WARNING
) << "Permission value is not a list.";
99 // Failed to parse, but since error is NULL, failures are not fatal so
100 // return true here anyway.
104 for (size_t i
= 0; i
< permissions
->GetSize(); ++i
) {
105 std::string permission_str
;
106 if (!permissions
->GetString(i
, &permission_str
)) {
107 // permission should be a string
109 *error
= ErrorUtils::FormatErrorMessageUTF16(
110 errors::kInvalidPermission
,
111 base_name
+ '.' + base::IntToString(i
));
114 LOG(WARNING
) << "Permission is not a string.";
118 if (!CreateAPIPermission(
119 base_name
+ '.' + permission_str
, NULL
, source
,
120 api_permissions
, error
, unhandled_permissions
))
125 return CreateAPIPermission(base_name
, NULL
, source
,
126 api_permissions
, error
, NULL
);
131 void APIPermissionSet::insert(APIPermission::ID id
) {
132 const APIPermissionInfo
* permission_info
=
133 PermissionsInfo::GetInstance()->GetByID(id
);
134 DCHECK(permission_info
);
135 insert(permission_info
->CreateAPIPermission());
138 void APIPermissionSet::insert(APIPermission
* permission
) {
139 BaseSetOperators
<APIPermissionSet
>::insert(permission
);
143 bool APIPermissionSet::ParseFromJSON(
144 const base::ListValue
* permissions
,
145 APIPermissionSet::ParseSource source
,
146 APIPermissionSet
* api_permissions
,
147 base::string16
* error
,
148 std::vector
<std::string
>* unhandled_permissions
) {
149 for (size_t i
= 0; i
< permissions
->GetSize(); ++i
) {
150 std::string permission_str
;
151 const base::Value
* permission_value
= NULL
;
152 if (!permissions
->GetString(i
, &permission_str
)) {
153 const base::DictionaryValue
* dict
= NULL
;
154 // permission should be a string or a single key dict.
155 if (!permissions
->GetDictionary(i
, &dict
) || dict
->size() != 1) {
157 *error
= ErrorUtils::FormatErrorMessageUTF16(
158 errors::kInvalidPermission
, base::IntToString(i
));
161 LOG(WARNING
) << "Permission is not a string or single key dict.";
164 base::DictionaryValue::Iterator
it(*dict
);
165 permission_str
= it
.key();
166 permission_value
= &it
.value();
169 // Check if this permission is a special case where its value should
170 // be treated as a list of child permissions.
171 if (PermissionsInfo::GetInstance()->HasChildPermissions(permission_str
)) {
172 if (!ParseChildPermissions(permission_str
, permission_value
, source
,
173 api_permissions
, error
, unhandled_permissions
))
178 if (!CreateAPIPermission(permission_str
, permission_value
, source
,
179 api_permissions
, error
, unhandled_permissions
))
185 void APIPermissionSet::AddImpliedPermissions() {
186 // The fileSystem.write and fileSystem.directory permissions imply
187 // fileSystem.writeDirectory.
188 // Has a corresponding rule in ChromePermissionMessageProvider.
189 // TODO(sammc): Remove this. See http://crbug.com/284849.
190 if (ContainsKey(map(), APIPermission::kFileSystemWrite
) &&
191 ContainsKey(map(), APIPermission::kFileSystemDirectory
)) {
192 insert(APIPermission::kFileSystemWriteDirectory
);
196 PermissionID::PermissionID(APIPermission::ID id
)
197 : std::pair
<APIPermission::ID
, base::string16
>(id
, base::string16()) {
200 PermissionID::PermissionID(APIPermission::ID id
,
201 const base::string16
& parameter
)
202 : std::pair
<APIPermission::ID
, base::string16
>(id
, parameter
) {
205 PermissionID::~PermissionID() {
208 PermissionIDSet::PermissionIDSet() {
211 PermissionIDSet::~PermissionIDSet() {
214 void PermissionIDSet::insert(APIPermission::ID permission_id
) {
215 insert(permission_id
, base::string16());
218 void PermissionIDSet::insert(APIPermission::ID permission_id
,
219 const base::string16
& permission_detail
) {
220 permissions_
.insert(PermissionID(permission_id
, permission_detail
));
223 void PermissionIDSet::InsertAll(const PermissionIDSet
& permission_set
) {
224 for (const auto& permission
: permission_set
.permissions_
) {
225 permissions_
.insert(permission
);
229 void PermissionIDSet::erase(APIPermission::ID permission_id
) {
230 permissions_
.erase(PermissionID(permission_id
));
233 std::vector
<base::string16
> PermissionIDSet::GetAllPermissionParameters()
235 std::vector
<base::string16
> params
;
236 for (const auto& permission
: permissions_
) {
237 params
.push_back(permission
.parameter());
242 bool PermissionIDSet::ContainsID(APIPermission::ID permission_id
) const {
243 auto it
= permissions_
.lower_bound(PermissionID(permission_id
));
244 return it
!= permissions_
.end() && it
->id() == permission_id
;
247 bool PermissionIDSet::ContainsAllIDs(
248 const std::set
<APIPermission::ID
>& permission_ids
) const {
249 return std::includes(permissions_
.begin(), permissions_
.end(),
250 permission_ids
.begin(), permission_ids
.end(),
251 [] (const PermissionIDCompareHelper
& lhs
,
252 const PermissionIDCompareHelper
& rhs
) {
253 return lhs
.id
< rhs
.id
;
257 PermissionIDSet
PermissionIDSet::GetAllPermissionsWithIDs(
258 const std::set
<APIPermission::ID
>& permission_ids
) const {
259 PermissionIDSet subset
;
260 for (const auto& permission
: permissions_
) {
261 if (ContainsKey(permission_ids
, permission
.id())) {
262 subset
.permissions_
.insert(permission
);
268 bool PermissionIDSet::Includes(const PermissionIDSet
& subset
) const {
269 return base::STLIncludes(permissions_
, subset
.permissions_
);
272 bool PermissionIDSet::Equals(const PermissionIDSet
& set
) const {
273 return permissions_
== set
.permissions_
;
277 PermissionIDSet
PermissionIDSet::Difference(const PermissionIDSet
& set_1
,
278 const PermissionIDSet
& set_2
) {
279 return PermissionIDSet(base::STLSetDifference
<std::set
<PermissionID
>>(
280 set_1
.permissions_
, set_2
.permissions_
));
283 size_t PermissionIDSet::size() const {
284 return permissions_
.size();
287 bool PermissionIDSet::empty() const {
288 return permissions_
.empty();
291 PermissionIDSet::PermissionIDSet(const std::set
<PermissionID
>& permissions
)
292 : permissions_(permissions
) {
295 } // namespace extensions