[go: nahoru, domu]

blob: 2649a8eb0d23361505524d9306cb56eee264f77b [file] [log] [blame]
// Copyright 2014 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/api/sockets/sockets_manifest_permission.h"
#include <memory>
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "extensions/common/api/extensions_manifest_types.h"
#include "extensions/common/api/sockets/sockets_manifest_data.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/strings/grit/extensions_strings.h"
#include "ipc/ipc_message.h"
#include "ui/base/l10n/l10n_util.h"
namespace extensions {
namespace sockets_errors {
const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'";
}
using api::extensions_manifest_types::Sockets;
using api::extensions_manifest_types::SocketHostPatterns;
using content::SocketPermissionRequest;
namespace {
static bool ParseHostPattern(
SocketsManifestPermission* permission,
content::SocketPermissionRequest::OperationType operation_type,
const std::string& host_pattern,
std::u16string* error) {
SocketPermissionEntry entry;
if (!SocketPermissionEntry::ParseHostPattern(
operation_type, host_pattern, &entry)) {
*error = ErrorUtils::FormatErrorMessageUTF16(
sockets_errors::kErrorInvalidHostPattern, host_pattern);
return false;
}
permission->AddPermission(entry);
return true;
}
static bool ParseHostPatterns(
SocketsManifestPermission* permission,
content::SocketPermissionRequest::OperationType operation_type,
const std::unique_ptr<SocketHostPatterns>& host_patterns,
std::u16string* error) {
if (!host_patterns)
return true;
if (host_patterns->as_string) {
return ParseHostPattern(
permission, operation_type, *host_patterns->as_string, error);
}
CHECK(host_patterns->as_strings);
for (std::vector<std::string>::const_iterator it =
host_patterns->as_strings->begin();
it != host_patterns->as_strings->end();
++it) {
if (!ParseHostPattern(permission, operation_type, *it, error)) {
return false;
}
}
return true;
}
static void SetHostPatterns(
std::unique_ptr<SocketHostPatterns>& host_patterns,
const SocketsManifestPermission* permission,
content::SocketPermissionRequest::OperationType operation_type) {
host_patterns.reset(new SocketHostPatterns());
host_patterns->as_strings.reset(new std::vector<std::string>());
for (auto it = permission->entries().cbegin();
it != permission->entries().cend(); ++it) {
if (it->pattern().type == operation_type) {
host_patterns->as_strings->push_back(it->GetHostPatternAsString());
}
}
}
// Helper function for adding the 'any host' permission. Determines if the
// message is needed from |sockets|, and adds the permission to |ids|.
// Returns true if it added the message.
bool AddAnyHostMessage(const SocketPermissionEntrySet& sockets,
PermissionIDSet* ids) {
for (const auto& socket : sockets) {
if (socket.IsAddressBoundType() &&
socket.GetHostType() == SocketPermissionEntry::ANY_HOST) {
ids->insert(APIPermission::kSocketAnyHost);
return true;
}
}
return false;
}
// Helper function for adding subdomain socket permissions. Determines what
// messages are needed from |sockets|, and adds permissions to |ids|.
void AddSubdomainHostMessage(const SocketPermissionEntrySet& sockets,
PermissionIDSet* ids) {
std::set<std::u16string> domains;
for (const auto& socket : sockets) {
if (socket.GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS)
domains.insert(base::UTF8ToUTF16(socket.pattern().host));
}
if (!domains.empty()) {
for (const auto& domain : domains)
ids->insert(APIPermission::kSocketDomainHosts, domain);
}
}
// Helper function for adding specific host socket permissions. Determines what
// messages are needed from |sockets|, and adds permissions to |ids|.
void AddSpecificHostMessage(const SocketPermissionEntrySet& sockets,
PermissionIDSet* ids) {
std::set<std::u16string> hostnames;
for (const auto& socket : sockets) {
if (socket.GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS)
hostnames.insert(base::UTF8ToUTF16(socket.pattern().host));
}
if (!hostnames.empty()) {
for (const auto& hostname : hostnames)
ids->insert(APIPermission::kSocketSpecificHosts, hostname);
}
}
// Helper function for adding the network list socket permission. Determines if
// the message is needed from |sockets|, and adds the permission to |ids|.
void AddNetworkListMessage(const SocketPermissionEntrySet& sockets,
PermissionIDSet* ids) {
for (const auto& socket : sockets) {
if (socket.pattern().type == SocketPermissionRequest::NETWORK_STATE) {
ids->insert(APIPermission::kNetworkState);
}
}
}
} // namespace
SocketsManifestPermission::SocketsManifestPermission() {}
SocketsManifestPermission::~SocketsManifestPermission() {}
// static
std::unique_ptr<SocketsManifestPermission> SocketsManifestPermission::FromValue(
const base::Value& value,
std::u16string* error) {
std::unique_ptr<Sockets> sockets = Sockets::FromValue(value, error);
if (!sockets)
return std::unique_ptr<SocketsManifestPermission>();
std::unique_ptr<SocketsManifestPermission> result(
new SocketsManifestPermission());
if (sockets->udp) {
if (!ParseHostPatterns(result.get(),
SocketPermissionRequest::UDP_BIND,
sockets->udp->bind,
error)) {
return std::unique_ptr<SocketsManifestPermission>();
}
if (!ParseHostPatterns(result.get(),
SocketPermissionRequest::UDP_SEND_TO,
sockets->udp->send,
error)) {
return std::unique_ptr<SocketsManifestPermission>();
}
if (!ParseHostPatterns(result.get(),
SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
sockets->udp->multicast_membership,
error)) {
return std::unique_ptr<SocketsManifestPermission>();
}
}
if (sockets->tcp) {
if (!ParseHostPatterns(result.get(),
SocketPermissionRequest::TCP_CONNECT,
sockets->tcp->connect,
error)) {
return std::unique_ptr<SocketsManifestPermission>();
}
}
if (sockets->tcp_server) {
if (!ParseHostPatterns(result.get(),
SocketPermissionRequest::TCP_LISTEN,
sockets->tcp_server->listen,
error)) {
return std::unique_ptr<SocketsManifestPermission>();
}
}
return result;
}
bool SocketsManifestPermission::CheckRequest(
const Extension* extension,
const SocketPermissionRequest& request) const {
for (auto it = permissions_.cbegin(); it != permissions_.cend(); ++it) {
if (it->Check(request))
return true;
}
return false;
}
std::string SocketsManifestPermission::name() const {
return manifest_keys::kSockets;
}
std::string SocketsManifestPermission::id() const { return name(); }
PermissionIDSet SocketsManifestPermission::GetPermissions() const {
PermissionIDSet ids;
AddSocketHostPermissions(permissions_, &ids);
return ids;
}
bool SocketsManifestPermission::FromValue(const base::Value* value) {
if (!value)
return false;
std::u16string error;
std::unique_ptr<SocketsManifestPermission> manifest_permission(
SocketsManifestPermission::FromValue(*value, &error));
if (!manifest_permission)
return false;
permissions_ = manifest_permission->permissions_;
return true;
}
std::unique_ptr<base::Value> SocketsManifestPermission::ToValue() const {
Sockets sockets;
sockets.udp.reset(new Sockets::Udp());
SetHostPatterns(sockets.udp->bind, this, SocketPermissionRequest::UDP_BIND);
SetHostPatterns(
sockets.udp->send, this, SocketPermissionRequest::UDP_SEND_TO);
SetHostPatterns(sockets.udp->multicast_membership,
this,
SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP);
if (sockets.udp->bind->as_strings->size() == 0 &&
sockets.udp->send->as_strings->size() == 0 &&
sockets.udp->multicast_membership->as_strings->size() == 0) {
sockets.udp.reset(NULL);
}
sockets.tcp.reset(new Sockets::Tcp());
SetHostPatterns(
sockets.tcp->connect, this, SocketPermissionRequest::TCP_CONNECT);
if (sockets.tcp->connect->as_strings->size() == 0) {
sockets.tcp.reset(NULL);
}
sockets.tcp_server.reset(new Sockets::TcpServer());
SetHostPatterns(
sockets.tcp_server->listen, this, SocketPermissionRequest::TCP_LISTEN);
if (sockets.tcp_server->listen->as_strings->size() == 0) {
sockets.tcp_server.reset(NULL);
}
return std::unique_ptr<base::Value>(sockets.ToValue().release());
}
std::unique_ptr<ManifestPermission> SocketsManifestPermission::Diff(
const ManifestPermission* rhs) const {
const SocketsManifestPermission* other =
static_cast<const SocketsManifestPermission*>(rhs);
auto result = std::make_unique<SocketsManifestPermission>();
result->permissions_ = base::STLSetDifference<SocketPermissionEntrySet>(
permissions_, other->permissions_);
return result;
}
std::unique_ptr<ManifestPermission> SocketsManifestPermission::Union(
const ManifestPermission* rhs) const {
const SocketsManifestPermission* other =
static_cast<const SocketsManifestPermission*>(rhs);
auto result = std::make_unique<SocketsManifestPermission>();
result->permissions_ = base::STLSetUnion<SocketPermissionEntrySet>(
permissions_, other->permissions_);
return result;
}
std::unique_ptr<ManifestPermission> SocketsManifestPermission::Intersect(
const ManifestPermission* rhs) const {
const SocketsManifestPermission* other =
static_cast<const SocketsManifestPermission*>(rhs);
auto result = std::make_unique<SocketsManifestPermission>();
result->permissions_ = base::STLSetIntersection<SocketPermissionEntrySet>(
permissions_, other->permissions_);
return result;
}
void SocketsManifestPermission::AddPermission(
const SocketPermissionEntry& entry) {
permissions_.insert(entry);
}
// static
void SocketsManifestPermission::AddSocketHostPermissions(
const SocketPermissionEntrySet& sockets,
PermissionIDSet* ids) {
if (!AddAnyHostMessage(sockets, ids)) {
AddSpecificHostMessage(sockets, ids);
AddSubdomainHostMessage(sockets, ids);
}
AddNetworkListMessage(sockets, ids);
}
bool SocketsManifestPermission::RequiresManagementUIWarning() const {
return false;
}
bool SocketsManifestPermission::RequiresManagedSessionFullLoginWarning() const {
return false;
}
} // namespace extensions