summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/app/generated_resources.grd11
-rw-r--r--chrome/browser/extensions/api/permissions/permissions_api_helpers.cc44
-rw-r--r--chrome/browser/extensions/api/usb/usb_api.cc12
-rw-r--r--chrome/chrome_common.gypi4
-rw-r--r--chrome/common/DEPS1
-rw-r--r--chrome/common/extensions/api/_permission_features.json4
-rw-r--r--chrome/common/extensions/extension.cc10
-rw-r--r--chrome/common/extensions/extension_manifest_constants.cc2
-rw-r--r--chrome/common/extensions/extension_manifest_constants.h1
-rw-r--r--chrome/common/extensions/extension_messages.cc20
-rw-r--r--chrome/common/extensions/extension_messages.h9
-rw-r--r--chrome/common/extensions/extension_unittest.cc27
-rw-r--r--chrome/common/extensions/permissions/api_permission.cc4
-rw-r--r--chrome/common/extensions/permissions/api_permission.h12
-rw-r--r--chrome/common/extensions/permissions/bluetooth_device_permission.cc12
-rw-r--r--chrome/common/extensions/permissions/bluetooth_device_permission.h5
-rw-r--r--chrome/common/extensions/permissions/permission_message.h1
-rw-r--r--chrome/common/extensions/permissions/permission_set_unittest.cc1
-rw-r--r--chrome/common/extensions/permissions/usb_device_permission.cc66
-rw-r--r--chrome/common/extensions/permissions/usb_device_permission.h35
-rw-r--r--chrome/common/extensions/permissions/usb_device_permission_data.cc84
-rw-r--r--chrome/common/extensions/permissions/usb_device_permission_data.h40
-rw-r--r--chrome/renderer/resources/extensions/permissions_custom_bindings.js3
-rw-r--r--chrome/test/data/extensions/optional_only_permission/manifest1.json13
-rw-r--r--chrome/test/data/extensions/optional_only_permission/manifest2.json13
25 files changed, 402 insertions, 32 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index dca7efd..61859fd 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5088,9 +5088,18 @@ Public Exponent (<ph name="PUBLIC_EXPONENT_NUM_BITS">$3<ex>24</ex></ph> bits):
<message name="IDS_EXTENSION_PROMPT_WARNING_BLUETOOTH" desc="Permission string for access to the Bluetooth API.">
Access Bluetooth on your system
</message>
- <message name="IDS_EXTENSION_PROMPT_WARNING_BLUETOOTH_DEVICE" desc="Permission string for access to a specific the Bluetooth device.">
+ <message name="IDS_EXTENSION_PROMPT_WARNING_BLUETOOTH_DEVICE" desc="Permission string for access to a specific Bluetooth device.">
Access the Bluetooth device "<ph name="DEVICE_NAME">$1<ex>Galaxy Nexus</ex></ph>".
</message>
+ <message name="IDS_EXTENSION_PROMPT_WARNING_UNKNOWN_USB_VENDOR" desc="Description used within IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE when a vendor cannot be established for a USB device.">
+ Unknown Company
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_WARNING_UNKNOWN_USB_PRODUCT" desc="Description used within IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE when a product cannot be established for a USB device.">
+ Unknown Device
+ </message>
+ <message name="IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE" desc="Permission string for access to a specific USB device.">
+ Access the USB device "<ph name="PRODUCT_NAME">$1<ex>SoundKnob</ex></ph> (<ph name="VENDOR_NAME">$2<ex>Griffin Technology</ex></ph>)".
+ </message>
<message name="IDS_EXTENSION_PROMPT_WARNING_AUDIO_CAPTURE" desc="Permission string for access to audio capture devices.">
Use your microphone
</message>
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
index 6168852..2400d5c 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_helpers.cc
@@ -4,12 +4,14 @@
#include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
+#include "base/json/json_reader.h"
#include "base/values.h"
#include "chrome/common/extensions/api/permissions.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/permissions/bluetooth_device_permission.h"
#include "chrome/common/extensions/permissions/permission_set.h"
#include "chrome/common/extensions/permissions/permissions_info.h"
+#include "chrome/common/extensions/permissions/usb_device_permission.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/url_pattern_set.h"
@@ -25,12 +27,14 @@ namespace permissions_api_helpers {
namespace {
+const char kInvalidParameter[] =
+ "Invalid argument for permission '*'.";
const char kInvalidOrigin[] =
"Invalid value for origin pattern *: *";
const char kUnknownPermissionError[] =
"'*' is not a recognized permission.";
-const char kNonBluetoothPermissionWithArgument[] =
- "Only the bluetoothDevice permission supports arguments.";
+const char kUnsupportedPermissionId[] =
+ "Only the bluetoothDevice and usbDevice permissions support arguments.";
} // namespace
@@ -68,20 +72,36 @@ scoped_refptr<PermissionSet> UnpackPermissionSet(
std::string permission_name = it->substr(0, delimiter);
std::string permission_arg = it->substr(delimiter + 1);
- // Restrict this to the bluetoothDevice permission for now, to
- // discourage the use of this style of permission spreading until it is
- // better supported.
- const APIPermissionInfo* permission_info = info->GetByID(
- APIPermission::kBluetoothDevice);
- if (permission_name != permission_info->name()) {
- *error = kNonBluetoothPermissionWithArgument;
+ scoped_ptr<base::Value> permission_json(
+ base::JSONReader::Read(permission_arg));
+ if (!permission_json.get()) {
+ *error = ErrorUtils::FormatErrorMessage(kInvalidParameter, *it);
return NULL;
}
- BluetoothDevicePermission *permission =
- new BluetoothDevicePermission(permission_info);
- permission->AddDevicesFromString(permission_arg);
+ APIPermission* permission = NULL;
+
+ // Explicitly check the permissions that accept arguments until the bug
+ // referenced above is fixed.
+ const APIPermissionInfo* bluetooth_device_permission_info =
+ info->GetByID(APIPermission::kBluetoothDevice);
+ const APIPermissionInfo* usb_device_permission_info =
+ info->GetByID(APIPermission::kUsbDevice);
+ if (permission_name == bluetooth_device_permission_info->name()) {
+ permission = new BluetoothDevicePermission(
+ bluetooth_device_permission_info);
+ } else if (permission_name == usb_device_permission_info->name()) {
+ permission = new UsbDevicePermission(usb_device_permission_info);
+ } else {
+ *error = kUnsupportedPermissionId;
+ return NULL;
+ }
+ CHECK(permission);
+ if (!permission->FromValue(permission_json.get())) {
+ *error = ErrorUtils::FormatErrorMessage(kInvalidParameter, *it);
+ return NULL;
+ }
apis.insert(permission);
} else {
const APIPermissionInfo* permission_info = info->GetByName(*it);
diff --git a/chrome/browser/extensions/api/usb/usb_api.cc b/chrome/browser/extensions/api/usb/usb_api.cc
index 9fa26cf..1b2d7b6 100644
--- a/chrome/browser/extensions/api/usb/usb_api.cc
+++ b/chrome/browser/extensions/api/usb/usb_api.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/usb/usb_service.h"
#include "chrome/browser/usb/usb_service_factory.h"
#include "chrome/common/extensions/api/usb.h"
+#include "chrome/common/extensions/permissions/usb_device_permission.h"
namespace BulkTransfer = extensions::api::usb::BulkTransfer;
namespace ClaimInterface = extensions::api::usb::ClaimInterface;
@@ -68,6 +69,8 @@ static const char* kErrorConvertRecipient = "Invalid transfer recipient.";
static const char* kErrorConvertRequestType = "Invalid request type.";
static const char* kErrorMalformedParameters = "Error parsing parameters.";
static const char* kErrorNoDevice = "No such device.";
+static const char* kErrorPermissionDenied =
+ "Permission to access device was denied";
static UsbDevice* device_for_test_ = NULL;
@@ -298,6 +301,15 @@ void UsbFindDevicesFunction::AsyncWorkStart() {
return;
}
+ UsbDevicePermission::CheckParam param(
+ parameters_->vendor_id, parameters_->product_id);
+ if (!GetExtension()->CheckAPIPermissionWithParam(
+ APIPermission::kUsbDevice, &param)) {
+ LOG(WARNING) << "Insufficient permissions to access device.";
+ CompleteWithError(kErrorPermissionDenied);
+ return;
+ }
+
UsbService* const service = UsbServiceFactory::GetInstance()->GetForProfile(
profile());
if (!service) {
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 315f6ca..b74ca0d 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -205,6 +205,10 @@
'common/extensions/permissions/socket_permission.h',
'common/extensions/permissions/socket_permission_data.cc',
'common/extensions/permissions/socket_permission_data.h',
+ 'common/extensions/permissions/usb_device_permission.cc',
+ 'common/extensions/permissions/usb_device_permission.h',
+ 'common/extensions/permissions/usb_device_permission_data.cc',
+ 'common/extensions/permissions/usb_device_permission_data.h',
'common/extensions/request_media_access_permission_helper.cc',
'common/extensions/request_media_access_permission_helper.h',
'common/extensions/unpacker.cc',
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index f709bc3..c85a982 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -1,6 +1,7 @@
include_rules = [
"+chrome/plugin", # For checking whether we're a plugin process.
"+device/bluetooth", # For BluetoothDevicePermission
+ "+device/usb", # For UsbDevicePermission
"+extensions/common",
"+grit", # For generated headers
"+libxml",
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index dea3b0c..7651c34 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -344,6 +344,10 @@
"channel": "dev",
"extension_types": ["platform_app"]
},
+ "usbDevice": {
+ "channel": "dev",
+ "extension_types": ["platform_app"]
+ },
"videoCapture": {
"channel": "stable",
"extension_types": ["platform_app"]
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 97a125c..872ef54 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -1490,6 +1490,16 @@ bool Extension::InitFromValue(int flags, string16* error) {
return false;
}
+ // Check for any permissions that are optional only.
+ for (APIPermissionSet::const_iterator i = api_permissions.begin();
+ i != api_permissions.end(); ++i) {
+ if ((*i)->info()->must_be_optional()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kPermissionMustBeOptional, (*i)->info()->name());
+ return false;
+ }
+ }
+
// TODO(jeremya/kalman) do this via the features system by exposing the
// app.window API to platform apps, with no dependency on any permissions.
// See http://crbug.com/120069.
diff --git a/chrome/common/extensions/extension_manifest_constants.cc b/chrome/common/extensions/extension_manifest_constants.cc
index 43871ac..185f865 100644
--- a/chrome/common/extensions/extension_manifest_constants.cc
+++ b/chrome/common/extensions/extension_manifest_constants.cc
@@ -522,6 +522,8 @@ const char kNoWildCardsInPaths[] =
"Wildcards are not allowed in extent URL pattern paths.";
const char kOneUISurfaceOnly[] =
"Only one of 'browser_action', 'page_action', and 'app' can be specified.";
+const char kPermissionMustBeOptional[] =
+ "Permission '*' must be specified in the optional section of the manifest.";
const char kPermissionNotAllowed[] =
"Access to permission '*' denied.";
const char kPermissionNotAllowedInManifest[] =
diff --git a/chrome/common/extensions/extension_manifest_constants.h b/chrome/common/extensions/extension_manifest_constants.h
index 23001cc..8271c88 100644
--- a/chrome/common/extensions/extension_manifest_constants.h
+++ b/chrome/common/extensions/extension_manifest_constants.h
@@ -339,6 +339,7 @@ namespace extension_manifest_errors {
extern const char kMultipleOverrides[];
extern const char kNoPermissionForFileBrowserHandlerMIMETypes[];
extern const char kNoWildCardsInPaths[];
+ extern const char kPermissionMustBeOptional[];
extern const char kPermissionNotAllowed[];
extern const char kPermissionNotAllowedInManifest[];
extern const char kPlatformAppNeedsManifestVersion2[];
diff --git a/chrome/common/extensions/extension_messages.cc b/chrome/common/extensions/extension_messages.cc
index 95ae472..28fe74b 100644
--- a/chrome/common/extensions/extension_messages.cc
+++ b/chrome/common/extensions/extension_messages.cc
@@ -19,6 +19,7 @@ using extensions::Extension;
using extensions::PermissionSet;
using extensions::SocketPermissionData;
using extensions::URLPatternSet;
+using extensions::UsbDevicePermissionData;
ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params()
: location(Extension::INVALID),
@@ -227,6 +228,25 @@ void ParamTraits<BluetoothDevicePermissionData>::Log(
LogParam(std::string("<BluetoothDevicePermissionData>"), l);
}
+void ParamTraits<UsbDevicePermissionData>::Write(
+ Message* m, const param_type& p) {
+ WriteParam(m, p.GetAsString());
+}
+
+bool ParamTraits<UsbDevicePermissionData>::Read(
+ const Message* m, PickleIterator* iter, param_type* r) {
+ std::string spec;
+ if (!ReadParam(m, iter, &spec))
+ return false;
+
+ return r->Parse(spec);
+}
+
+void ParamTraits<UsbDevicePermissionData>::Log(
+ const param_type& p, std::string* l) {
+ LogParam(std::string("<UsbDevicePermissionData>"), l);
+}
+
void ParamTraits<ExtensionMsg_Loaded_Params>::Write(Message* m,
const param_type& p) {
WriteParam(m, p.location);
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 6058fbf..86210c6 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -12,6 +12,7 @@
#include "chrome/common/extensions/permissions/bluetooth_device_permission_data.h"
#include "chrome/common/extensions/permissions/permission_set.h"
#include "chrome/common/extensions/permissions/socket_permission_data.h"
+#include "chrome/common/extensions/permissions/usb_device_permission_data.h"
#include "chrome/common/view_type.h"
#include "chrome/common/web_apps.h"
#include "content/public/common/common_param_traits.h"
@@ -210,6 +211,14 @@ struct ParamTraits<extensions::BluetoothDevicePermissionData> {
static void Log(const param_type& p, std::string* l);
};
+template <>
+struct ParamTraits<extensions::UsbDevicePermissionData> {
+ typedef extensions::UsbDevicePermissionData param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
} // namespace IPC
#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_MESSAGES_H_
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index 7d26279..4c899f6 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -21,6 +21,7 @@
#include "chrome/common/extensions/permissions/api_permission.h"
#include "chrome/common/extensions/permissions/permission_set.h"
#include "chrome/common/extensions/permissions/socket_permission.h"
+#include "chrome/common/extensions/permissions/usb_device_permission.h"
#include "chrome/common/url_constants.h"
#include "extensions/common/error_utils.h"
#include "googleurl/src/gurl.h"
@@ -40,6 +41,7 @@ using extensions::Feature;
using extensions::PermissionSet;
using extensions::SocketPermission;
using extensions::URLPatternSet;
+using extensions::UsbDevicePermission;
namespace keys = extension_manifest_keys;
namespace values = extension_manifest_values;
@@ -1246,6 +1248,31 @@ TEST(ExtensionTest, DontSyncDefault) {
EXPECT_FALSE(extension_default->IsSyncable());
}
+TEST(ExtensionTest, OptionalOnlyPermission) {
+ // Set feature current channel to dev because the only permission that must
+ // be optional (usbDevice) is only available on dev channel.
+ Feature::ScopedCurrentChannel scoped_channel(
+ chrome::VersionInfo::CHANNEL_DEV);
+
+ scoped_refptr<Extension> extension;
+ std::string error;
+ extension = LoadManifestUnchecked("optional_only_permission",
+ "manifest1.json",
+ Extension::INTERNAL, Extension::NO_FLAGS,
+ &error);
+ EXPECT_TRUE(extension == NULL);
+ ASSERT_EQ(ErrorUtils::FormatErrorMessage(
+ errors::kPermissionMustBeOptional, "usbDevice"), error);
+
+ error.clear();
+ extension = LoadManifestUnchecked("optional_only_permission",
+ "manifest2.json",
+ Extension::INTERNAL, Extension::NO_FLAGS,
+ &error);
+ EXPECT_TRUE(extension != NULL);
+ EXPECT_TRUE(error.empty());
+}
+
// These last 2 tests don't make sense on Chrome OS, where extension plugins
// are not allowed.
#if !defined(OS_CHROMEOS)
diff --git a/chrome/common/extensions/permissions/api_permission.cc b/chrome/common/extensions/permissions/api_permission.cc
index 5278fa1..03b23cd 100644
--- a/chrome/common/extensions/permissions/api_permission.cc
+++ b/chrome/common/extensions/permissions/api_permission.cc
@@ -7,6 +7,7 @@
#include "chrome/common/extensions/permissions/bluetooth_device_permission.h"
#include "chrome/common/extensions/permissions/permissions_info.h"
#include "chrome/common/extensions/permissions/socket_permission.h"
+#include "chrome/common/extensions/permissions/usb_device_permission.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
@@ -339,6 +340,9 @@ void APIPermissionInfo::RegisterAllPermissions(
{ APIPermission::kUsb, "usb", kFlagNone,
IDS_EXTENSION_PROMPT_WARNING_USB,
PermissionMessage::kUsb },
+ { APIPermission::kUsbDevice, "usbDevice",
+ kFlagMustBeOptional, 0, PermissionMessage::kNone,
+ &::CreateAPIPermission<UsbDevicePermission> },
{ APIPermission::kSystemIndicator, "systemIndicator", kFlagNone,
IDS_EXTENSION_PROMPT_WARNING_SYSTEM_INDICATOR,
PermissionMessage::kSystemIndicator },
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index de5eb92..d714f3d 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -106,6 +106,7 @@ class APIPermission {
kTtsEngine,
kUnlimitedStorage,
kUsb,
+ kUsbDevice,
kVideoCapture,
kWallpaperPrivate,
kWebNavigation,
@@ -211,7 +212,10 @@ class APIPermissionInfo {
kFlagImpliesFullURLAccess = 1 << 1,
// Indicates that extensions cannot specify the permission as optional.
- kFlagCannotBeOptional = 1 << 3
+ kFlagCannotBeOptional = 1 << 3,
+
+ // Indicates that extensions cannot specify the permission as optional.
+ kFlagMustBeOptional = 1 << 4
};
typedef APIPermission* (*APIPermissionConstructor)(const APIPermissionInfo*);
@@ -251,6 +255,12 @@ class APIPermissionInfo {
return (flags_ & kFlagCannotBeOptional) == 0;
}
+ // Returns true if this permission must be added and removed via the
+ // optional permissions extension API.
+ bool must_be_optional() const {
+ return (flags_ & kFlagMustBeOptional) != 0;
+ }
+
private:
// Instances should only be constructed from within PermissionsInfo.
friend class PermissionsInfo;
diff --git a/chrome/common/extensions/permissions/bluetooth_device_permission.cc b/chrome/common/extensions/permissions/bluetooth_device_permission.cc
index 83e2bd6..bc35443 100644
--- a/chrome/common/extensions/permissions/bluetooth_device_permission.cc
+++ b/chrome/common/extensions/permissions/bluetooth_device_permission.cc
@@ -4,12 +4,10 @@
#include "chrome/common/extensions/permissions/bluetooth_device_permission.h"
-#include <algorithm>
#include <string>
#include <vector>
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -38,16 +36,6 @@ BluetoothDevicePermission::BluetoothDevicePermission(
BluetoothDevicePermission::~BluetoothDevicePermission() {
}
-void BluetoothDevicePermission::AddDevicesFromString(
- const std::string &devices_string) {
- std::vector<std::string> devices;
- Tokenize(devices_string, kSeparator, &devices);
- for (std::vector<std::string>::const_iterator i = devices.begin();
- i != devices.end(); ++i) {
- data_set_.insert(BluetoothDevicePermissionData(*i));
- }
-}
-
std::string BluetoothDevicePermission::ToString() const {
std::vector<std::string> parts;
parts.push_back(name());
diff --git a/chrome/common/extensions/permissions/bluetooth_device_permission.h b/chrome/common/extensions/permissions/bluetooth_device_permission.h
index d12cada..e708ec8 100644
--- a/chrome/common/extensions/permissions/bluetooth_device_permission.h
+++ b/chrome/common/extensions/permissions/bluetooth_device_permission.h
@@ -5,7 +5,6 @@
#ifndef CHROME_COMMON_EXTENSIONS_PERMISSIONS_BLUETOOTH_DEVICE_PERMISSION_H_
#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_BLUETOOTH_DEVICE_PERMISSION_H_
-#include <set>
#include <string>
#include "chrome/common/extensions/permissions/api_permission.h"
@@ -30,10 +29,6 @@ class BluetoothDevicePermission
explicit BluetoothDevicePermission(const APIPermissionInfo* info);
virtual ~BluetoothDevicePermission();
- // Adds BluetoothDevices from |devices| to the set of allowed devices.
- // |devices| should be a string of Bluetooth device addresses separated by |.
- void AddDevicesFromString(const std::string &devices_string);
-
// APIPermission overrides
virtual std::string ToString() const OVERRIDE;
virtual bool ManifestEntryForbidden() const OVERRIDE;
diff --git a/chrome/common/extensions/permissions/permission_message.h b/chrome/common/extensions/permissions/permission_message.h
index 94a73e1..597fc36 100644
--- a/chrome/common/extensions/permissions/permission_message.h
+++ b/chrome/common/extensions/permissions/permission_message.h
@@ -55,6 +55,7 @@ class PermissionMessage {
kUsb,
kSystemIndicator,
kBluetoothDevice,
+ kUsbDevice,
kEnumBoundary
};
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 8fb5895..0f01d71 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -730,6 +730,7 @@ TEST(PermissionsTest, PermissionMessages) {
// Platform apps.
skip.insert(APIPermission::kFileSystem);
skip.insert(APIPermission::kSocket);
+ skip.insert(APIPermission::kUsbDevice);
PermissionsInfo* info = PermissionsInfo::GetInstance();
APIPermissionSet permissions = info->GetAll();
diff --git a/chrome/common/extensions/permissions/usb_device_permission.cc b/chrome/common/extensions/permissions/usb_device_permission.cc
new file mode 100644
index 0000000..cc13b93
--- /dev/null
+++ b/chrome/common/extensions/permissions/usb_device_permission.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 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 "chrome/common/extensions/permissions/usb_device_permission.h"
+
+#include <set>
+#include <string>
+
+#include "base/logging.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/extensions/permissions/permissions_info.h"
+#include "device/usb/usb_ids.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+UsbDevicePermission::UsbDevicePermission(
+ const APIPermissionInfo* info)
+ : SetDisjunctionPermission<UsbDevicePermissionData,
+ UsbDevicePermission>(info) {
+}
+
+UsbDevicePermission::~UsbDevicePermission() {
+}
+
+PermissionMessages UsbDevicePermission::GetMessages() const {
+ DCHECK(HasMessages());
+ PermissionMessages result;
+
+ for (std::set<UsbDevicePermissionData>::const_iterator i =
+ data_set_.begin(); i != data_set_.end(); ++i) {
+
+ const char* vendor = device::UsbIds::GetVendorName(i->vendor_id());
+ string16 vendor_name;
+ if (vendor) {
+ vendor_name = ASCIIToUTF16(vendor);
+ } else {
+ vendor_name = l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_UNKNOWN_USB_VENDOR);
+ }
+
+ const char* product =
+ device::UsbIds::GetProductName(i->vendor_id(), i->product_id());
+ string16 product_name;
+ if (product) {
+ product_name = ASCIIToUTF16(product);
+ } else {
+ product_name = l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_UNKNOWN_USB_PRODUCT);
+ }
+
+ result.push_back(PermissionMessage(
+ PermissionMessage::kUsbDevice,
+ l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE,
+ product_name,
+ vendor_name)));
+ }
+
+ return result;
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/permissions/usb_device_permission.h b/chrome/common/extensions/permissions/usb_device_permission.h
new file mode 100644
index 0000000..77ea15d
--- /dev/null
+++ b/chrome/common/extensions/permissions/usb_device_permission.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 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 CHROME_COMMON_EXTENSIONS_PERMISSIONS_USB_DEVICE_PERMISSION_H_
+#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_USB_DEVICE_PERMISSION_H_
+
+#include "base/basictypes.h"
+#include "chrome/common/extensions/permissions/api_permission.h"
+#include "chrome/common/extensions/permissions/set_disjunction_permission.h"
+#include "chrome/common/extensions/permissions/usb_device_permission_data.h"
+
+namespace extensions {
+
+class UsbDevicePermission
+ : public SetDisjunctionPermission<UsbDevicePermissionData,
+ UsbDevicePermission> {
+ public:
+ struct CheckParam : public APIPermission::CheckParam {
+ CheckParam(uint16 vendor_id, uint16 product_id)
+ : vendor_id(vendor_id), product_id(product_id) {}
+ const uint16 vendor_id;
+ const uint16 product_id;
+ };
+
+ explicit UsbDevicePermission(const APIPermissionInfo* info);
+ virtual ~UsbDevicePermission();
+
+ // APIPermission overrides
+ virtual PermissionMessages GetMessages() const OVERRIDE;
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_PERMISSIONS_USB_DEVICE_PERMISSION_H_
diff --git a/chrome/common/extensions/permissions/usb_device_permission_data.cc b/chrome/common/extensions/permissions/usb_device_permission_data.cc
new file mode 100644
index 0000000..087d628
--- /dev/null
+++ b/chrome/common/extensions/permissions/usb_device_permission_data.cc
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 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 "chrome/common/extensions/permissions/usb_device_permission_data.h"
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/string_number_conversions.h"
+#include "base/string_split.h"
+#include "chrome/common/extensions/permissions/api_permission.h"
+#include "chrome/common/extensions/permissions/usb_device_permission.h"
+
+namespace {
+
+const char kColon = ':';
+
+} // namespace
+
+namespace extensions {
+
+UsbDevicePermissionData::UsbDevicePermissionData()
+ : vendor_id_(0), product_id_(0), spec_("") {
+}
+
+UsbDevicePermissionData::UsbDevicePermissionData(uint16 vendor_id,
+ uint16 product_id)
+ : vendor_id_(vendor_id), product_id_(product_id), spec_("") {
+}
+
+bool UsbDevicePermissionData::Check(
+ const APIPermission::CheckParam* param) const {
+ if (!param)
+ return false;
+ const UsbDevicePermission::CheckParam& specific_param =
+ *static_cast<const UsbDevicePermission::CheckParam*>(param);
+ return vendor_id_ == specific_param.vendor_id &&
+ product_id_ == specific_param.product_id;
+}
+
+bool UsbDevicePermissionData::Parse(const std::string& spec) {
+ spec_.clear();
+
+ std::vector<std::string> tokens;
+ base::SplitStringDontTrim(spec, kColon, &tokens);
+ if (tokens.size() != 2)
+ return false;
+
+ int temp;
+ if (!base::StringToInt(tokens[0], &temp) || temp < 0 || temp > kuint16max)
+ return false;
+ vendor_id_ = temp;
+
+ if (!base::StringToInt(tokens[1], &temp) || temp < 0 || temp > kuint16max)
+ return false;
+ product_id_ = temp;
+
+ return true;
+}
+
+const std::string& UsbDevicePermissionData::GetAsString() const {
+ if (spec_.empty()) {
+ spec_.append(base::IntToString(vendor_id_));
+ spec_.append(1, kColon);
+ spec_.append(base::IntToString(product_id_));
+ }
+ return spec_;
+}
+
+bool UsbDevicePermissionData::operator<(
+ const UsbDevicePermissionData& rhs) const {
+ if (vendor_id_ == rhs.vendor_id_)
+ return product_id_ < rhs.product_id_;
+ return vendor_id_ < rhs.vendor_id_;
+}
+
+bool UsbDevicePermissionData::operator==(
+ const UsbDevicePermissionData& rhs) const {
+ return vendor_id_ == rhs.vendor_id_ && product_id_ == rhs.product_id_;
+}
+
+} // namespace extensions
diff --git a/chrome/common/extensions/permissions/usb_device_permission_data.h b/chrome/common/extensions/permissions/usb_device_permission_data.h
new file mode 100644
index 0000000..a83976e
--- /dev/null
+++ b/chrome/common/extensions/permissions/usb_device_permission_data.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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 CHROME_COMMON_EXTENSIONS_PERMISSIONS_USB_DEVICE_PERMISSION_DATA_H_
+#define CHROME_COMMON_EXTENSIONS_PERMISSIONS_USB_DEVICE_PERMISSION_DATA_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "chrome/common/extensions/permissions/api_permission.h"
+
+namespace extensions {
+
+// A pattern that can be used to match a USB device permission.
+// Should be of the format: vendorId:productId, where both vendorId and
+// productId are decimal strings representing uint16 values.
+class UsbDevicePermissionData {
+ public:
+ UsbDevicePermissionData();
+ UsbDevicePermissionData(uint16 vendor_id, uint16 product_id);
+
+ bool Check(const APIPermission::CheckParam* param) const;
+ bool Parse(const std::string& spec);
+ const std::string& GetAsString() const;
+
+ bool operator<(const UsbDevicePermissionData& rhs) const;
+ bool operator==(const UsbDevicePermissionData& rhs) const;
+
+ uint16 vendor_id() const { return vendor_id_; }
+ uint16 product_id() const { return product_id_; }
+
+ private:
+ uint16 vendor_id_;
+ uint16 product_id_;
+ mutable std::string spec_;
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_PERMISSIONS_USB_DEVICE_PERMISSION_DATA_H_
diff --git a/chrome/renderer/resources/extensions/permissions_custom_bindings.js b/chrome/renderer/resources/extensions/permissions_custom_bindings.js
index 82a0b0a..faf03f8 100644
--- a/chrome/renderer/resources/extensions/permissions_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/permissions_custom_bindings.js
@@ -27,7 +27,8 @@ chromeHidden.registerCustomHook('permissions', function(api) {
if (keys.length != 1) {
throw new Error("Too many keys in object-style permission.");
}
- arguments[0].permissions[i] = keys[0] + '|' + a[keys[0]];
+ arguments[0].permissions[i] = keys[0] + '|' +
+ JSON.stringify(a[keys[0]]);
}
}
diff --git a/chrome/test/data/extensions/optional_only_permission/manifest1.json b/chrome/test/data/extensions/optional_only_permission/manifest1.json
new file mode 100644
index 0000000..d29bdc1
--- /dev/null
+++ b/chrome/test/data/extensions/optional_only_permission/manifest1.json
@@ -0,0 +1,13 @@
+{
+ "name": "optional only permission test",
+ "version": "1.0",
+ "manifest_version": 2,
+ "app": {
+ "background": {
+ "scripts": ["main.js"]
+ }
+ },
+ "permissions": [
+ {"usbDevice":["0:0"]}
+ ]
+}
diff --git a/chrome/test/data/extensions/optional_only_permission/manifest2.json b/chrome/test/data/extensions/optional_only_permission/manifest2.json
new file mode 100644
index 0000000..bd12900
--- /dev/null
+++ b/chrome/test/data/extensions/optional_only_permission/manifest2.json
@@ -0,0 +1,13 @@
+{
+ "name": "optional only permission test",
+ "version": "1.0",
+ "manifest_version": 2,
+ "app": {
+ "background": {
+ "scripts": ["main.js"]
+ }
+ },
+ "optional_permissions": [
+ {"usbDevice":["123:456"]}
+ ]
+}