Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / common / api / sockets / sockets_manifest_permission.cc
bloba5f02711b41b2c1b92bcedb9e68d382dd0dda67b
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/common/api/sockets/sockets_manifest_permission.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_split.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "extensions/common/api/extensions_manifest_types.h"
13 #include "extensions/common/api/sockets/sockets_manifest_data.h"
14 #include "extensions/common/error_utils.h"
15 #include "extensions/common/manifest_constants.h"
16 #include "grit/extensions_strings.h"
17 #include "ipc/ipc_message.h"
18 #include "ui/base/l10n/l10n_util.h"
20 namespace extensions {
22 namespace sockets_errors {
23 const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'";
26 namespace errors = sockets_errors;
27 using api::extensions_manifest_types::Sockets;
28 using api::extensions_manifest_types::SocketHostPatterns;
29 using content::SocketPermissionRequest;
31 namespace {
33 static bool ParseHostPattern(
34 SocketsManifestPermission* permission,
35 content::SocketPermissionRequest::OperationType operation_type,
36 const std::string& host_pattern,
37 base::string16* error) {
38 SocketPermissionEntry entry;
39 if (!SocketPermissionEntry::ParseHostPattern(
40 operation_type, host_pattern, &entry)) {
41 *error = ErrorUtils::FormatErrorMessageUTF16(
42 errors::kErrorInvalidHostPattern, host_pattern);
43 return false;
45 permission->AddPermission(entry);
46 return true;
49 static bool ParseHostPatterns(
50 SocketsManifestPermission* permission,
51 content::SocketPermissionRequest::OperationType operation_type,
52 const scoped_ptr<SocketHostPatterns>& host_patterns,
53 base::string16* error) {
54 if (!host_patterns)
55 return true;
57 if (host_patterns->as_string) {
58 return ParseHostPattern(
59 permission, operation_type, *host_patterns->as_string, error);
62 CHECK(host_patterns->as_strings);
63 for (std::vector<std::string>::const_iterator it =
64 host_patterns->as_strings->begin();
65 it != host_patterns->as_strings->end();
66 ++it) {
67 if (!ParseHostPattern(permission, operation_type, *it, error)) {
68 return false;
71 return true;
74 static void SetHostPatterns(
75 scoped_ptr<SocketHostPatterns>& host_patterns,
76 const SocketsManifestPermission* permission,
77 content::SocketPermissionRequest::OperationType operation_type) {
78 host_patterns.reset(new SocketHostPatterns());
79 host_patterns->as_strings.reset(new std::vector<std::string>());
80 for (SocketPermissionEntrySet::const_iterator it =
81 permission->entries().begin();
82 it != permission->entries().end(); ++it) {
83 if (it->pattern().type == operation_type) {
84 host_patterns->as_strings->push_back(it->GetHostPatternAsString());
89 // Helper function for adding the 'any host' permission. Determines if the
90 // message is needed from |sockets|, and adds the permission to |ids|.
91 // Returns true if it added the message.
92 bool AddAnyHostMessage(const SocketPermissionEntrySet& sockets,
93 PermissionIDSet* ids) {
94 for (const auto& socket : sockets) {
95 if (socket.IsAddressBoundType() &&
96 socket.GetHostType() == SocketPermissionEntry::ANY_HOST) {
97 ids->insert(APIPermission::kSocketAnyHost);
98 return true;
101 return false;
104 // Helper function for adding subdomain socket permissions. Determines what
105 // messages are needed from |sockets|, and adds permissions to |ids|.
106 void AddSubdomainHostMessage(const SocketPermissionEntrySet& sockets,
107 PermissionIDSet* ids) {
108 std::set<base::string16> domains;
109 for (const auto& socket : sockets) {
110 if (socket.GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS)
111 domains.insert(base::UTF8ToUTF16(socket.pattern().host));
113 if (!domains.empty()) {
114 for (const auto& domain : domains)
115 ids->insert(APIPermission::kSocketDomainHosts, domain);
119 // Helper function for adding specific host socket permissions. Determines what
120 // messages are needed from |sockets|, and adds permissions to |ids|.
121 void AddSpecificHostMessage(const SocketPermissionEntrySet& sockets,
122 PermissionIDSet* ids) {
123 std::set<base::string16> hostnames;
124 for (const auto& socket : sockets) {
125 if (socket.GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS)
126 hostnames.insert(base::UTF8ToUTF16(socket.pattern().host));
128 if (!hostnames.empty()) {
129 for (const auto& hostname : hostnames)
130 ids->insert(APIPermission::kSocketSpecificHosts, hostname);
134 // Helper function for adding the network list socket permission. Determines if
135 // the message is needed from |sockets|, and adds the permission to |ids|.
136 void AddNetworkListMessage(const SocketPermissionEntrySet& sockets,
137 PermissionIDSet* ids) {
138 for (const auto& socket : sockets) {
139 if (socket.pattern().type == SocketPermissionRequest::NETWORK_STATE) {
140 ids->insert(APIPermission::kNetworkState);
145 } // namespace
147 SocketsManifestPermission::SocketsManifestPermission() {}
149 SocketsManifestPermission::~SocketsManifestPermission() {}
151 // static
152 scoped_ptr<SocketsManifestPermission> SocketsManifestPermission::FromValue(
153 const base::Value& value,
154 base::string16* error) {
155 scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error);
156 if (!sockets)
157 return scoped_ptr<SocketsManifestPermission>();
159 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
160 if (sockets->udp) {
161 if (!ParseHostPatterns(result.get(),
162 SocketPermissionRequest::UDP_BIND,
163 sockets->udp->bind,
164 error)) {
165 return scoped_ptr<SocketsManifestPermission>();
167 if (!ParseHostPatterns(result.get(),
168 SocketPermissionRequest::UDP_SEND_TO,
169 sockets->udp->send,
170 error)) {
171 return scoped_ptr<SocketsManifestPermission>();
173 if (!ParseHostPatterns(result.get(),
174 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
175 sockets->udp->multicast_membership,
176 error)) {
177 return scoped_ptr<SocketsManifestPermission>();
180 if (sockets->tcp) {
181 if (!ParseHostPatterns(result.get(),
182 SocketPermissionRequest::TCP_CONNECT,
183 sockets->tcp->connect,
184 error)) {
185 return scoped_ptr<SocketsManifestPermission>();
188 if (sockets->tcp_server) {
189 if (!ParseHostPatterns(result.get(),
190 SocketPermissionRequest::TCP_LISTEN,
191 sockets->tcp_server->listen,
192 error)) {
193 return scoped_ptr<SocketsManifestPermission>();
196 return result.Pass();
199 bool SocketsManifestPermission::CheckRequest(
200 const Extension* extension,
201 const SocketPermissionRequest& request) const {
202 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
203 it != permissions_.end();
204 ++it) {
205 if (it->Check(request))
206 return true;
208 return false;
211 std::string SocketsManifestPermission::name() const {
212 return manifest_keys::kSockets;
215 std::string SocketsManifestPermission::id() const { return name(); }
217 PermissionIDSet SocketsManifestPermission::GetPermissions() const {
218 PermissionIDSet ids;
219 AddSocketHostPermissions(permissions_, &ids);
220 return ids;
223 bool SocketsManifestPermission::FromValue(const base::Value* value) {
224 if (!value)
225 return false;
226 base::string16 error;
227 scoped_ptr<SocketsManifestPermission> manifest_permission(
228 SocketsManifestPermission::FromValue(*value, &error));
230 if (!manifest_permission)
231 return false;
233 permissions_ = manifest_permission->permissions_;
234 return true;
237 scoped_ptr<base::Value> SocketsManifestPermission::ToValue() const {
238 Sockets sockets;
240 sockets.udp.reset(new Sockets::Udp());
241 SetHostPatterns(sockets.udp->bind, this, SocketPermissionRequest::UDP_BIND);
242 SetHostPatterns(
243 sockets.udp->send, this, SocketPermissionRequest::UDP_SEND_TO);
244 SetHostPatterns(sockets.udp->multicast_membership,
245 this,
246 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP);
247 if (sockets.udp->bind->as_strings->size() == 0 &&
248 sockets.udp->send->as_strings->size() == 0 &&
249 sockets.udp->multicast_membership->as_strings->size() == 0) {
250 sockets.udp.reset(NULL);
253 sockets.tcp.reset(new Sockets::Tcp());
254 SetHostPatterns(
255 sockets.tcp->connect, this, SocketPermissionRequest::TCP_CONNECT);
256 if (sockets.tcp->connect->as_strings->size() == 0) {
257 sockets.tcp.reset(NULL);
260 sockets.tcp_server.reset(new Sockets::TcpServer());
261 SetHostPatterns(
262 sockets.tcp_server->listen, this, SocketPermissionRequest::TCP_LISTEN);
263 if (sockets.tcp_server->listen->as_strings->size() == 0) {
264 sockets.tcp_server.reset(NULL);
267 return scoped_ptr<base::Value>(sockets.ToValue().release()).Pass();
270 ManifestPermission* SocketsManifestPermission::Diff(
271 const ManifestPermission* rhs) const {
272 const SocketsManifestPermission* other =
273 static_cast<const SocketsManifestPermission*>(rhs);
275 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
276 result->permissions_ = base::STLSetDifference<SocketPermissionEntrySet>(
277 permissions_, other->permissions_);
278 return result.release();
281 ManifestPermission* SocketsManifestPermission::Union(
282 const ManifestPermission* rhs) const {
283 const SocketsManifestPermission* other =
284 static_cast<const SocketsManifestPermission*>(rhs);
286 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
287 result->permissions_ = base::STLSetUnion<SocketPermissionEntrySet>(
288 permissions_, other->permissions_);
289 return result.release();
292 ManifestPermission* SocketsManifestPermission::Intersect(
293 const ManifestPermission* rhs) const {
294 const SocketsManifestPermission* other =
295 static_cast<const SocketsManifestPermission*>(rhs);
297 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
298 result->permissions_ = base::STLSetIntersection<SocketPermissionEntrySet>(
299 permissions_, other->permissions_);
300 return result.release();
303 void SocketsManifestPermission::AddPermission(
304 const SocketPermissionEntry& entry) {
305 permissions_.insert(entry);
308 // static
309 void SocketsManifestPermission::AddSocketHostPermissions(
310 const SocketPermissionEntrySet& sockets,
311 PermissionIDSet* ids) {
312 if (!AddAnyHostMessage(sockets, ids)) {
313 AddSpecificHostMessage(sockets, ids);
314 AddSubdomainHostMessage(sockets, ids);
316 AddNetworkListMessage(sockets, ids);
319 } // namespace extensions