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/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "extensions/common/api/extensions_manifest_types.h"
12 #include "extensions/common/api/sockets/sockets_manifest_data.h"
13 #include "extensions/common/error_utils.h"
14 #include "extensions/common/extension_messages.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 core_api::extensions_manifest_types::Sockets
;
28 using core_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 (SocketsManifestPermission::SocketPermissionEntrySet::const_iterator it
=
81 permission
->entries().begin();
82 it
!= permission
->entries().end();
84 if (it
->pattern().type
== operation_type
) {
85 host_patterns
->as_strings
->push_back(it
->GetHostPatternAsString());
92 SocketsManifestPermission::SocketsManifestPermission() {}
94 SocketsManifestPermission::~SocketsManifestPermission() {}
97 scoped_ptr
<SocketsManifestPermission
> SocketsManifestPermission::FromValue(
98 const base::Value
& value
,
99 base::string16
* error
) {
100 scoped_ptr
<Sockets
> sockets
= Sockets::FromValue(value
, error
);
102 return scoped_ptr
<SocketsManifestPermission
>();
104 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
106 if (!ParseHostPatterns(result
.get(),
107 SocketPermissionRequest::UDP_BIND
,
110 return scoped_ptr
<SocketsManifestPermission
>();
112 if (!ParseHostPatterns(result
.get(),
113 SocketPermissionRequest::UDP_SEND_TO
,
116 return scoped_ptr
<SocketsManifestPermission
>();
118 if (!ParseHostPatterns(result
.get(),
119 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP
,
120 sockets
->udp
->multicast_membership
,
122 return scoped_ptr
<SocketsManifestPermission
>();
126 if (!ParseHostPatterns(result
.get(),
127 SocketPermissionRequest::TCP_CONNECT
,
128 sockets
->tcp
->connect
,
130 return scoped_ptr
<SocketsManifestPermission
>();
133 if (sockets
->tcp_server
) {
134 if (!ParseHostPatterns(result
.get(),
135 SocketPermissionRequest::TCP_LISTEN
,
136 sockets
->tcp_server
->listen
,
138 return scoped_ptr
<SocketsManifestPermission
>();
141 return result
.Pass();
144 bool SocketsManifestPermission::CheckRequest(
145 const Extension
* extension
,
146 const SocketPermissionRequest
& request
) const {
147 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
148 it
!= permissions_
.end();
150 if (it
->Check(request
))
156 std::string
SocketsManifestPermission::name() const {
157 return manifest_keys::kSockets
;
160 std::string
SocketsManifestPermission::id() const { return name(); }
162 bool SocketsManifestPermission::HasMessages() const {
163 bool is_empty
= permissions_
.empty();
167 PermissionMessages
SocketsManifestPermission::GetMessages() const {
168 // TODO(rpaquay): This function and callees is (almost) a copy/paste
169 // from extensions::SocketPermissiona.
170 PermissionMessages result
;
171 if (!AddAnyHostMessage(result
)) {
172 AddSpecificHostMessage(result
);
173 AddSubdomainHostMessage(result
);
175 AddNetworkListMessage(result
);
179 bool SocketsManifestPermission::FromValue(const base::Value
* value
) {
182 base::string16 error
;
183 scoped_ptr
<SocketsManifestPermission
> manifest_permission(
184 SocketsManifestPermission::FromValue(*value
, &error
));
186 if (!manifest_permission
)
189 permissions_
= manifest_permission
->permissions_
;
193 scoped_ptr
<base::Value
> SocketsManifestPermission::ToValue() const {
196 sockets
.udp
.reset(new Sockets::Udp());
197 SetHostPatterns(sockets
.udp
->bind
, this, SocketPermissionRequest::UDP_BIND
);
199 sockets
.udp
->send
, this, SocketPermissionRequest::UDP_SEND_TO
);
200 SetHostPatterns(sockets
.udp
->multicast_membership
,
202 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP
);
203 if (sockets
.udp
->bind
->as_strings
->size() == 0 &&
204 sockets
.udp
->send
->as_strings
->size() == 0 &&
205 sockets
.udp
->multicast_membership
->as_strings
->size() == 0) {
206 sockets
.udp
.reset(NULL
);
209 sockets
.tcp
.reset(new Sockets::Tcp());
211 sockets
.tcp
->connect
, this, SocketPermissionRequest::TCP_CONNECT
);
212 if (sockets
.tcp
->connect
->as_strings
->size() == 0) {
213 sockets
.tcp
.reset(NULL
);
216 sockets
.tcp_server
.reset(new Sockets::TcpServer());
218 sockets
.tcp_server
->listen
, this, SocketPermissionRequest::TCP_LISTEN
);
219 if (sockets
.tcp_server
->listen
->as_strings
->size() == 0) {
220 sockets
.tcp_server
.reset(NULL
);
223 return scoped_ptr
<base::Value
>(sockets
.ToValue().release()).Pass();
226 ManifestPermission
* SocketsManifestPermission::Diff(
227 const ManifestPermission
* rhs
) const {
228 const SocketsManifestPermission
* other
=
229 static_cast<const SocketsManifestPermission
*>(rhs
);
231 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
232 result
->permissions_
= base::STLSetDifference
<SocketPermissionEntrySet
>(
233 permissions_
, other
->permissions_
);
234 return result
.release();
237 ManifestPermission
* SocketsManifestPermission::Union(
238 const ManifestPermission
* rhs
) const {
239 const SocketsManifestPermission
* other
=
240 static_cast<const SocketsManifestPermission
*>(rhs
);
242 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
243 result
->permissions_
= base::STLSetUnion
<SocketPermissionEntrySet
>(
244 permissions_
, other
->permissions_
);
245 return result
.release();
248 ManifestPermission
* SocketsManifestPermission::Intersect(
249 const ManifestPermission
* rhs
) const {
250 const SocketsManifestPermission
* other
=
251 static_cast<const SocketsManifestPermission
*>(rhs
);
253 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
254 result
->permissions_
= base::STLSetIntersection
<SocketPermissionEntrySet
>(
255 permissions_
, other
->permissions_
);
256 return result
.release();
259 void SocketsManifestPermission::AddPermission(
260 const SocketPermissionEntry
& entry
) {
261 permissions_
.insert(entry
);
264 bool SocketsManifestPermission::AddAnyHostMessage(
265 PermissionMessages
& messages
) const {
266 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
267 it
!= permissions_
.end();
269 if (it
->IsAddressBoundType() &&
270 it
->GetHostType() == SocketPermissionEntry::ANY_HOST
) {
272 PermissionMessage(PermissionMessage::kSocketAnyHost
,
273 l10n_util::GetStringUTF16(
274 IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST
)));
281 void SocketsManifestPermission::AddSubdomainHostMessage(
282 PermissionMessages
& messages
) const {
283 std::set
<base::string16
> domains
;
284 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
285 it
!= permissions_
.end();
287 if (it
->GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS
)
288 domains
.insert(base::UTF8ToUTF16(it
->pattern().host
));
290 if (!domains
.empty()) {
291 int id
= (domains
.size() == 1)
292 ? IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN
293 : IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS
;
294 messages
.push_back(PermissionMessage(
295 PermissionMessage::kSocketDomainHosts
,
296 l10n_util::GetStringFUTF16(
299 std::vector
<base::string16
>(domains
.begin(), domains
.end()),
304 void SocketsManifestPermission::AddSpecificHostMessage(
305 PermissionMessages
& messages
) const {
306 std::set
<base::string16
> hostnames
;
307 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
308 it
!= permissions_
.end();
310 if (it
->GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS
)
311 hostnames
.insert(base::UTF8ToUTF16(it
->pattern().host
));
313 if (!hostnames
.empty()) {
314 int id
= (hostnames
.size() == 1)
315 ? IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST
316 : IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS
;
317 messages
.push_back(PermissionMessage(
318 PermissionMessage::kSocketSpecificHosts
,
319 l10n_util::GetStringFUTF16(
322 std::vector
<base::string16
>(hostnames
.begin(), hostnames
.end()),
327 void SocketsManifestPermission::AddNetworkListMessage(
328 PermissionMessages
& messages
) const {
329 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
330 it
!= permissions_
.end();
332 if (it
->pattern().type
== SocketPermissionRequest::NETWORK_STATE
) {
334 PermissionMessage(PermissionMessage::kNetworkState
,
335 l10n_util::GetStringUTF16(
336 IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE
)));
341 } // namespace extensions