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
;
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
);
45 permission
->AddPermission(entry
);
49 static bool ParseHostPatterns(
50 SocketsManifestPermission
* permission
,
51 content::SocketPermissionRequest::OperationType operation_type
,
52 const scoped_ptr
<SocketHostPatterns
>& host_patterns
,
53 base::string16
* error
) {
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();
67 if (!ParseHostPattern(permission
, operation_type
, *it
, error
)) {
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
);
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
);
147 SocketsManifestPermission::SocketsManifestPermission() {}
149 SocketsManifestPermission::~SocketsManifestPermission() {}
152 scoped_ptr
<SocketsManifestPermission
> SocketsManifestPermission::FromValue(
153 const base::Value
& value
,
154 base::string16
* error
) {
155 scoped_ptr
<Sockets
> sockets
= Sockets::FromValue(value
, error
);
157 return scoped_ptr
<SocketsManifestPermission
>();
159 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
161 if (!ParseHostPatterns(result
.get(),
162 SocketPermissionRequest::UDP_BIND
,
165 return scoped_ptr
<SocketsManifestPermission
>();
167 if (!ParseHostPatterns(result
.get(),
168 SocketPermissionRequest::UDP_SEND_TO
,
171 return scoped_ptr
<SocketsManifestPermission
>();
173 if (!ParseHostPatterns(result
.get(),
174 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP
,
175 sockets
->udp
->multicast_membership
,
177 return scoped_ptr
<SocketsManifestPermission
>();
181 if (!ParseHostPatterns(result
.get(),
182 SocketPermissionRequest::TCP_CONNECT
,
183 sockets
->tcp
->connect
,
185 return scoped_ptr
<SocketsManifestPermission
>();
188 if (sockets
->tcp_server
) {
189 if (!ParseHostPatterns(result
.get(),
190 SocketPermissionRequest::TCP_LISTEN
,
191 sockets
->tcp_server
->listen
,
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();
205 if (it
->Check(request
))
211 std::string
SocketsManifestPermission::name() const {
212 return manifest_keys::kSockets
;
215 std::string
SocketsManifestPermission::id() const { return name(); }
217 PermissionIDSet
SocketsManifestPermission::GetPermissions() const {
219 AddSocketHostPermissions(permissions_
, &ids
);
223 bool SocketsManifestPermission::FromValue(const base::Value
* value
) {
226 base::string16 error
;
227 scoped_ptr
<SocketsManifestPermission
> manifest_permission(
228 SocketsManifestPermission::FromValue(*value
, &error
));
230 if (!manifest_permission
)
233 permissions_
= manifest_permission
->permissions_
;
237 scoped_ptr
<base::Value
> SocketsManifestPermission::ToValue() const {
240 sockets
.udp
.reset(new Sockets::Udp());
241 SetHostPatterns(sockets
.udp
->bind
, this, SocketPermissionRequest::UDP_BIND
);
243 sockets
.udp
->send
, this, SocketPermissionRequest::UDP_SEND_TO
);
244 SetHostPatterns(sockets
.udp
->multicast_membership
,
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());
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());
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
);
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