summaryrefslogtreecommitdiffstats
path: root/extensions/common/permissions
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/common/permissions')
-rw-r--r--extensions/common/permissions/api_permission.cc143
-rw-r--r--extensions/common/permissions/api_permission.h333
-rw-r--r--extensions/common/permissions/api_permission_set.cc343
-rw-r--r--extensions/common/permissions/api_permission_set.h173
-rw-r--r--extensions/common/permissions/api_permission_set_unittest.cc333
-rw-r--r--extensions/common/permissions/permissions_info.cc101
-rw-r--r--extensions/common/permissions/permissions_info.h81
7 files changed, 1507 insertions, 0 deletions
diff --git a/extensions/common/permissions/api_permission.cc b/extensions/common/permissions/api_permission.cc
new file mode 100644
index 0000000..f183ed2
--- /dev/null
+++ b/extensions/common/permissions/api_permission.cc
@@ -0,0 +1,143 @@
+// 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.h"
+
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+using extensions::APIPermission;
+using extensions::APIPermissionInfo;
+using extensions::PermissionMessage;
+using extensions::PermissionMessages;
+
+class SimpleAPIPermission : public APIPermission {
+ public:
+ explicit SimpleAPIPermission(const APIPermissionInfo* permission)
+ : APIPermission(permission) { }
+
+ virtual ~SimpleAPIPermission() { }
+
+ virtual bool HasMessages() const OVERRIDE {
+ return info()->message_id() > PermissionMessage::kNone;
+ }
+
+ virtual PermissionMessages GetMessages() const OVERRIDE {
+ DCHECK(HasMessages());
+ PermissionMessages result;
+ result.push_back(GetMessage_());
+ return result;
+ }
+
+ virtual bool Check(
+ const APIPermission::CheckParam* param) const OVERRIDE {
+ return !param;
+ }
+
+ virtual bool Contains(const APIPermission* rhs) const OVERRIDE {
+ CHECK(info() == rhs->info());
+ return true;
+ }
+
+ virtual bool Equal(const APIPermission* rhs) const OVERRIDE {
+ if (this == rhs)
+ return true;
+ CHECK(info() == rhs->info());
+ return true;
+ }
+
+ virtual bool FromValue(const base::Value* value) OVERRIDE {
+ if (value)
+ return false;
+ return true;
+ }
+
+ virtual scoped_ptr<base::Value> ToValue() const OVERRIDE {
+ return scoped_ptr<base::Value>();
+ }
+
+ virtual APIPermission* Clone() const OVERRIDE {
+ return new SimpleAPIPermission(info());
+ }
+
+ virtual APIPermission* Diff(const APIPermission* rhs) const OVERRIDE {
+ CHECK(info() == rhs->info());
+ return NULL;
+ }
+
+ virtual APIPermission* Union(const APIPermission* rhs) const OVERRIDE {
+ CHECK(info() == rhs->info());
+ return new SimpleAPIPermission(info());
+ }
+
+ virtual APIPermission* Intersect(const APIPermission* rhs) const OVERRIDE {
+ CHECK(info() == rhs->info());
+ return new SimpleAPIPermission(info());
+ }
+
+ virtual void Write(IPC::Message* m) const OVERRIDE { }
+
+ virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE {
+ return true;
+ }
+
+ virtual void Log(std::string* log) const OVERRIDE { }
+};
+
+} // namespace
+
+namespace extensions {
+
+APIPermission::APIPermission(const APIPermissionInfo* info)
+ : info_(info) {
+ DCHECK(info_);
+}
+
+APIPermission::~APIPermission() { }
+
+APIPermission::ID APIPermission::id() const {
+ return info()->id();
+}
+
+const char* APIPermission::name() const {
+ return info()->name();
+}
+
+PermissionMessage APIPermission::GetMessage_() const {
+ return info()->GetMessage_();
+}
+
+//
+// APIPermissionInfo
+//
+
+APIPermissionInfo::APIPermissionInfo(
+ APIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ PermissionMessage::ID message_id,
+ int flags,
+ APIPermissionConstructor api_permission_constructor)
+ : id_(id),
+ name_(name),
+ flags_(flags),
+ l10n_message_id_(l10n_message_id),
+ message_id_(message_id),
+ api_permission_constructor_(api_permission_constructor) { }
+
+
+APIPermissionInfo::~APIPermissionInfo() { }
+
+APIPermission* APIPermissionInfo::CreateAPIPermission() const {
+ return api_permission_constructor_ ?
+ api_permission_constructor_(this) : new SimpleAPIPermission(this);
+}
+
+PermissionMessage APIPermissionInfo::GetMessage_() const {
+ return PermissionMessage(
+ message_id_, l10n_util::GetStringUTF16(l10n_message_id_));
+}
+
+} // namespace extensions
diff --git a/extensions/common/permissions/api_permission.h b/extensions/common/permissions/api_permission.h
new file mode 100644
index 0000000..6fbe479
--- /dev/null
+++ b/extensions/common/permissions/api_permission.h
@@ -0,0 +1,333 @@
+// 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.
+
+#ifndef EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/values.h"
+#include "extensions/common/permissions/permission_message.h"
+
+namespace IPC {
+class Message;
+}
+
+namespace extensions {
+
+class APIPermissionInfo;
+class ChromeAPIPermissions;
+
+// APIPermission is for handling some complex permissions. Please refer to
+// extensions::SocketPermission as an example.
+// There is one instance per permission per loaded extension.
+class APIPermission {
+ public:
+ enum ID {
+ // Error codes.
+ kInvalid = -2,
+ kUnknown = -1,
+
+ // Real permissions.
+ kActiveTab,
+ kActivityLogPrivate,
+ kAdView,
+ kAlarms,
+ kAppCurrentWindowInternal,
+ kAppRuntime,
+ kAppWindow,
+ kAudio,
+ kAudioCapture,
+ kAutoTestPrivate,
+ kBackground,
+ kBluetooth,
+ kBookmark,
+ kBookmarkManagerPrivate,
+ kBrailleDisplayPrivate,
+ kBrowsingData,
+ kCast,
+ kChromeosInfoPrivate,
+ kClipboardRead,
+ kClipboardWrite,
+ kCloudPrintPrivate,
+ kCommandLinePrivate,
+ kContentSettings,
+ kContextMenus,
+ kCookie,
+ kDiagnostics,
+ kDial,
+ kDebugger,
+ kDeclarative,
+ kDeclarativeContent,
+ kDeclarativeWebRequest,
+ kDesktopCapture,
+ kDeveloperPrivate,
+ kDevtools,
+ kDns,
+ kDownloads,
+ kDownloadsInternal,
+ kDownloadsOpen,
+ kDownloadsShelf,
+ kEchoPrivate,
+ kEnterprisePlatformKeysPrivate,
+ kExperimental,
+ kFeedbackPrivate,
+ kFileBrowserHandler,
+ kFileBrowserHandlerInternal,
+ kFileBrowserPrivate,
+ kFileSystem,
+ kFileSystemDirectory,
+ kFileSystemRetainEntries,
+ kFileSystemWrite,
+ kFileSystemWriteDirectory,
+ kFontSettings,
+ kFullscreen,
+ kGeolocation,
+ kHistory,
+ kIdentity,
+ kIdentityPrivate,
+ kIdltest,
+ kIdle,
+ kInfobars,
+ kInput,
+ kInputMethodPrivate,
+ kLocation,
+ kLogPrivate,
+ kManagement,
+ kMediaGalleries,
+ kMediaGalleriesPrivate,
+ kMediaPlayerPrivate,
+ kMetricsPrivate,
+ kMDns,
+ kMusicManagerPrivate,
+ kNativeMessaging,
+ kNetworkingPrivate,
+ kNotification,
+ kPageCapture,
+ kPointerLock,
+ kPlugin,
+ kPower,
+ kPreferencesPrivate,
+ kPrincipalsPrivate,
+ kPrivacy,
+ kProcesses,
+ kProxy,
+ kPushMessaging,
+ kImageWriterPrivate,
+ kRtcPrivate,
+ kScreensaver,
+ kSerial,
+ kSessions,
+ kSignedInDevices,
+ kSocket,
+ kSocketsUdp,
+ kStorage,
+ kStreamsPrivate,
+ kSyncFileSystem,
+ kSystemPrivate,
+ kSystemIndicator,
+ kSystemDisplay,
+ kSystemStorage,
+ kTab,
+ kTabCapture,
+ kTabCaptureForTab,
+ kTerminalPrivate,
+ kTopSites,
+ kTts,
+ kTtsEngine,
+ kUnlimitedStorage,
+ kUsb,
+ kUsbDevice,
+ kVideoCapture,
+ kVirtualKeyboardPrivate,
+ kWallpaper,
+ kWallpaperPrivate,
+ kWebConnectable, // for externally_connectable manifest key
+ kWebNavigation,
+ kWebRequest,
+ kWebRequestBlocking,
+ kWebRequestInternal,
+ kWebRtc,
+ kWebrtcLoggingPrivate,
+ kWebstorePrivate,
+ kWebView,
+ kSystemCpu,
+ kSystemMemory,
+ kSystemInfoCpu,
+ kSystemInfoMemory,
+ kEnumBoundary
+ };
+
+ struct CheckParam {
+ };
+
+ explicit APIPermission(const APIPermissionInfo* info);
+
+ virtual ~APIPermission();
+
+ // Returns the id of this permission.
+ ID id() const;
+
+ // Returns the name of this permission.
+ const char* name() const;
+
+ // Returns the APIPermission of this permission.
+ const APIPermissionInfo* info() const {
+ return info_;
+ }
+
+ // Returns true if this permission has any PermissionMessages.
+ virtual bool HasMessages() const = 0;
+
+ // Returns the localized permission messages of this permission.
+ virtual PermissionMessages GetMessages() const = 0;
+
+ // Returns true if the given permission is allowed.
+ virtual bool Check(const CheckParam* param) const = 0;
+
+ // Returns true if |rhs| is a subset of this.
+ virtual bool Contains(const APIPermission* rhs) const = 0;
+
+ // Returns true if |rhs| is equal to this.
+ virtual bool Equal(const APIPermission* rhs) const = 0;
+
+ // Parses the APIPermission from |value|. Returns false if error happens.
+ virtual bool FromValue(const base::Value* value) = 0;
+
+ // Stores this into a new created |value|.
+ virtual scoped_ptr<base::Value> ToValue() const = 0;
+
+ // Clones this.
+ virtual APIPermission* Clone() const = 0;
+
+ // Returns a new API permission which equals this - |rhs|.
+ virtual APIPermission* Diff(const APIPermission* rhs) const = 0;
+
+ // Returns a new API permission which equals the union of this and |rhs|.
+ virtual APIPermission* Union(const APIPermission* rhs) const = 0;
+
+ // Returns a new API permission which equals the intersect of this and |rhs|.
+ virtual APIPermission* Intersect(const APIPermission* rhs) const = 0;
+
+ // IPC functions
+ // Writes this into the given IPC message |m|.
+ virtual void Write(IPC::Message* m) const = 0;
+
+ // Reads from the given IPC message |m|.
+ virtual bool Read(const IPC::Message* m, PickleIterator* iter) = 0;
+
+ // Logs this permission.
+ virtual void Log(std::string* log) const = 0;
+
+ protected:
+ // Returns the localized permission message associated with this api.
+ // Use GetMessage_ to avoid name conflict with macro GetMessage on Windows.
+ PermissionMessage GetMessage_() const;
+
+ private:
+ const APIPermissionInfo* const info_;
+};
+
+
+// The APIPermissionInfo is an immutable class that describes a single
+// named permission (API permission).
+// There is one instance per permission.
+class APIPermissionInfo {
+ public:
+ enum Flag {
+ kFlagNone = 0,
+
+ // Indicates if the permission implies full access (native code).
+ kFlagImpliesFullAccess = 1 << 0,
+
+ // Indicates if the permission implies full URL access.
+ kFlagImpliesFullURLAccess = 1 << 1,
+
+ // Indicates that extensions cannot specify the permission as optional.
+ kFlagCannotBeOptional = 1 << 3,
+
+ // Indicates that the permission is internal to the extensions
+ // system and cannot be specified in the "permissions" list.
+ kFlagInternal = 1 << 4,
+ };
+
+ typedef APIPermission* (*APIPermissionConstructor)(const APIPermissionInfo*);
+
+ typedef std::set<APIPermission::ID> IDSet;
+
+ ~APIPermissionInfo();
+
+ // Creates a APIPermission instance.
+ APIPermission* CreateAPIPermission() const;
+
+ int flags() const { return flags_; }
+
+ APIPermission::ID id() const { return id_; }
+
+ // Returns the message id associated with this permission.
+ PermissionMessage::ID message_id() const {
+ return message_id_;
+ }
+
+ // Returns the name of this permission.
+ const char* name() const { return name_; }
+
+ // Returns true if this permission implies full access (e.g., native code).
+ bool implies_full_access() const {
+ return (flags_ & kFlagImpliesFullAccess) != 0;
+ }
+
+ // Returns true if this permission implies full URL access.
+ bool implies_full_url_access() const {
+ return (flags_ & kFlagImpliesFullURLAccess) != 0;
+ }
+
+ // Returns true if this permission can be added and removed via the
+ // optional permissions extension API.
+ bool supports_optional() const {
+ return (flags_ & kFlagCannotBeOptional) == 0;
+ }
+
+ // Returns true if this permission is internal rather than a
+ // "permissions" list entry.
+ bool is_internal() const {
+ return (flags_ & kFlagInternal) != 0;
+ }
+
+ private:
+ // Instances should only be constructed from within a
+ // PermissionsInfo::Delegate.
+ friend class ChromeAPIPermissions;
+ // Implementations of APIPermission will want to get the permission message,
+ // but this class's implementation should be hidden from everyone else.
+ friend class APIPermission;
+
+ explicit APIPermissionInfo(
+ APIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ PermissionMessage::ID message_id,
+ int flags,
+ APIPermissionConstructor api_permission_constructor);
+
+ // Returns the localized permission message associated with this api.
+ // Use GetMessage_ to avoid name conflict with macro GetMessage on Windows.
+ PermissionMessage GetMessage_() const;
+
+ const APIPermission::ID id_;
+ const char* const name_;
+ const int flags_;
+ const int l10n_message_id_;
+ const PermissionMessage::ID message_id_;
+ const APIPermissionConstructor api_permission_constructor_;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_H_
diff --git a/extensions/common/permissions/api_permission_set.cc b/extensions/common/permissions/api_permission_set.cc
new file mode 100644
index 0000000..ebaf8d8
--- /dev/null
+++ b/extensions/common/permissions/api_permission_set.cc
@@ -0,0 +1,343 @@
+// 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
+
+APIPermissionSet::APIPermissionSet() {
+}
+
+APIPermissionSet::APIPermissionSet(const APIPermissionSet& set) {
+ this->operator=(set);
+}
+
+APIPermissionSet::~APIPermissionSet() {
+}
+
+APIPermissionSet::const_iterator::const_iterator(
+ const APIPermissionMap::const_iterator& it)
+ : it_(it) {
+}
+
+APIPermissionSet::const_iterator::const_iterator(
+ const const_iterator& ids_it)
+ : it_(ids_it.it_) {
+}
+
+APIPermissionSet& APIPermissionSet::operator=(const APIPermissionSet& rhs) {
+ const_iterator it = rhs.begin();
+ const const_iterator end = rhs.end();
+ while (it != end) {
+ insert(it->Clone());
+ ++it;
+ }
+ return *this;
+}
+
+bool APIPermissionSet::operator==(const APIPermissionSet& rhs) const {
+ const_iterator it = begin();
+ const_iterator rhs_it = rhs.begin();
+ const_iterator it_end = end();
+ const_iterator rhs_it_end = rhs.end();
+
+ while (it != it_end && rhs_it != rhs_it_end) {
+ if (!it->Equal(*rhs_it))
+ return false;
+ ++it;
+ ++rhs_it;
+ }
+ return it == it_end && rhs_it == rhs_it_end;
+}
+
+void APIPermissionSet::insert(APIPermission::ID id) {
+ const APIPermissionInfo* permission_info =
+ PermissionsInfo::GetInstance()->GetByID(id);
+ insert(permission_info->CreateAPIPermission());
+}
+
+void APIPermissionSet::insert(APIPermission* permission) {
+ map_[permission->id()].reset(permission);
+}
+
+bool APIPermissionSet::Contains(const APIPermissionSet& rhs) const {
+ APIPermissionSet::const_iterator it1 = begin();
+ APIPermissionSet::const_iterator it2 = rhs.begin();
+ APIPermissionSet::const_iterator end1 = end();
+ APIPermissionSet::const_iterator end2 = rhs.end();
+
+ while (it1 != end1 && it2 != end2) {
+ if (it1->id() > it2->id()) {
+ return false;
+ } else if (it1->id() < it2->id()) {
+ ++it1;
+ } else {
+ if (!it1->Contains(*it2))
+ return false;
+ ++it1;
+ ++it2;
+ }
+ }
+
+ return it2 == end2;
+}
+
+void APIPermissionSet::Difference(
+ const APIPermissionSet& set1,
+ const APIPermissionSet& set2,
+ APIPermissionSet* set3) {
+ CHECK(set3);
+ set3->clear();
+
+ APIPermissionSet::const_iterator it1 = set1.begin();
+ APIPermissionSet::const_iterator it2 = set2.begin();
+ const APIPermissionSet::const_iterator end1 = set1.end();
+ const APIPermissionSet::const_iterator end2 = set2.end();
+
+ while (it1 != end1 && it2 != end2) {
+ if (it1->id() < it2->id()) {
+ set3->insert(it1->Clone());
+ ++it1;
+ } else if (it1->id() > it2->id()) {
+ ++it2;
+ } else {
+ APIPermission* p = it1->Diff(*it2);
+ if (p)
+ set3->insert(p);
+ ++it1;
+ ++it2;
+ }
+ }
+
+ while (it1 != end1) {
+ set3->insert(it1->Clone());
+ ++it1;
+ }
+}
+
+void APIPermissionSet::Intersection(
+ const APIPermissionSet& set1,
+ const APIPermissionSet& set2,
+ APIPermissionSet* set3) {
+ DCHECK(set3);
+ set3->clear();
+
+ APIPermissionSet::const_iterator it1 = set1.begin();
+ APIPermissionSet::const_iterator it2 = set2.begin();
+ const APIPermissionSet::const_iterator end1 = set1.end();
+ const APIPermissionSet::const_iterator end2 = set2.end();
+
+ while (it1 != end1 && it2 != end2) {
+ if (it1->id() < it2->id()) {
+ ++it1;
+ } else if (it1->id() > it2->id()) {
+ ++it2;
+ } else {
+ APIPermission* p = it1->Intersect(*it2);
+ if (p)
+ set3->insert(p);
+ ++it1;
+ ++it2;
+ }
+ }
+}
+
+void APIPermissionSet::Union(
+ const APIPermissionSet& set1,
+ const APIPermissionSet& set2,
+ APIPermissionSet* set3) {
+ DCHECK(set3);
+ set3->clear();
+
+ APIPermissionSet::const_iterator it1 = set1.begin();
+ APIPermissionSet::const_iterator it2 = set2.begin();
+ const APIPermissionSet::const_iterator end1 = set1.end();
+ const APIPermissionSet::const_iterator end2 = set2.end();
+
+ while (true) {
+ if (it1 == end1) {
+ while (it2 != end2) {
+ set3->insert(it2->Clone());
+ ++it2;
+ }
+ break;
+ }
+ if (it2 == end2) {
+ while (it1 != end1) {
+ set3->insert(it1->Clone());
+ ++it1;
+ }
+ break;
+ }
+ if (it1->id() < it2->id()) {
+ set3->insert(it1->Clone());
+ ++it1;
+ } else if (it1->id() > it2->id()) {
+ set3->insert(it2->Clone());
+ ++it2;
+ } else {
+ set3->insert(it1->Union(*it2));
+ ++it1;
+ ++it2;
+ }
+ }
+}
+
+// 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
diff --git a/extensions/common/permissions/api_permission_set.h b/extensions/common/permissions/api_permission_set.h
new file mode 100644
index 0000000..9b6f26d
--- /dev/null
+++ b/extensions/common/permissions/api_permission_set.h
@@ -0,0 +1,173 @@
+// 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.
+
+#ifndef EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_SET_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_SET_H_
+
+#include <iterator>
+#include <map>
+
+#include "base/memory/linked_ptr.h"
+#include "extensions/common/permissions/api_permission.h"
+
+namespace base {
+class ListValue;
+} // namespace base
+
+namespace extensions {
+
+class Extension;
+
+typedef std::map<APIPermission::ID,
+ linked_ptr<APIPermission> > APIPermissionMap;
+
+class APIPermissionSet {
+ public:
+ class const_iterator :
+ public std::iterator<std::input_iterator_tag, const APIPermission*> {
+ public:
+ const_iterator(const APIPermissionMap::const_iterator& it);
+ const_iterator(const const_iterator& ids_it);
+
+ const_iterator& operator++() {
+ ++it_;
+ return *this;
+ }
+
+ const_iterator operator++(int) {
+ const_iterator tmp(it_++);
+ return tmp;
+ }
+
+ bool operator==(const const_iterator& rhs) const {
+ return it_ == rhs.it_;
+ }
+
+ bool operator!=(const const_iterator& rhs) const {
+ return it_ != rhs.it_;
+ }
+
+ const APIPermission* operator*() const {
+ return it_->second.get();
+ }
+
+ const APIPermission* operator->() const {
+ return it_->second.get();
+ }
+
+ private:
+ APIPermissionMap::const_iterator it_;
+ };
+
+ enum ParseSource {
+ // Don't allow internal permissions to be parsed (e.g. entries in the
+ // "permissions" list in a manifest).
+ kDisallowInternalPermissions,
+
+ // Allow internal permissions to be parsed (e.g. from the "api" field of a
+ // permissions list in the prefs).
+ kAllowInternalPermissions,
+ };
+
+ APIPermissionSet();
+
+ APIPermissionSet(const APIPermissionSet& set);
+
+ ~APIPermissionSet();
+
+ const_iterator begin() const {
+ return const_iterator(map().begin());
+ }
+
+ const_iterator end() const {
+ return map().end();
+ }
+
+ const_iterator find(APIPermission::ID id) const {
+ return map().find(id);
+ }
+
+ const APIPermissionMap& map() const {
+ return map_;
+ }
+
+ APIPermissionMap& map() {
+ return map_;
+ }
+
+ void clear() {
+ map_.clear();
+ }
+
+ size_t count(APIPermission::ID id) const {
+ return map().count(id);
+ }
+
+ bool empty() const {
+ return map().empty();
+ }
+
+ size_t erase(APIPermission::ID id) {
+ return map().erase(id);
+ }
+
+ size_t size() const {
+ return map().size();
+ }
+
+ APIPermissionSet& operator=(const APIPermissionSet& rhs);
+
+ bool operator==(const APIPermissionSet& rhs) const;
+
+ bool operator!=(const APIPermissionSet& rhs) const {
+ return !operator==(rhs);
+ }
+
+ void insert(APIPermission::ID id);
+
+ // Insert |permission| into the APIPermissionSet. The APIPermissionSet will
+ // take the ownership of |permission|,
+ void insert(APIPermission* permission);
+
+ bool Contains(const APIPermissionSet& rhs) const;
+
+ static void Difference(
+ const APIPermissionSet& set1,
+ const APIPermissionSet& set2,
+ APIPermissionSet* set3);
+
+ static void Intersection(
+ const APIPermissionSet& set1,
+ const APIPermissionSet& set2,
+ APIPermissionSet* set3);
+
+ static void Union(
+ const APIPermissionSet& set1,
+ const APIPermissionSet& set2,
+ APIPermissionSet* set3);
+
+ // Parses permissions from |permissions| and adds the parsed permissions to
+ // |api_permissions|. If |source| is kDisallowInternalPermissions, treat
+ // permissions with kFlagInternal as errors. If |unhandled_permissions|
+ // is not NULL, the names of all permissions that couldn't be parsed will be
+ // added to this vector. If |error| is NULL, parsing will continue with the
+ // next permission if invalid data is detected. If |error| is not NULL, it
+ // will be set to an error message and false is returned when an invalid
+ // permission is found.
+ static bool ParseFromJSON(
+ const base::ListValue* permissions,
+ ParseSource source,
+ APIPermissionSet* api_permissions,
+ string16* error,
+ std::vector<std::string>* unhandled_permissions);
+
+ void AddImpliedPermissions();
+
+ private:
+ APIPermissionMap map_;
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_PERMISSIONS_API_PERMISSION_SET_H_
diff --git a/extensions/common/permissions/api_permission_set_unittest.cc b/extensions/common/permissions/api_permission_set_unittest.cc
new file mode 100644
index 0000000..85f8ccc
--- /dev/null
+++ b/extensions/common/permissions/api_permission_set_unittest.cc
@@ -0,0 +1,333 @@
+// 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 "base/pickle.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "ipc/ipc_message.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+TEST(APIPermissionSetTest, General) {
+ APIPermissionSet apis;
+ apis.insert(APIPermission::kTab);
+ apis.insert(APIPermission::kBackground);
+ apis.insert(APIPermission::kProxy);
+ apis.insert(APIPermission::kClipboardWrite);
+ apis.insert(APIPermission::kPlugin);
+
+ EXPECT_EQ(apis.find(APIPermission::kProxy)->id(), APIPermission::kProxy);
+ EXPECT_TRUE(apis.find(APIPermission::kSocket) == apis.end());
+
+ EXPECT_EQ(apis.size(), 5u);
+
+ EXPECT_EQ(apis.erase(APIPermission::kTab), 1u);
+ EXPECT_EQ(apis.size(), 4u);
+
+ EXPECT_EQ(apis.erase(APIPermission::kTab), 0u);
+ EXPECT_EQ(apis.size(), 4u);
+}
+
+TEST(APIPermissionSetTest, CreateUnion) {
+ APIPermission* permission = NULL;
+
+ APIPermissionSet apis1;
+ APIPermissionSet apis2;
+ APIPermissionSet expected_apis;
+ APIPermissionSet result;
+
+ const APIPermissionInfo* permission_info =
+ PermissionsInfo::GetInstance()->GetByID(APIPermission::kSocket);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+
+ // Union with an empty set.
+ apis1.insert(APIPermission::kTab);
+ apis1.insert(APIPermission::kBackground);
+ apis1.insert(permission->Clone());
+ expected_apis.insert(APIPermission::kTab);
+ expected_apis.insert(APIPermission::kBackground);
+ expected_apis.insert(permission);
+
+ APIPermissionSet::Union(apis1, apis2, &result);
+
+ EXPECT_TRUE(apis1.Contains(apis2));
+ EXPECT_TRUE(apis1.Contains(result));
+ EXPECT_FALSE(apis2.Contains(apis1));
+ EXPECT_FALSE(apis2.Contains(result));
+ EXPECT_TRUE(result.Contains(apis1));
+ EXPECT_TRUE(result.Contains(apis2));
+
+ EXPECT_EQ(expected_apis, result);
+
+ // Now use a real second set.
+ apis2.insert(APIPermission::kTab);
+ apis2.insert(APIPermission::kProxy);
+ apis2.insert(APIPermission::kClipboardWrite);
+ apis2.insert(APIPermission::kPlugin);
+
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+ value->Append(new base::StringValue("udp-send-to::8899"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ apis2.insert(permission);
+
+ expected_apis.insert(APIPermission::kTab);
+ expected_apis.insert(APIPermission::kProxy);
+ expected_apis.insert(APIPermission::kClipboardWrite);
+ expected_apis.insert(APIPermission::kPlugin);
+
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ value->Append(new base::StringValue("udp-send-to::8899"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ // Insert a new socket permission which will replace the old one.
+ expected_apis.insert(permission);
+
+ APIPermissionSet::Union(apis1, apis2, &result);
+
+ EXPECT_FALSE(apis1.Contains(apis2));
+ EXPECT_FALSE(apis1.Contains(result));
+ EXPECT_FALSE(apis2.Contains(apis1));
+ EXPECT_FALSE(apis2.Contains(result));
+ EXPECT_TRUE(result.Contains(apis1));
+ EXPECT_TRUE(result.Contains(apis2));
+
+ EXPECT_EQ(expected_apis, result);
+}
+
+TEST(APIPermissionSetTest, CreateIntersection) {
+ APIPermission* permission = NULL;
+
+ APIPermissionSet apis1;
+ APIPermissionSet apis2;
+ APIPermissionSet expected_apis;
+ APIPermissionSet result;
+
+ const APIPermissionInfo* permission_info =
+ PermissionsInfo::GetInstance()->GetByID(APIPermission::kSocket);
+
+ // Intersection with an empty set.
+ apis1.insert(APIPermission::kTab);
+ apis1.insert(APIPermission::kBackground);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ apis1.insert(permission);
+
+ APIPermissionSet::Intersection(apis1, apis2, &result);
+ EXPECT_TRUE(apis1.Contains(result));
+ EXPECT_TRUE(apis2.Contains(result));
+ EXPECT_TRUE(apis1.Contains(apis2));
+ EXPECT_FALSE(apis2.Contains(apis1));
+ EXPECT_FALSE(result.Contains(apis1));
+ EXPECT_TRUE(result.Contains(apis2));
+
+ EXPECT_TRUE(result.empty());
+ EXPECT_EQ(expected_apis, result);
+
+ // Now use a real second set.
+ apis2.insert(APIPermission::kTab);
+ apis2.insert(APIPermission::kProxy);
+ apis2.insert(APIPermission::kClipboardWrite);
+ apis2.insert(APIPermission::kPlugin);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ value->Append(new base::StringValue("udp-send-to::8899"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ apis2.insert(permission);
+
+ expected_apis.insert(APIPermission::kTab);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ expected_apis.insert(permission);
+
+ APIPermissionSet::Intersection(apis1, apis2, &result);
+
+ EXPECT_TRUE(apis1.Contains(result));
+ EXPECT_TRUE(apis2.Contains(result));
+ EXPECT_FALSE(apis1.Contains(apis2));
+ EXPECT_FALSE(apis2.Contains(apis1));
+ EXPECT_FALSE(result.Contains(apis1));
+ EXPECT_FALSE(result.Contains(apis2));
+
+ EXPECT_EQ(expected_apis, result);
+}
+
+TEST(APIPermissionSetTest, CreateDifference) {
+ APIPermission* permission = NULL;
+
+ APIPermissionSet apis1;
+ APIPermissionSet apis2;
+ APIPermissionSet expected_apis;
+ APIPermissionSet result;
+
+ const APIPermissionInfo* permission_info =
+ PermissionsInfo::GetInstance()->GetByID(APIPermission::kSocket);
+
+ // Difference with an empty set.
+ apis1.insert(APIPermission::kTab);
+ apis1.insert(APIPermission::kBackground);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ apis1.insert(permission);
+
+ APIPermissionSet::Difference(apis1, apis2, &result);
+
+ EXPECT_EQ(apis1, result);
+
+ // Now use a real second set.
+ apis2.insert(APIPermission::kTab);
+ apis2.insert(APIPermission::kProxy);
+ apis2.insert(APIPermission::kClipboardWrite);
+ apis2.insert(APIPermission::kPlugin);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+ value->Append(new base::StringValue("udp-send-to::8899"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ apis2.insert(permission);
+
+ expected_apis.insert(APIPermission::kBackground);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ expected_apis.insert(permission);
+
+ APIPermissionSet::Difference(apis1, apis2, &result);
+
+ EXPECT_TRUE(apis1.Contains(result));
+ EXPECT_FALSE(apis2.Contains(result));
+
+ EXPECT_EQ(expected_apis, result);
+
+ // |result| = |apis1| - |apis2| --> |result| intersect |apis2| == empty_set
+ APIPermissionSet result2;
+ APIPermissionSet::Intersection(result, apis2, &result2);
+ EXPECT_TRUE(result2.empty());
+}
+
+TEST(APIPermissionSetTest, IPC) {
+ APIPermission* permission = NULL;
+
+ APIPermissionSet apis;
+ APIPermissionSet expected_apis;
+
+ const APIPermissionInfo* permission_info =
+ PermissionsInfo::GetInstance()->GetByID(APIPermission::kSocket);
+
+ apis.insert(APIPermission::kTab);
+ apis.insert(APIPermission::kBackground);
+ permission = permission_info->CreateAPIPermission();
+ {
+ scoped_ptr<base::ListValue> value(new base::ListValue());
+ value->Append(new base::StringValue("tcp-connect:*.example.com:80"));
+ value->Append(new base::StringValue("udp-bind::8080"));
+ value->Append(new base::StringValue("udp-send-to::8888"));
+ if (!permission->FromValue(value.get())) {
+ NOTREACHED();
+ }
+ }
+ apis.insert(permission);
+
+ EXPECT_NE(apis, expected_apis);
+
+ IPC::Message m;
+ WriteParam(&m, apis);
+ PickleIterator iter(m);
+ CHECK(ReadParam(&m, &iter, &expected_apis));
+ EXPECT_EQ(apis, expected_apis);
+}
+
+TEST(APIPermissionSetTest, ImplicitPermissions) {
+ APIPermissionSet apis;
+ apis.insert(APIPermission::kFileSystemWrite);
+ apis.AddImpliedPermissions();
+
+ EXPECT_EQ(apis.find(APIPermission::kFileSystemWrite)->id(),
+ APIPermission::kFileSystemWrite);
+ EXPECT_EQ(apis.size(), 1u);
+
+ apis.erase(APIPermission::kFileSystemWrite);
+ apis.insert(APIPermission::kFileSystemDirectory);
+ apis.AddImpliedPermissions();
+
+ EXPECT_EQ(apis.find(APIPermission::kFileSystemDirectory)->id(),
+ APIPermission::kFileSystemDirectory);
+ EXPECT_EQ(apis.size(), 1u);
+
+ apis.insert(APIPermission::kFileSystemWrite);
+ apis.AddImpliedPermissions();
+
+ EXPECT_EQ(apis.find(APIPermission::kFileSystemWrite)->id(),
+ APIPermission::kFileSystemWrite);
+ EXPECT_EQ(apis.find(APIPermission::kFileSystemDirectory)->id(),
+ APIPermission::kFileSystemDirectory);
+ EXPECT_EQ(apis.find(APIPermission::kFileSystemWriteDirectory)->id(),
+ APIPermission::kFileSystemWriteDirectory);
+ EXPECT_EQ(apis.size(), 3u);
+}
+
+} // namespace extensions
diff --git a/extensions/common/permissions/permissions_info.cc b/extensions/common/permissions/permissions_info.cc
new file mode 100644
index 0000000..bac3d9c1
--- /dev/null
+++ b/extensions/common/permissions/permissions_info.cc
@@ -0,0 +1,101 @@
+// 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/permissions_info.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "extensions/common/extensions_client.h"
+
+namespace extensions {
+
+static base::LazyInstance<PermissionsInfo> g_permissions_info =
+ LAZY_INSTANCE_INITIALIZER;
+
+// static
+PermissionsInfo* PermissionsInfo::GetInstance() {
+ return g_permissions_info.Pointer();
+}
+
+PermissionsInfo::~PermissionsInfo() {
+ STLDeleteContainerPairSecondPointers(id_map_.begin(), id_map_.end());
+}
+
+const APIPermissionInfo* PermissionsInfo::GetByID(
+ APIPermission::ID id) const {
+ IDMap::const_iterator i = id_map_.find(id);
+ return (i == id_map_.end()) ? NULL : i->second;
+}
+
+const APIPermissionInfo* PermissionsInfo::GetByName(
+ const std::string& name) const {
+ NameMap::const_iterator i = name_map_.find(name);
+ return (i == name_map_.end()) ? NULL : i->second;
+}
+
+APIPermissionSet PermissionsInfo::GetAll() const {
+ APIPermissionSet permissions;
+ for (IDMap::const_iterator i = id_map_.begin(); i != id_map_.end(); ++i)
+ permissions.insert(i->second->id());
+ return permissions;
+}
+
+APIPermissionSet PermissionsInfo::GetAllByName(
+ const std::set<std::string>& permission_names) const {
+ APIPermissionSet permissions;
+ for (std::set<std::string>::const_iterator i = permission_names.begin();
+ i != permission_names.end(); ++i) {
+ const APIPermissionInfo* permission_info = GetByName(*i);
+ if (permission_info)
+ permissions.insert(permission_info->id());
+ }
+ return permissions;
+}
+
+bool PermissionsInfo::HasChildPermissions(const std::string& name) const {
+ NameMap::const_iterator i = name_map_.lower_bound(name + '.');
+ if (i == name_map_.end()) return false;
+ return StartsWithASCII(i->first, name + '.', true);
+}
+
+PermissionsInfo::PermissionsInfo()
+ : hosted_app_permission_count_(0),
+ permission_count_(0) {
+ DCHECK(ExtensionsClient::Get());
+ InitializeWithProvider(ExtensionsClient::Get()->GetPermissionsProvider());
+}
+
+void PermissionsInfo::InitializeWithProvider(
+ const PermissionsProvider& provider) {
+ std::vector<APIPermissionInfo*> permissions = provider.GetAllPermissions();
+ std::vector<PermissionsProvider::AliasInfo> aliases =
+ provider.GetAllAliases();
+
+ for (size_t i = 0; i < permissions.size(); ++i)
+ RegisterPermission(permissions[i]);
+ for (size_t i = 0; i < aliases.size(); ++i)
+ RegisterAlias(aliases[i].name, aliases[i].alias);
+}
+
+void PermissionsInfo::RegisterAlias(
+ const char* name,
+ const char* alias) {
+ DCHECK(ContainsKey(name_map_, name));
+ DCHECK(!ContainsKey(name_map_, alias));
+ name_map_[alias] = name_map_[name];
+}
+
+void PermissionsInfo::RegisterPermission(APIPermissionInfo* permission) {
+ DCHECK(!ContainsKey(id_map_, permission->id()));
+ DCHECK(!ContainsKey(name_map_, permission->name()));
+
+ id_map_[permission->id()] = permission;
+ name_map_[permission->name()] = permission;
+
+ permission_count_++;
+}
+
+} // namespace extensions
diff --git a/extensions/common/permissions/permissions_info.h b/extensions/common/permissions/permissions_info.h
new file mode 100644
index 0000000..9be7e6d
--- /dev/null
+++ b/extensions/common/permissions/permissions_info.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef EXTENSIONS_COMMON_PERMISSIONS_PERMISSIONS_INFO_H_
+#define EXTENSIONS_COMMON_PERMISSIONS_PERMISSIONS_INFO_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permission_message.h"
+#include "extensions/common/permissions/permissions_provider.h"
+
+namespace extensions {
+
+// A global object that holds the extension permission instances and provides
+// methods for accessing them.
+class PermissionsInfo {
+ public:
+ static PermissionsInfo* GetInstance();
+
+ virtual ~PermissionsInfo();
+
+ // Returns the permission with the given |id|, and NULL if it doesn't exist.
+ const APIPermissionInfo* GetByID(APIPermission::ID id) const;
+
+ // Returns the permission with the given |name|, and NULL if none
+ // exists.
+ const APIPermissionInfo* GetByName(const std::string& name) const;
+
+ // Returns a set containing all valid api permission ids.
+ APIPermissionSet GetAll() const;
+
+ // Converts all the permission names in |permission_names| to permission ids.
+ APIPermissionSet GetAllByName(
+ const std::set<std::string>& permission_names) const;
+
+ // Checks if any permissions have names that start with |name| followed by a
+ // period.
+ bool HasChildPermissions(const std::string& name) const;
+
+ // Gets the total number of API permissions.
+ size_t get_permission_count() const { return permission_count_; }
+
+ private:
+ friend struct base::DefaultLazyInstanceTraits<PermissionsInfo>;
+
+ PermissionsInfo();
+
+ // Initializes the permissions from the provider.
+ void InitializeWithProvider(const PermissionsProvider& provider);
+
+ // Registers an |alias| for a given permission |name|.
+ void RegisterAlias(const char* name, const char* alias);
+
+ // Registers a permission with the specified attributes and flags.
+ void RegisterPermission(APIPermissionInfo* permission);
+
+ // Maps permission ids to permissions.
+ typedef std::map<APIPermission::ID, APIPermissionInfo*> IDMap;
+
+ // Maps names and aliases to permissions.
+ typedef std::map<std::string, APIPermissionInfo*> NameMap;
+
+ IDMap id_map_;
+ NameMap name_map_;
+
+ size_t hosted_app_permission_count_;
+ size_t permission_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(PermissionsInfo);
+};
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_PERMISSIONS_PERMISSIONS_INFO_H_