1// Copyright (c) 2012 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 "chrome/common/extensions/permissions/api_permission_set.h"
6
7#include "base/logging.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/values.h"
10#include "chrome/common/extensions/extension_manifest_constants.h"
11#include "chrome/common/extensions/permissions/permissions_info.h"
12#include "extensions/common/error_utils.h"
13
14namespace errors = extension_manifest_errors;
15
16namespace {
17
18using extensions::APIPermission;
19using extensions::APIPermissionInfo;
20using extensions::APIPermissionSet;
21using extensions::ErrorUtils;
22using extensions::PermissionsInfo;
23
24bool CreateAPIPermission(
25    const std::string& permission_str,
26    const base::Value* permission_value,
27    APIPermissionSet::ParseSource source,
28    APIPermissionSet* api_permissions,
29    string16* error,
30    std::vector<std::string>* unhandled_permissions) {
31
32  const APIPermissionInfo* permission_info =
33      PermissionsInfo::GetInstance()->GetByName(permission_str);
34  if (permission_info) {
35    scoped_ptr<APIPermission> permission(
36        permission_info->CreateAPIPermission());
37    if (source != APIPermissionSet::kAllowInternalPermissions &&
38        permission_info->is_internal()) {
39      // An internal permission specified in permissions list is an error.
40      if (error) {
41        *error = ErrorUtils::FormatErrorMessageUTF16(
42            errors::kPermissionNotAllowedInManifest, permission_str);
43      }
44      return false;
45    }
46
47    if (!permission->FromValue(permission_value)) {
48      if (error) {
49        *error = ErrorUtils::FormatErrorMessageUTF16(
50            errors::kInvalidPermission, permission_info->name());
51        return false;
52      }
53      LOG(WARNING) << "Parse permission failed.";
54    } else {
55      api_permissions->insert(permission.release());
56    }
57    return true;
58  }
59
60  if (unhandled_permissions)
61    unhandled_permissions->push_back(permission_str);
62  else
63    LOG(WARNING) << "Unknown permission[" << permission_str << "].";
64
65  return true;
66}
67
68bool ParseChildPermissions(const std::string& base_name,
69                           const base::Value* permission_value,
70                           APIPermissionSet::ParseSource source,
71                           APIPermissionSet* api_permissions,
72                           string16* error,
73                           std::vector<std::string>* unhandled_permissions) {
74  if (permission_value) {
75    const base::ListValue* permissions;
76    if (!permission_value->GetAsList(&permissions)) {
77      if (error) {
78        *error = ErrorUtils::FormatErrorMessageUTF16(
79            errors::kInvalidPermission, base_name);
80        return false;
81      }
82      LOG(WARNING) << "Permission value is not a list.";
83      // Failed to parse, but since error is NULL, failures are not fatal so
84      // return true here anyway.
85      return true;
86    }
87
88    for (size_t i = 0; i < permissions->GetSize(); ++i) {
89      std::string permission_str;
90      if (!permissions->GetString(i, &permission_str)) {
91        // permission should be a string
92        if (error) {
93          *error = ErrorUtils::FormatErrorMessageUTF16(
94              errors::kInvalidPermission,
95              base_name + '.' + base::IntToString(i));
96          return false;
97        }
98        LOG(WARNING) << "Permission is not a string.";
99        continue;
100      }
101
102      if (!CreateAPIPermission(
103              base_name + '.' + permission_str, NULL, source,
104              api_permissions, error, unhandled_permissions))
105        return false;
106    }
107  }
108
109  return CreateAPIPermission(base_name, NULL, source,
110                             api_permissions, error, NULL);
111}
112
113}  // namespace
114
115namespace extensions {
116
117APIPermissionSet::APIPermissionSet() {
118}
119
120APIPermissionSet::APIPermissionSet(const APIPermissionSet& set) {
121  this->operator=(set);
122}
123
124APIPermissionSet::~APIPermissionSet() {
125}
126
127APIPermissionSet::const_iterator::const_iterator(
128    const APIPermissionMap::const_iterator& it)
129  : it_(it) {
130}
131
132APIPermissionSet::const_iterator::const_iterator(
133    const const_iterator& ids_it)
134  : it_(ids_it.it_) {
135}
136
137APIPermissionSet& APIPermissionSet::operator=(const APIPermissionSet& rhs) {
138  const_iterator it = rhs.begin();
139  const const_iterator end = rhs.end();
140  while (it != end) {
141    insert(it->Clone());
142    ++it;
143  }
144  return *this;
145}
146
147bool APIPermissionSet::operator==(const APIPermissionSet& rhs) const {
148  const_iterator it = begin();
149  const_iterator rhs_it = rhs.begin();
150  const_iterator it_end = end();
151  const_iterator rhs_it_end = rhs.end();
152
153  while (it != it_end && rhs_it != rhs_it_end) {
154    if (!it->Equal(*rhs_it))
155      return false;
156    ++it;
157    ++rhs_it;
158  }
159  return it == it_end && rhs_it == rhs_it_end;
160}
161
162void APIPermissionSet::insert(APIPermission::ID id) {
163  const APIPermissionInfo* permission_info =
164      PermissionsInfo::GetInstance()->GetByID(id);
165  insert(permission_info->CreateAPIPermission());
166}
167
168void APIPermissionSet::insert(APIPermission* permission) {
169  map_[permission->id()].reset(permission);
170}
171
172bool APIPermissionSet::Contains(const APIPermissionSet& rhs) const {
173  APIPermissionSet::const_iterator it1 = begin();
174  APIPermissionSet::const_iterator it2 = rhs.begin();
175  APIPermissionSet::const_iterator end1 = end();
176  APIPermissionSet::const_iterator end2 = rhs.end();
177
178  while (it1 != end1 && it2 != end2) {
179    if (it1->id() > it2->id()) {
180      return false;
181    } else if (it1->id() < it2->id()) {
182      ++it1;
183    } else {
184        if (!it1->Contains(*it2))
185          return false;
186      ++it1;
187      ++it2;
188    }
189  }
190
191  return it2 == end2;
192}
193
194void APIPermissionSet::Difference(
195    const APIPermissionSet& set1,
196    const APIPermissionSet& set2,
197    APIPermissionSet* set3) {
198  CHECK(set3);
199  set3->clear();
200
201  APIPermissionSet::const_iterator it1 = set1.begin();
202  APIPermissionSet::const_iterator it2 = set2.begin();
203  const APIPermissionSet::const_iterator end1 = set1.end();
204  const APIPermissionSet::const_iterator end2 = set2.end();
205
206  while (it1 != end1 && it2 != end2) {
207    if (it1->id() < it2->id()) {
208      set3->insert(it1->Clone());
209      ++it1;
210    } else if (it1->id() > it2->id()) {
211      ++it2;
212    } else {
213      APIPermission* p = it1->Diff(*it2);
214      if (p)
215        set3->insert(p);
216      ++it1;
217      ++it2;
218    }
219  }
220
221  while (it1 != end1) {
222    set3->insert(it1->Clone());
223    ++it1;
224  }
225}
226
227void APIPermissionSet::Intersection(
228    const APIPermissionSet& set1,
229    const APIPermissionSet& set2,
230    APIPermissionSet* set3) {
231  DCHECK(set3);
232  set3->clear();
233
234  APIPermissionSet::const_iterator it1 = set1.begin();
235  APIPermissionSet::const_iterator it2 = set2.begin();
236  const APIPermissionSet::const_iterator end1 = set1.end();
237  const APIPermissionSet::const_iterator end2 = set2.end();
238
239  while (it1 != end1 && it2 != end2) {
240    if (it1->id() < it2->id()) {
241      ++it1;
242    } else if (it1->id() > it2->id()) {
243      ++it2;
244    } else {
245      APIPermission* p = it1->Intersect(*it2);
246      if (p)
247        set3->insert(p);
248      ++it1;
249      ++it2;
250    }
251  }
252}
253
254void APIPermissionSet::Union(
255    const APIPermissionSet& set1,
256    const APIPermissionSet& set2,
257    APIPermissionSet* set3) {
258  DCHECK(set3);
259  set3->clear();
260
261  APIPermissionSet::const_iterator it1 = set1.begin();
262  APIPermissionSet::const_iterator it2 = set2.begin();
263  const APIPermissionSet::const_iterator end1 = set1.end();
264  const APIPermissionSet::const_iterator end2 = set2.end();
265
266  while (true) {
267    if (it1 == end1) {
268      while (it2 != end2) {
269        set3->insert(it2->Clone());
270        ++it2;
271      }
272      break;
273    }
274    if (it2 == end2) {
275      while (it1 != end1) {
276        set3->insert(it1->Clone());
277        ++it1;
278      }
279      break;
280    }
281    if (it1->id() < it2->id()) {
282      set3->insert(it1->Clone());
283      ++it1;
284    } else if (it1->id() > it2->id()) {
285      set3->insert(it2->Clone());
286      ++it2;
287    } else {
288      set3->insert(it1->Union(*it2));
289      ++it1;
290      ++it2;
291    }
292  }
293}
294
295// static
296bool APIPermissionSet::ParseFromJSON(
297    const base::ListValue* permissions,
298    APIPermissionSet::ParseSource source,
299    APIPermissionSet* api_permissions,
300    string16* error,
301    std::vector<std::string>* unhandled_permissions) {
302  for (size_t i = 0; i < permissions->GetSize(); ++i) {
303    std::string permission_str;
304    const base::Value* permission_value = NULL;
305    if (!permissions->GetString(i, &permission_str)) {
306      const base::DictionaryValue* dict = NULL;
307      // permission should be a string or a single key dict.
308      if (!permissions->GetDictionary(i, &dict) || dict->size() != 1) {
309        if (error) {
310          *error = ErrorUtils::FormatErrorMessageUTF16(
311              errors::kInvalidPermission, base::IntToString(i));
312          return false;
313        }
314        LOG(WARNING) << "Permission is not a string or single key dict.";
315        continue;
316      }
317      base::DictionaryValue::Iterator it(*dict);
318      permission_str = it.key();
319      permission_value = &it.value();
320    }
321
322    // Check if this permission is a special case where its value should
323    // be treated as a list of child permissions.
324    if (PermissionsInfo::GetInstance()->HasChildPermissions(permission_str)) {
325      if (!ParseChildPermissions(permission_str, permission_value, source,
326                                 api_permissions, error, unhandled_permissions))
327        return false;
328      continue;
329    }
330
331    if (!CreateAPIPermission(permission_str, permission_value, source,
332                             api_permissions, error, unhandled_permissions))
333      return false;
334  }
335  return true;
336}
337
338}  // namespace extensions
339