1 // Copyright 2013 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 "chrome/common/extensions/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 "chrome/common/extensions/api/manifest_types.h"
12 #include "chrome/common/extensions/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/generated_resources.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::manifest_types::Sockets
;
28 using api::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(permission
, operation_type
,
59 *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(); ++it
) {
66 if (!ParseHostPattern(permission
, operation_type
, *it
, error
)) {
73 static void SetHostPatterns(
74 scoped_ptr
<SocketHostPatterns
>& host_patterns
,
75 const SocketsManifestPermission
* permission
,
76 content::SocketPermissionRequest::OperationType operation_type
) {
77 host_patterns
.reset(new SocketHostPatterns());
78 host_patterns
->as_strings
.reset(new std::vector
<std::string
>());
79 for (SocketsManifestPermission::SocketPermissionEntrySet::const_iterator it
=
80 permission
->entries().begin(); it
!= permission
->entries().end() ; ++it
) {
81 if (it
->pattern().type
== operation_type
) {
82 host_patterns
->as_strings
->push_back(it
->GetHostPatternAsString());
89 SocketsManifestPermission::SocketsManifestPermission() {}
91 SocketsManifestPermission::~SocketsManifestPermission() {}
94 scoped_ptr
<SocketsManifestPermission
> SocketsManifestPermission::FromValue(
95 const base::Value
& value
,
96 base::string16
* error
) {
97 scoped_ptr
<Sockets
> sockets
= Sockets::FromValue(value
, error
);
99 return scoped_ptr
<SocketsManifestPermission
>();
101 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
103 if (!ParseHostPatterns(result
.get(),
104 SocketPermissionRequest::UDP_BIND
,
107 return scoped_ptr
<SocketsManifestPermission
>();
109 if (!ParseHostPatterns(result
.get(),
110 SocketPermissionRequest::UDP_SEND_TO
,
113 return scoped_ptr
<SocketsManifestPermission
>();
115 if (!ParseHostPatterns(result
.get(),
116 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP
,
117 sockets
->udp
->multicast_membership
,
119 return scoped_ptr
<SocketsManifestPermission
>();
123 if (!ParseHostPatterns(result
.get(),
124 SocketPermissionRequest::TCP_CONNECT
,
125 sockets
->tcp
->connect
,
127 return scoped_ptr
<SocketsManifestPermission
>();
130 if (sockets
->tcp_server
) {
131 if (!ParseHostPatterns(result
.get(),
132 SocketPermissionRequest::TCP_LISTEN
,
133 sockets
->tcp_server
->listen
,
135 return scoped_ptr
<SocketsManifestPermission
>();
138 return result
.Pass();
141 bool SocketsManifestPermission::CheckRequest(
142 const Extension
* extension
,
143 const SocketPermissionRequest
& request
) const {
144 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
145 it
!= permissions_
.end(); ++it
) {
146 if (it
->Check(request
))
152 std::string
SocketsManifestPermission::name() const {
153 return manifest_keys::kSockets
;
156 std::string
SocketsManifestPermission::id() const {
160 bool SocketsManifestPermission::HasMessages() const {
161 bool is_empty
= permissions_
.empty();
165 PermissionMessages
SocketsManifestPermission::GetMessages() const {
166 // TODO(rpaquay): This function and callees is (almost) a copy/paste
167 // from extensions::SocketPermissiona.
168 PermissionMessages result
;
169 if (!AddAnyHostMessage(result
)) {
170 AddSpecificHostMessage(result
);
171 AddSubdomainHostMessage(result
);
173 AddNetworkListMessage(result
);
177 bool SocketsManifestPermission::FromValue(const base::Value
* value
) {
180 base::string16 error
;
181 scoped_ptr
<SocketsManifestPermission
> manifest_permission(
182 SocketsManifestPermission::FromValue(*value
, &error
));
184 if (!manifest_permission
)
187 permissions_
= manifest_permission
->permissions_
;
191 scoped_ptr
<base::Value
> SocketsManifestPermission::ToValue() const {
194 sockets
.udp
.reset(new Sockets::Udp());
195 SetHostPatterns(sockets
.udp
->bind
, this,
196 SocketPermissionRequest::UDP_BIND
);
197 SetHostPatterns(sockets
.udp
->send
, this,
198 SocketPermissionRequest::UDP_SEND_TO
);
199 SetHostPatterns(sockets
.udp
->multicast_membership
, this,
200 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP
);
201 if (sockets
.udp
->bind
->as_strings
->size() == 0 &&
202 sockets
.udp
->send
->as_strings
->size() == 0 &&
203 sockets
.udp
->multicast_membership
->as_strings
->size() == 0) {
204 sockets
.udp
.reset(NULL
);
207 sockets
.tcp
.reset(new Sockets::Tcp());
208 SetHostPatterns(sockets
.tcp
->connect
, this,
209 SocketPermissionRequest::TCP_CONNECT
);
210 if (sockets
.tcp
->connect
->as_strings
->size() == 0) {
211 sockets
.tcp
.reset(NULL
);
214 sockets
.tcp_server
.reset(new Sockets::TcpServer());
215 SetHostPatterns(sockets
.tcp_server
->listen
, this,
216 SocketPermissionRequest::TCP_LISTEN
);
217 if (sockets
.tcp_server
->listen
->as_strings
->size() == 0) {
218 sockets
.tcp_server
.reset(NULL
);
221 return scoped_ptr
<base::Value
>(sockets
.ToValue().release()).Pass();
224 ManifestPermission
* SocketsManifestPermission::Clone() const {
225 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
226 result
->permissions_
= permissions_
;
227 return result
.release();
230 ManifestPermission
* SocketsManifestPermission::Diff(
231 const ManifestPermission
* rhs
) const {
232 const SocketsManifestPermission
* other
=
233 static_cast<const SocketsManifestPermission
*>(rhs
);
235 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
236 result
->permissions_
= base::STLSetDifference
<SocketPermissionEntrySet
>(
237 permissions_
, other
->permissions_
);
238 return result
.release();
241 ManifestPermission
* SocketsManifestPermission::Union(
242 const ManifestPermission
* rhs
) const {
243 const SocketsManifestPermission
* other
=
244 static_cast<const SocketsManifestPermission
*>(rhs
);
246 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
247 result
->permissions_
= base::STLSetUnion
<SocketPermissionEntrySet
>(
248 permissions_
, other
->permissions_
);
249 return result
.release();
252 ManifestPermission
* SocketsManifestPermission::Intersect(
253 const ManifestPermission
* rhs
) const {
254 const SocketsManifestPermission
* other
=
255 static_cast<const SocketsManifestPermission
*>(rhs
);
257 scoped_ptr
<SocketsManifestPermission
> result(new SocketsManifestPermission());
258 result
->permissions_
= base::STLSetIntersection
<SocketPermissionEntrySet
>(
259 permissions_
, other
->permissions_
);
260 return result
.release();
263 bool SocketsManifestPermission::Contains(const ManifestPermission
* rhs
) const {
264 const SocketsManifestPermission
* other
=
265 static_cast<const SocketsManifestPermission
*>(rhs
);
267 return base::STLIncludes
<SocketPermissionEntrySet
>(permissions_
,
268 other
->permissions_
);
271 bool SocketsManifestPermission::Equal(const ManifestPermission
* rhs
) const {
272 const SocketsManifestPermission
* other
=
273 static_cast<const SocketsManifestPermission
*>(rhs
);
275 return (permissions_
== other
->permissions_
);
278 void SocketsManifestPermission::Write(IPC::Message
* m
) const {
279 IPC::WriteParam(m
, permissions_
);
282 bool SocketsManifestPermission::Read(const IPC::Message
* m
,
283 PickleIterator
* iter
) {
284 return IPC::ReadParam(m
, iter
, &permissions_
);
287 void SocketsManifestPermission::Log(std::string
* log
) const {
288 IPC::LogParam(permissions_
, log
);
291 void SocketsManifestPermission::AddPermission(
292 const SocketPermissionEntry
& entry
) {
293 permissions_
.insert(entry
);
296 bool SocketsManifestPermission::AddAnyHostMessage(
297 PermissionMessages
& messages
) const {
298 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
299 it
!= permissions_
.end(); ++it
) {
300 if (it
->IsAddressBoundType() &&
301 it
->GetHostType() == SocketPermissionEntry::ANY_HOST
) {
302 messages
.push_back(PermissionMessage(
303 PermissionMessage::kSocketAnyHost
,
304 l10n_util::GetStringUTF16(
305 IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST
)));
312 void SocketsManifestPermission::AddSubdomainHostMessage(
313 PermissionMessages
& messages
) const {
314 std::set
<base::string16
> domains
;
315 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
316 it
!= permissions_
.end(); ++it
) {
317 if (it
->GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS
)
318 domains
.insert(base::UTF8ToUTF16(it
->pattern().host
));
320 if (!domains
.empty()) {
321 int id
= (domains
.size() == 1) ?
322 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN
:
323 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS
;
324 messages
.push_back(PermissionMessage(
325 PermissionMessage::kSocketDomainHosts
,
326 l10n_util::GetStringFUTF16(
329 std::vector
<base::string16
>(
330 domains
.begin(), domains
.end()), ' '))));
334 void SocketsManifestPermission::AddSpecificHostMessage(
335 PermissionMessages
& messages
) const {
336 std::set
<base::string16
> hostnames
;
337 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
338 it
!= permissions_
.end(); ++it
) {
339 if (it
->GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS
)
340 hostnames
.insert(base::UTF8ToUTF16(it
->pattern().host
));
342 if (!hostnames
.empty()) {
343 int id
= (hostnames
.size() == 1) ?
344 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST
:
345 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS
;
346 messages
.push_back(PermissionMessage(
347 PermissionMessage::kSocketSpecificHosts
,
348 l10n_util::GetStringFUTF16(
351 std::vector
<base::string16
>(
352 hostnames
.begin(), hostnames
.end()), ' '))));
356 void SocketsManifestPermission::AddNetworkListMessage(
357 PermissionMessages
& messages
) const {
358 for (SocketPermissionEntrySet::const_iterator it
= permissions_
.begin();
359 it
!= permissions_
.end(); ++it
) {
360 if (it
->pattern().type
== SocketPermissionRequest::NETWORK_STATE
) {
361 messages
.push_back(PermissionMessage(
362 PermissionMessage::kNetworkState
,
363 l10n_util::GetStringUTF16(
364 IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE
)));
369 } // namespace extensions