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/manifest_constants.h"
15 #include "grit/extensions_strings.h"
16 #include "ipc/ipc_message.h"
17 #include "ui/base/l10n/l10n_util.h"
19 namespace extensions {
21 namespace sockets_errors {
22 const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'";
25 namespace errors = sockets_errors;
26 using core_api::extensions_manifest_types::Sockets;
27 using core_api::extensions_manifest_types::SocketHostPatterns;
28 using content::SocketPermissionRequest;
32 static bool ParseHostPattern(
33 SocketsManifestPermission* permission,
34 content::SocketPermissionRequest::OperationType operation_type,
35 const std::string& host_pattern,
36 base::string16* error) {
37 SocketPermissionEntry entry;
38 if (!SocketPermissionEntry::ParseHostPattern(
39 operation_type, host_pattern, &entry)) {
40 *error = ErrorUtils::FormatErrorMessageUTF16(
41 errors::kErrorInvalidHostPattern, host_pattern);
44 permission->AddPermission(entry);
48 static bool ParseHostPatterns(
49 SocketsManifestPermission* permission,
50 content::SocketPermissionRequest::OperationType operation_type,
51 const scoped_ptr<SocketHostPatterns>& host_patterns,
52 base::string16* error) {
56 if (host_patterns->as_string) {
57 return ParseHostPattern(
58 permission, operation_type, *host_patterns->as_string, error);
61 CHECK(host_patterns->as_strings);
62 for (std::vector<std::string>::const_iterator it =
63 host_patterns->as_strings->begin();
64 it != host_patterns->as_strings->end();
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();
81 it != permission->entries().end();
83 if (it->pattern().type == operation_type) {
84 host_patterns->as_strings->push_back(it->GetHostPatternAsString());
91 SocketsManifestPermission::SocketsManifestPermission() {}
93 SocketsManifestPermission::~SocketsManifestPermission() {}
96 scoped_ptr<SocketsManifestPermission> SocketsManifestPermission::FromValue(
97 const base::Value& value,
98 base::string16* error) {
99 scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error);
101 return scoped_ptr<SocketsManifestPermission>();
103 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
105 if (!ParseHostPatterns(result.get(),
106 SocketPermissionRequest::UDP_BIND,
109 return scoped_ptr<SocketsManifestPermission>();
111 if (!ParseHostPatterns(result.get(),
112 SocketPermissionRequest::UDP_SEND_TO,
115 return scoped_ptr<SocketsManifestPermission>();
117 if (!ParseHostPatterns(result.get(),
118 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP,
119 sockets->udp->multicast_membership,
121 return scoped_ptr<SocketsManifestPermission>();
125 if (!ParseHostPatterns(result.get(),
126 SocketPermissionRequest::TCP_CONNECT,
127 sockets->tcp->connect,
129 return scoped_ptr<SocketsManifestPermission>();
132 if (sockets->tcp_server) {
133 if (!ParseHostPatterns(result.get(),
134 SocketPermissionRequest::TCP_LISTEN,
135 sockets->tcp_server->listen,
137 return scoped_ptr<SocketsManifestPermission>();
140 return result.Pass();
143 bool SocketsManifestPermission::CheckRequest(
144 const Extension* extension,
145 const SocketPermissionRequest& request) const {
146 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
147 it != permissions_.end();
149 if (it->Check(request))
155 std::string SocketsManifestPermission::name() const {
156 return manifest_keys::kSockets;
159 std::string SocketsManifestPermission::id() const { return name(); }
161 bool SocketsManifestPermission::HasMessages() const {
162 bool is_empty = permissions_.empty();
166 PermissionMessages SocketsManifestPermission::GetMessages() const {
167 // TODO(rpaquay): This function and callees is (almost) a copy/paste
168 // from extensions::SocketPermissiona.
169 PermissionMessages result;
170 if (!AddAnyHostMessage(result)) {
171 AddSpecificHostMessage(result);
172 AddSubdomainHostMessage(result);
174 AddNetworkListMessage(result);
178 bool SocketsManifestPermission::FromValue(const base::Value* value) {
181 base::string16 error;
182 scoped_ptr<SocketsManifestPermission> manifest_permission(
183 SocketsManifestPermission::FromValue(*value, &error));
185 if (!manifest_permission)
188 permissions_ = manifest_permission->permissions_;
192 scoped_ptr<base::Value> SocketsManifestPermission::ToValue() const {
195 sockets.udp.reset(new Sockets::Udp());
196 SetHostPatterns(sockets.udp->bind, this, SocketPermissionRequest::UDP_BIND);
198 sockets.udp->send, this, SocketPermissionRequest::UDP_SEND_TO);
199 SetHostPatterns(sockets.udp->multicast_membership,
201 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP);
202 if (sockets.udp->bind->as_strings->size() == 0 &&
203 sockets.udp->send->as_strings->size() == 0 &&
204 sockets.udp->multicast_membership->as_strings->size() == 0) {
205 sockets.udp.reset(NULL);
208 sockets.tcp.reset(new Sockets::Tcp());
210 sockets.tcp->connect, this, SocketPermissionRequest::TCP_CONNECT);
211 if (sockets.tcp->connect->as_strings->size() == 0) {
212 sockets.tcp.reset(NULL);
215 sockets.tcp_server.reset(new Sockets::TcpServer());
217 sockets.tcp_server->listen, this, SocketPermissionRequest::TCP_LISTEN);
218 if (sockets.tcp_server->listen->as_strings->size() == 0) {
219 sockets.tcp_server.reset(NULL);
222 return scoped_ptr<base::Value>(sockets.ToValue().release()).Pass();
225 ManifestPermission* SocketsManifestPermission::Diff(
226 const ManifestPermission* rhs) const {
227 const SocketsManifestPermission* other =
228 static_cast<const SocketsManifestPermission*>(rhs);
230 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
231 result->permissions_ = base::STLSetDifference<SocketPermissionEntrySet>(
232 permissions_, other->permissions_);
233 return result.release();
236 ManifestPermission* SocketsManifestPermission::Union(
237 const ManifestPermission* rhs) const {
238 const SocketsManifestPermission* other =
239 static_cast<const SocketsManifestPermission*>(rhs);
241 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
242 result->permissions_ = base::STLSetUnion<SocketPermissionEntrySet>(
243 permissions_, other->permissions_);
244 return result.release();
247 ManifestPermission* SocketsManifestPermission::Intersect(
248 const ManifestPermission* rhs) const {
249 const SocketsManifestPermission* other =
250 static_cast<const SocketsManifestPermission*>(rhs);
252 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission());
253 result->permissions_ = base::STLSetIntersection<SocketPermissionEntrySet>(
254 permissions_, other->permissions_);
255 return result.release();
258 void SocketsManifestPermission::AddPermission(
259 const SocketPermissionEntry& entry) {
260 permissions_.insert(entry);
263 bool SocketsManifestPermission::AddAnyHostMessage(
264 PermissionMessages& messages) const {
265 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
266 it != permissions_.end();
268 if (it->IsAddressBoundType() &&
269 it->GetHostType() == SocketPermissionEntry::ANY_HOST) {
271 PermissionMessage(PermissionMessage::kSocketAnyHost,
272 l10n_util::GetStringUTF16(
273 IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST)));
280 void SocketsManifestPermission::AddSubdomainHostMessage(
281 PermissionMessages& messages) const {
282 std::set<base::string16> domains;
283 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
284 it != permissions_.end();
286 if (it->GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS)
287 domains.insert(base::UTF8ToUTF16(it->pattern().host));
289 if (!domains.empty()) {
290 int id = (domains.size() == 1)
291 ? IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN
292 : IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS;
293 messages.push_back(PermissionMessage(
294 PermissionMessage::kSocketDomainHosts,
295 l10n_util::GetStringFUTF16(
298 std::vector<base::string16>(domains.begin(), domains.end()),
303 void SocketsManifestPermission::AddSpecificHostMessage(
304 PermissionMessages& messages) const {
305 std::set<base::string16> hostnames;
306 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
307 it != permissions_.end();
309 if (it->GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS)
310 hostnames.insert(base::UTF8ToUTF16(it->pattern().host));
312 if (!hostnames.empty()) {
313 int id = (hostnames.size() == 1)
314 ? IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST
315 : IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS;
316 messages.push_back(PermissionMessage(
317 PermissionMessage::kSocketSpecificHosts,
318 l10n_util::GetStringFUTF16(
321 std::vector<base::string16>(hostnames.begin(), hostnames.end()),
326 void SocketsManifestPermission::AddNetworkListMessage(
327 PermissionMessages& messages) const {
328 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin();
329 it != permissions_.end();
331 if (it->pattern().type == SocketPermissionRequest::NETWORK_STATE) {
333 PermissionMessage(PermissionMessage::kNetworkState,
334 l10n_util::GetStringUTF16(
335 IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE)));
340 } // namespace extensions