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| and/or
91 // |messages|, ignoring them if they are NULL. Returns true if it added the
93 bool AddAnyHostMessage(const SocketPermissionEntrySet
& sockets
,
95 PermissionMessages
* messages
) {
96 for (const auto& socket
: sockets
) {
97 if (socket
.IsAddressBoundType() &&
98 socket
.GetHostType() == SocketPermissionEntry::ANY_HOST
) {
100 ids
->insert(APIPermission::kSocketAnyHost
);
102 messages
->push_back(PermissionMessage(
103 PermissionMessage::kSocketAnyHost
,
104 l10n_util::GetStringUTF16(
105 IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST
)));
113 // Helper function for adding subdomain socket permissions. Determines what
114 // messages are needed from |sockets|, and adds permissions to |ids| and/or
115 // |messages|, ignoring them if they are NULL.
116 void AddSubdomainHostMessage(const SocketPermissionEntrySet
& sockets
,
117 PermissionIDSet
* ids
,
118 PermissionMessages
* messages
) {
119 std::set
<base::string16
> domains
;
120 for (const auto& socket
: sockets
) {
121 if (socket
.GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS
)
122 domains
.insert(base::UTF8ToUTF16(socket
.pattern().host
));
124 if (!domains
.empty()) {
125 // TODO(sashab): This is not correct for all languages - add proper
126 // internationalization of this string for all plural states.
128 int id
= (domains
.size() == 1)
129 ? IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN
130 : IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS
;
131 messages
->push_back(PermissionMessage(
132 PermissionMessage::kSocketDomainHosts
,
133 l10n_util::GetStringFUTF16(
134 id
, base::JoinString(std::vector
<base::string16
>(domains
.begin(),
136 base::ASCIIToUTF16(" ")))));
139 for (const auto& domain
: domains
)
140 ids
->insert(APIPermission::kSocketDomainHosts
, domain
);
145 // Helper function for adding specific host socket permissions. Determines what
146 // messages are needed from |sockets|, and adds permissions to |ids| and/or
147 // |messages|, ignoring them if they are NULL.
148 void AddSpecificHostMessage(const SocketPermissionEntrySet
& sockets
,
149 PermissionIDSet
* ids
,
150 PermissionMessages
* messages
) {
151 std::set
<base::string16
> hostnames
;
152 for (const auto& socket
: sockets
) {
153 if (socket
.GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS
)
154 hostnames
.insert(base::UTF8ToUTF16(socket
.pattern().host
));
156 if (!hostnames
.empty()) {
157 // TODO(sashab): This is not correct for all languages - add proper
158 // internationalization of this string for all plural states.
160 int id
= (hostnames
.size() == 1)
161 ? IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST
162 : IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS
;
163 messages
->push_back(PermissionMessage(
164 PermissionMessage::kSocketSpecificHosts
,
165 l10n_util::GetStringFUTF16(
166 id
, base::JoinString(std::vector
<base::string16
>(
167 hostnames
.begin(), hostnames
.end()),
168 base::ASCIIToUTF16(" ")))));
171 for (const auto& hostname
: hostnames
)
172 ids
->insert(APIPermission::kSocketSpecificHosts
, hostname
);
177 // Helper function for adding the network list socket permission. Determines if
178 // the message is needed from |sockets|, and adds the permission to |ids| and/or
179 // |messages|, ignoring them if they are NULL.
180 void AddNetworkListMessage(const SocketPermissionEntrySet
& sockets
,
181 PermissionIDSet
* ids
,
182 PermissionMessages
* messages
) {
183 for (const auto& socket
: sockets
) {
184 if (socket
.pattern().type
== SocketPermissionRequest::NETWORK_STATE
) {
186 ids
->insert(APIPermission::kNetworkState
);
189 PermissionMessage(PermissionMessage::kNetworkState
,
190 l10n_util::GetStringUTF16(
191 IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE
)));
199 SocketsManifestPermission::SocketsManifestPermission() {}
201 SocketsManifestPermission::~SocketsManifestPermission() {}
204 scoped_ptr
<SocketsManifestPermission
> SocketsManifestPermission::FromValue(
205 const base::Value
& value
,
206 base::string16
* error
) {
207 scoped_ptr
<Sockets
> sockets
= Sockets::FromValue(value
, error
);
209 return scoped_ptr
<SocketsManifestPermission
>();
211 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
213 if (!ParseHostPatterns(result
.get(),
214 SocketPermissionRequest::UDP_BIND
,
217 return scoped_ptr
<SocketsManifestPermission
>();
219 if (!ParseHostPatterns(result
.get(),
220 SocketPermissionRequest::UDP_SEND_TO
,
223 return scoped_ptr
<SocketsManifestPermission
>();
225 if (!ParseHostPatterns(result
.get(),
226 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP
,
227 sockets
->udp
->multicast_membership
,
229 return scoped_ptr
<SocketsManifestPermission
>();
233 if (!ParseHostPatterns(result
.get(),
234 SocketPermissionRequest::TCP_CONNECT
,
235 sockets
->tcp
->connect
,
237 return scoped_ptr
<SocketsManifestPermission
>();
240 if (sockets
->tcp_server
) {
241 if (!ParseHostPatterns(result
.get(),
242 SocketPermissionRequest::TCP_LISTEN
,
243 sockets
->tcp_server
->listen
,
245 return scoped_ptr
<SocketsManifestPermission
>();
248 return result
.Pass();
251 bool SocketsManifestPermission::CheckRequest(
252 const Extension
* extension
,
253 const SocketPermissionRequest
& request
) const {
254 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
255 it
!= permissions_
.end();
257 if (it
->Check(request
))
263 std::string
SocketsManifestPermission::name() const {
264 return manifest_keys::kSockets
;
267 std::string
SocketsManifestPermission::id() const { return name(); }
269 PermissionIDSet
SocketsManifestPermission::GetPermissions() const {
271 AddSocketHostPermissions(permissions_
, &ids
, NULL
);
275 bool SocketsManifestPermission::FromValue(const base::Value
* value
) {
278 base::string16 error
;
279 scoped_ptr
<SocketsManifestPermission
> manifest_permission(
280 SocketsManifestPermission::FromValue(*value
, &error
));
282 if (!manifest_permission
)
285 permissions_
= manifest_permission
->permissions_
;
289 scoped_ptr
<base::Value
> SocketsManifestPermission::ToValue() const {
292 sockets
.udp
.reset(new Sockets::Udp());
293 SetHostPatterns(sockets
.udp
->bind
, this, SocketPermissionRequest::UDP_BIND
);
295 sockets
.udp
->send
, this, SocketPermissionRequest::UDP_SEND_TO
);
296 SetHostPatterns(sockets
.udp
->multicast_membership
,
298 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP
);
299 if (sockets
.udp
->bind
->as_strings
->size() == 0 &&
300 sockets
.udp
->send
->as_strings
->size() == 0 &&
301 sockets
.udp
->multicast_membership
->as_strings
->size() == 0) {
302 sockets
.udp
.reset(NULL
);
305 sockets
.tcp
.reset(new Sockets::Tcp());
307 sockets
.tcp
->connect
, this, SocketPermissionRequest::TCP_CONNECT
);
308 if (sockets
.tcp
->connect
->as_strings
->size() == 0) {
309 sockets
.tcp
.reset(NULL
);
312 sockets
.tcp_server
.reset(new Sockets::TcpServer());
314 sockets
.tcp_server
->listen
, this, SocketPermissionRequest::TCP_LISTEN
);
315 if (sockets
.tcp_server
->listen
->as_strings
->size() == 0) {
316 sockets
.tcp_server
.reset(NULL
);
319 return scoped_ptr
<base::Value
>(sockets
.ToValue().release()).Pass();
322 ManifestPermission
* SocketsManifestPermission::Diff(
323 const ManifestPermission
* rhs
) const {
324 const SocketsManifestPermission
* other
=
325 static_cast<const SocketsManifestPermission
*>(rhs
);
327 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
328 result
->permissions_
= base::STLSetDifference
<SocketPermissionEntrySet
>(
329 permissions_
, other
->permissions_
);
330 return result
.release();
333 ManifestPermission
* SocketsManifestPermission::Union(
334 const ManifestPermission
* rhs
) const {
335 const SocketsManifestPermission
* other
=
336 static_cast<const SocketsManifestPermission
*>(rhs
);
338 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
339 result
->permissions_
= base::STLSetUnion
<SocketPermissionEntrySet
>(
340 permissions_
, other
->permissions_
);
341 return result
.release();
344 ManifestPermission
* SocketsManifestPermission::Intersect(
345 const ManifestPermission
* rhs
) const {
346 const SocketsManifestPermission
* other
=
347 static_cast<const SocketsManifestPermission
*>(rhs
);
349 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
350 result
->permissions_
= base::STLSetIntersection
<SocketPermissionEntrySet
>(
351 permissions_
, other
->permissions_
);
352 return result
.release();
355 void SocketsManifestPermission::AddPermission(
356 const SocketPermissionEntry
& entry
) {
357 permissions_
.insert(entry
);
361 void SocketsManifestPermission::AddSocketHostPermissions(
362 const SocketPermissionEntrySet
& sockets
,
363 PermissionIDSet
* ids
,
364 PermissionMessages
* messages
) {
365 if (!AddAnyHostMessage(sockets
, ids
, messages
)) {
366 AddSpecificHostMessage(sockets
, ids
, messages
);
367 AddSubdomainHostMessage(sockets
, ids
, messages
);
369 AddNetworkListMessage(sockets
, ids
, messages
);
372 } // namespace extensions