| Index: chrome/common/extensions/api/sockets/sockets_handler.cc
|
| diff --git a/chrome/common/extensions/api/sockets/sockets_handler.cc b/chrome/common/extensions/api/sockets/sockets_handler.cc
|
| index a1b51c21e3a0974a19e75b779742eb714ed162a5..3b5e0637e875e0b98492d1742240480b4235de17 100644
|
| --- a/chrome/common/extensions/api/sockets/sockets_handler.cc
|
| +++ b/chrome/common/extensions/api/sockets/sockets_handler.cc
|
| @@ -9,11 +9,16 @@
|
| #include "base/values.h"
|
| #include "chrome/common/extensions/api/manifest_types.h"
|
| #include "chrome/common/extensions/extension.h"
|
| +#include "chrome/common/extensions/extension_messages.h"
|
| #include "chrome/common/extensions/permissions/permissions_data.h"
|
| #include "chrome/common/extensions/permissions/socket_permission_data.h"
|
| #include "extensions/common/error_utils.h"
|
| #include "extensions/common/manifest_constants.h"
|
| #include "extensions/common/permissions/api_permission_set.h"
|
| +#include "grit/generated_resources.h"
|
| +#include "ipc/ipc_message.h"
|
| +#include "ipc/ipc_message_utils.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
|
|
| namespace extensions {
|
|
|
| @@ -24,6 +29,187 @@ const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'";
|
| namespace keys = extensions::manifest_keys;
|
| namespace errors = sockets_errors;
|
| using api::manifest_types::Sockets;
|
| +using content::SocketPermissionRequest;
|
| +
|
| +// TODO(rpaquay): Unit test for all this class (Diff, Union, etc).
|
| +class SocketsManifestPermission : public ManifestPermission {
|
| + public:
|
| + SocketsManifestPermission() {
|
| + }
|
| +
|
| + explicit SocketsManifestPermission(scoped_ptr<SocketsManifestData> data)
|
| + : data_(data.Pass()) {
|
| + }
|
| +
|
| + virtual std::string name() const OVERRIDE {
|
| + return keys::kSockets;
|
| + }
|
| +
|
| + virtual std::string id() const OVERRIDE {
|
| + return name();
|
| + }
|
| +
|
| + // Returns true if this permission has any PermissionMessages.
|
| + virtual bool HasMessages() const OVERRIDE {
|
| + if (!data_)
|
| + return false;
|
| +
|
| + return data_->HasMessages();
|
| + }
|
| +
|
| + // Returns the localized permission messages of this permission.
|
| + virtual PermissionMessages GetMessages() const OVERRIDE {
|
| + if (!data_)
|
| + return PermissionMessages();
|
| + return data_->GetPermissionMessages();
|
| + }
|
| +
|
| + // Parses the ManifestPermission from |value|. Returns false if error happens.
|
| + virtual bool FromValue(const base::Value* value) OVERRIDE {
|
| + if (!value)
|
| + return false;
|
| +
|
| + std::vector<InstallWarning> warnings;
|
| + string16 error;
|
| + scoped_ptr<SocketsManifestData> data(
|
| + SocketsManifestData::FromValue(*value, &warnings, &error));
|
| +
|
| + if (!data)
|
| + return false;
|
| +
|
| + data_ = data.Pass();
|
| + return true;
|
| + }
|
| +
|
| + // Stores this into a new created |value|.
|
| + virtual scoped_ptr<base::Value> ToValue() const OVERRIDE {
|
| + if (!data_) {
|
| + return Sockets().ToValue();
|
| + }
|
| +
|
| + return data_->ToValue();
|
| + }
|
| +
|
| + // Clones this.
|
| + virtual ManifestPermission* Clone() const OVERRIDE {
|
| + if (!data_)
|
| + return new SocketsManifestPermission();
|
| +
|
| + scoped_ptr<SocketsManifestData> clone_data(data_->Clone());
|
| + return new SocketsManifestPermission(clone_data.Pass());
|
| + }
|
| +
|
| + // Returns a new API permission which equals this - |rhs|.
|
| + virtual ManifestPermission* Diff(const ManifestPermission* rhs)
|
| + const OVERRIDE {
|
| + const SocketsManifestPermission* other =
|
| + static_cast<const SocketsManifestPermission*>(rhs);
|
| +
|
| + if (!data_)
|
| + return new SocketsManifestPermission();
|
| +
|
| + if (!other->data_)
|
| + return Clone();
|
| +
|
| + scoped_ptr<SocketsManifestData> data(data_->Diff(other->data_.get()));
|
| + return new SocketsManifestPermission(data.Pass());
|
| + }
|
| +
|
| + // Returns a new API permission which equals the union of this and |rhs|.
|
| + virtual ManifestPermission* Union(const ManifestPermission* rhs)
|
| + const OVERRIDE {
|
| + const SocketsManifestPermission* other =
|
| + static_cast<const SocketsManifestPermission*>(rhs);
|
| +
|
| + if (!data_)
|
| + return other->Clone();
|
| +
|
| + if (!other->data_)
|
| + return Clone();
|
| +
|
| + scoped_ptr<SocketsManifestData> data(data_->Union(other->data_.get()));
|
| + return new SocketsManifestPermission(data.Pass());
|
| + }
|
| +
|
| + // Returns a new API permission which equals the intersect of this and |rhs|.
|
| + virtual ManifestPermission* Intersect(const ManifestPermission* rhs)
|
| + const OVERRIDE {
|
| + const SocketsManifestPermission* other =
|
| + static_cast<const SocketsManifestPermission*>(rhs);
|
| +
|
| + if (!data_)
|
| + return new SocketsManifestPermission();
|
| +
|
| + if (!other->data_)
|
| + return new SocketsManifestPermission();
|
| +
|
| + scoped_ptr<SocketsManifestData> data(data_->Intersect(other->data_.get()));
|
| + return new SocketsManifestPermission(data.Pass());
|
| + }
|
| +
|
| + // Returns true if |rhs| is a subset of this.
|
| + virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE {
|
| + const SocketsManifestPermission* other =
|
| + static_cast<const SocketsManifestPermission*>(rhs);
|
| +
|
| + if (!data_)
|
| + return !other->data_;
|
| +
|
| + if (!other->data_)
|
| + return true;
|
| +
|
| + return data_->Contains(other->data_.get());
|
| + }
|
| +
|
| + // Returns true if |rhs| is equal to this.
|
| + virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE {
|
| + const SocketsManifestPermission* other =
|
| + static_cast<const SocketsManifestPermission*>(rhs);
|
| +
|
| + if (!data_)
|
| + return !other->data_;
|
| +
|
| + if (!other->data_)
|
| + return false;
|
| +
|
| + return data_->Equal(other->data_.get());
|
| + }
|
| +
|
| + // IPC functions
|
| + // Writes this into the given IPC message |m|.
|
| + virtual void Write(IPC::Message* m) const OVERRIDE {
|
| + bool has_data = !!data_;
|
| + IPC::WriteParam(m, has_data);
|
| + if (has_data) {
|
| + data_->Write(m);
|
| + }
|
| + }
|
| +
|
| + // Reads from the given IPC message |m|.
|
| + virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE {
|
| + data_.reset();
|
| +
|
| + bool has_data;
|
| + bool result = IPC::ReadParam(m, iter, &has_data);
|
| + if (!result)
|
| + return result;
|
| +
|
| + if (!has_data)
|
| + return true;
|
| +
|
| + data_.reset(new SocketsManifestData());
|
| + return data_->Read(m, iter);
|
| + }
|
| +
|
| + // Logs this permission.
|
| + virtual void Log(std::string* log) const OVERRIDE {
|
| + if (data_)
|
| + data_->Log(log);
|
| + }
|
| +
|
| + private:
|
| + scoped_ptr<SocketsManifestData> data_;
|
| +};
|
|
|
| SocketsHandler::SocketsHandler() {}
|
|
|
| @@ -45,11 +231,25 @@ bool SocketsHandler::Parse(Extension* extension, string16* error) {
|
| return true;
|
| }
|
|
|
| +ManifestPermission* SocketsHandler::CreatePermission() {
|
| + return new SocketsManifestPermission();
|
| +}
|
| +
|
| +ManifestPermission* SocketsHandler::CreateInitialRequiredPermission(
|
| + const Extension* extension) {
|
| + SocketsManifestData* data = SocketsManifestData::Get(extension);
|
| + if (data) {
|
| + return new SocketsManifestPermission(
|
| + scoped_ptr<SocketsManifestData>(data->Clone()).Pass());
|
| + }
|
| + return new SocketsManifestPermission();
|
| +}
|
| +
|
| const std::vector<std::string> SocketsHandler::Keys() const {
|
| return SingleKey(manifest_keys::kSockets);
|
| }
|
|
|
| -SocketsManifestData::SocketsManifestData() {}
|
| +SocketsManifestData::SocketsManifestData() : kinds_(kNone) {}
|
| SocketsManifestData::~SocketsManifestData() {}
|
|
|
| // static
|
| @@ -63,7 +263,7 @@ bool SocketsManifestData::CheckRequest(
|
| const Extension* extension,
|
| const content::SocketPermissionRequest& request) {
|
| SocketsManifestData* data = SocketsManifestData::Get(extension);
|
| - if (data == NULL)
|
| + if (!data)
|
| return false;
|
|
|
| return data->CheckRequestImpl(extension, request);
|
| @@ -80,6 +280,7 @@ scoped_ptr<SocketsManifestData> SocketsManifestData::FromValue(
|
|
|
| scoped_ptr<SocketsManifestData> result(new SocketsManifestData());
|
| if (sockets->udp) {
|
| + result->kinds_ |= kUdpPermission;
|
| if (!ParseHostPattern(result.get(),
|
| content::SocketPermissionRequest::UDP_BIND,
|
| sockets->udp->bind,
|
| @@ -100,6 +301,7 @@ scoped_ptr<SocketsManifestData> SocketsManifestData::FromValue(
|
| }
|
| }
|
| if (sockets->tcp) {
|
| + result->kinds_ |= kTcpPermission;
|
| if (!ParseHostPattern(result.get(),
|
| content::SocketPermissionRequest::TCP_CONNECT,
|
| sockets->tcp->connect,
|
| @@ -108,6 +310,7 @@ scoped_ptr<SocketsManifestData> SocketsManifestData::FromValue(
|
| }
|
| }
|
| if (sockets->tcp_server) {
|
| + result->kinds_ |= kTcpServerPermission;
|
| if (!ParseHostPattern(result.get(),
|
| content::SocketPermissionRequest::TCP_LISTEN,
|
| sockets->tcp_server->listen,
|
| @@ -118,6 +321,29 @@ scoped_ptr<SocketsManifestData> SocketsManifestData::FromValue(
|
| return result.Pass();
|
| }
|
|
|
| +scoped_ptr<base::Value> SocketsManifestData::ToValue() const {
|
| + Sockets sockets;
|
| + if (has_udp()) {
|
| + sockets.udp.reset(new Sockets::Udp());
|
| + sockets.udp->bind = CreateHostPattern(SocketPermissionRequest::UDP_BIND);
|
| + sockets.udp->send = CreateHostPattern(SocketPermissionRequest::UDP_SEND_TO);
|
| + sockets.udp->multicast_membership =
|
| + CreateHostPattern(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP);
|
| + }
|
| + if (has_tcp()) {
|
| + sockets.tcp.reset(new Sockets::Tcp());
|
| + sockets.tcp->connect =
|
| + CreateHostPattern(SocketPermissionRequest::TCP_CONNECT);
|
| + }
|
| + if (has_tcp_server()) {
|
| + sockets.tcp_server.reset(new Sockets::TcpServer());
|
| + sockets.tcp_server->listen =
|
| + CreateHostPattern(SocketPermissionRequest::TCP_LISTEN);
|
| + }
|
| +
|
| + return sockets.ToValue().Pass();
|
| +}
|
| +
|
| // static
|
| bool SocketsManifestData::ParseHostPattern(
|
| SocketsManifestData* manifest_data,
|
| @@ -137,6 +363,19 @@ bool SocketsManifestData::ParseHostPattern(
|
| return true;
|
| }
|
|
|
| +scoped_ptr<std::string> SocketsManifestData::CreateHostPattern(
|
| + content::SocketPermissionRequest::OperationType operation_type) const {
|
| + scoped_ptr<std::string> result;
|
| + for (SocketsManifestData::SocketPermissionEntrySet::const_iterator it =
|
| + entries().begin(); it != entries().end() ; ++it) {
|
| + if (it->pattern().type == operation_type) {
|
| + result.reset(new std::string(it->GetHostPatternAsString()));
|
| + break;
|
| + }
|
| + }
|
| + return result.Pass();
|
| +}
|
| +
|
| void SocketsManifestData::AddPermission(const SocketPermissionEntry& entry) {
|
| permissions_.insert(entry);
|
| }
|
| @@ -144,7 +383,7 @@ void SocketsManifestData::AddPermission(const SocketPermissionEntry& entry) {
|
| bool SocketsManifestData::CheckRequestImpl(
|
| const Extension* extension,
|
| const content::SocketPermissionRequest& request) {
|
| - for (PermissionSet::const_iterator it = permissions_.begin();
|
| + for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
|
| it != permissions_.end(); ++it) {
|
| if (it->Check(request))
|
| return true;
|
| @@ -152,4 +391,167 @@ bool SocketsManifestData::CheckRequestImpl(
|
| return false;
|
| }
|
|
|
| +bool SocketsManifestData::HasMessages() const {
|
| + bool is_empty = permissions_.empty() && (kinds_ == kNone);
|
| + return !is_empty;
|
| +}
|
| +
|
| +PermissionMessages SocketsManifestData::GetPermissionMessages() const {
|
| + // TODO(rpaquay): This function and callees is (almost) a copy/paste
|
| + // from |extensions::SocketPermission|.
|
| + PermissionMessages result;
|
| + if (!AddAnyHostMessage(result)) {
|
| + AddSpecificHostMessage(result);
|
| + AddSubdomainHostMessage(result);
|
| + }
|
| + AddNetworkListMessage(result);
|
| + return result;
|
| +}
|
| +
|
| +SocketsManifestData* SocketsManifestData::Diff(const SocketsManifestData* rhs)
|
| + const {
|
| + scoped_ptr<SocketsManifestData> data(new SocketsManifestData());
|
| + std::set_difference(
|
| + permissions_.begin(), permissions_.end(),
|
| + rhs->permissions_.begin(), rhs->permissions_.end(),
|
| + std::inserter<SocketPermissionEntrySet>(
|
| + data->permissions_, data->permissions_.begin()));
|
| +
|
| + data->kinds_ = (kinds_ & (~rhs->kinds_));
|
| + return data.release();
|
| +}
|
| +
|
| +SocketsManifestData* SocketsManifestData::Union(const SocketsManifestData* rhs)
|
| + const {
|
| + scoped_ptr<SocketsManifestData> data(new SocketsManifestData());
|
| + std::set_union(
|
| + permissions_.begin(), permissions_.end(),
|
| + rhs->permissions_.begin(), rhs->permissions_.end(),
|
| + std::inserter<SocketPermissionEntrySet>(
|
| + data->permissions_, data->permissions_.begin()));
|
| +
|
| + data->kinds_ = (kinds_ | rhs->kinds_);
|
| + return data.release();
|
| +}
|
| +
|
| +SocketsManifestData* SocketsManifestData::Intersect(
|
| + const SocketsManifestData* rhs) const {
|
| + scoped_ptr<SocketsManifestData> data(new SocketsManifestData());
|
| + std::set_intersection(
|
| + permissions_.begin(), permissions_.end(),
|
| + rhs->permissions_.begin(), rhs->permissions_.end(),
|
| + std::inserter<SocketPermissionEntrySet>(
|
| + data->permissions_, data->permissions_.begin()));
|
| +
|
| + data->kinds_ = (kinds_ & rhs->kinds_);
|
| + return data.release();
|
| +}
|
| +
|
| +bool SocketsManifestData::Contains(const SocketsManifestData* rhs) const {
|
| + return std::includes(
|
| + entries().begin(), entries().end(),
|
| + rhs->entries().begin(), rhs->entries().end()) &&
|
| + ((kinds_ | rhs->kinds_) == kinds_);
|
| +}
|
| +
|
| +bool SocketsManifestData::Equal(const SocketsManifestData* rhs) const {
|
| + return (permissions_ == rhs->permissions_) &&
|
| + (kinds_ == rhs->kinds_);
|
| +}
|
| +
|
| +SocketsManifestData* SocketsManifestData::Clone() const {
|
| + scoped_ptr<SocketsManifestData> result(new SocketsManifestData());
|
| + result->permissions_ = permissions_;
|
| + result->kinds_ = kinds_;
|
| + return result.release();
|
| +}
|
| +
|
| +void SocketsManifestData::Write(IPC::Message* m) const {
|
| + IPC::WriteParam(m, permissions_);
|
| + IPC::WriteParam(m, kinds_);
|
| +}
|
| +
|
| +bool SocketsManifestData::Read(const IPC::Message* m, PickleIterator* iter) {
|
| + return IPC::ReadParam(m, iter, &permissions_) &&
|
| + IPC::ReadParam(m, iter, &kinds_);
|
| +}
|
| +
|
| +void SocketsManifestData::Log(std::string* log) const {
|
| + IPC::LogParam(permissions_, log);
|
| + IPC::LogParam(kinds_, log);
|
| +}
|
| +
|
| +bool SocketsManifestData::AddAnyHostMessage(
|
| + PermissionMessages& messages) const {
|
| + for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
|
| + it != permissions_.end(); ++it) {
|
| + if (it->IsAddressBoundType() &&
|
| + it->GetHostType() == SocketPermissionEntry::ANY_HOST) {
|
| + messages.push_back(PermissionMessage(
|
| + PermissionMessage::kSocketAnyHost,
|
| + l10n_util::GetStringUTF16(
|
| + IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST)));
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +void SocketsManifestData::AddSubdomainHostMessage(
|
| + PermissionMessages& messages) const {
|
| + std::set<string16> domains;
|
| + for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
|
| + it != permissions_.end(); ++it) {
|
| + if (it->GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS)
|
| + domains.insert(UTF8ToUTF16(it->pattern().host));
|
| + }
|
| + if (!domains.empty()) {
|
| + int id = (domains.size() == 1) ?
|
| + IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN :
|
| + IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS;
|
| + messages.push_back(PermissionMessage(
|
| + PermissionMessage::kSocketDomainHosts,
|
| + l10n_util::GetStringFUTF16(
|
| + id,
|
| + JoinString(
|
| + std::vector<string16>(
|
| + domains.begin(), domains.end()), ' '))));
|
| + }
|
| +}
|
| +
|
| +void SocketsManifestData::AddSpecificHostMessage(
|
| + PermissionMessages& messages) const {
|
| + std::set<string16> hostnames;
|
| + for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
|
| + it != permissions_.end(); ++it) {
|
| + if (it->GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS)
|
| + hostnames.insert(UTF8ToUTF16(it->pattern().host));
|
| + }
|
| + if (!hostnames.empty()) {
|
| + int id = (hostnames.size() == 1) ?
|
| + IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST :
|
| + IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS;
|
| + messages.push_back(PermissionMessage(
|
| + PermissionMessage::kSocketSpecificHosts,
|
| + l10n_util::GetStringFUTF16(
|
| + id,
|
| + JoinString(
|
| + std::vector<string16>(
|
| + hostnames.begin(), hostnames.end()), ' '))));
|
| + }
|
| +}
|
| +
|
| +void SocketsManifestData::AddNetworkListMessage(
|
| + PermissionMessages& messages) const {
|
| + for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
|
| + it != permissions_.end(); ++it) {
|
| + if (it->pattern().type == content::SocketPermissionRequest::NETWORK_STATE) {
|
| + messages.push_back(PermissionMessage(
|
| + PermissionMessage::kNetworkState,
|
| + l10n_util::GetStringUTF16(
|
| + IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE)));
|
| + }
|
| + }
|
| +}
|
| +
|
| } // namespace extensions
|
|
|