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
15namespace extensions {
16
17namespace errors = manifest_errors;
18
19namespace {
20
21bool 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
75bool 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
122void 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
129void APIPermissionSet::insert(APIPermission* permission) {
130  BaseSetOperators<APIPermissionSet>::insert(permission);
131}
132
133// static
134bool 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
176void 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