Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5465)

Unified Diff: chrome/common/extensions/api/sockets/sockets_handler.cc

Issue 51433002: Enable permission warnings from ManifestHandlers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..3cdcd9786bab345c7968f2e63c0b173620f270f3 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,221 @@ 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 {
Yoyo Zhou 2013/11/09 01:15:30 Do you anticipate something like SetDisjunctionPer
rpaquay 2013/11/11 18:37:35 I would say probably at some point. I don't know o
Yoyo Zhou 2013/11/12 02:39:29 Okay.
+ 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 {
+ // TODO(rpaquay): Null check?
+ 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_) {
+ // TODO(rpaquay) : Is it ok to return NULL?
+ return scoped_ptr<base::Value>(base::Value::CreateNullValue());
+ }
+
+ Sockets sockets;
+ if (data_->is_udp()) {
+ sockets.udp.reset(new Sockets::Udp());
+ sockets.udp->bind = AddEntry(SocketPermissionRequest::UDP_BIND).Pass();
+ sockets.udp->send = AddEntry(SocketPermissionRequest::UDP_SEND_TO).Pass();
+ sockets.udp->multicast_membership =
+ AddEntry(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP).Pass();
+ }
+ if (data_->is_tcp()) {
+ sockets.tcp.reset(new Sockets::Tcp());
+ sockets.tcp->connect = AddEntry(
+ SocketPermissionRequest::TCP_CONNECT).Pass();
+ }
+ if (data_->is_tcp_server()) {
+ sockets.tcp_server.reset(new Sockets::TcpServer());
+ sockets.tcp_server->listen = AddEntry(
+ SocketPermissionRequest::TCP_LISTEN).Pass();
+ }
+
+ return sockets.ToValue().Pass();
+ }
+
+ // 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<std::string> AddEntry(
+ content::SocketPermissionRequest::OperationType operation_type) const {
+ scoped_ptr<std::string> result;
+ for (SocketsManifestData::SocketPermissionEntrySet::const_iterator it =
+ data_->entries().begin(); it != data_->entries().end() ; ++it) {
+ if (it->pattern().type == operation_type) {
+ result.reset(new std::string(it->GetHostPatternAsString()));
+ break;
+ }
+ }
+ return result.Pass();
+ }
+
+ scoped_ptr<SocketsManifestData> data_;
Yoyo Zhou 2013/11/09 01:15:30 This looks like unusual ownership. ManifestDatas a
rpaquay 2013/11/11 18:37:35 The "initial" value is a clone of the extension ma
Yoyo Zhou 2013/11/13 02:57:07 (SocketPermissionData already exists, but it seems
rpaquay 2013/11/13 21:28:55 This makes sense. Patchset #6 swaps ownership betw
+};
SocketsHandler::SocketsHandler() {}
@@ -45,11 +265,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 +297,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 +314,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 +335,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 +344,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,
@@ -144,7 +381,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 +389,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

Powered by Google App Engine
This is Rietveld 408576698