OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/common/extensions/api/sockets/sockets_manifest_permission.h" | |
6 | |
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" | |
19 | |
20 namespace extensions { | |
21 | |
22 namespace sockets_errors { | |
23 const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'"; | |
24 } | |
25 | |
26 namespace errors = sockets_errors; | |
27 using api::manifest_types::Sockets; | |
28 using api::manifest_types::SocketHostPatterns; | |
29 using content::SocketPermissionRequest; | |
30 | |
31 namespace { | |
32 | |
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); | |
43 return false; | |
44 } | |
45 permission->AddPermission(entry); | |
46 return true; | |
47 } | |
48 | |
49 static bool ParseHostPatterns( | |
50 SocketsManifestPermission* permission, | |
51 content::SocketPermissionRequest::OperationType operation_type, | |
52 const scoped_ptr<SocketHostPatterns>& host_patterns, | |
53 base::string16* error) { | |
54 if (!host_patterns) | |
55 return true; | |
56 | |
57 if (host_patterns->as_string) { | |
58 return ParseHostPattern(permission, operation_type, | |
59 *host_patterns->as_string, error); | |
60 } | |
61 | |
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)) { | |
67 return false; | |
68 } | |
69 } | |
70 return true; | |
71 } | |
72 | |
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()); | |
83 } | |
84 } | |
85 } | |
86 | |
87 } // namespace | |
88 | |
89 SocketsManifestPermission::SocketsManifestPermission() {} | |
90 | |
91 SocketsManifestPermission::~SocketsManifestPermission() {} | |
92 | |
93 // static | |
94 scoped_ptr<SocketsManifestPermission> SocketsManifestPermission::FromValue( | |
95 const base::Value& value, | |
96 base::string16* error) { | |
97 scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error); | |
98 if (!sockets) | |
99 return scoped_ptr<SocketsManifestPermission>(); | |
100 | |
101 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); | |
102 if (sockets->udp) { | |
103 if (!ParseHostPatterns(result.get(), | |
104 SocketPermissionRequest::UDP_BIND, | |
105 sockets->udp->bind, | |
106 error)) { | |
107 return scoped_ptr<SocketsManifestPermission>(); | |
108 } | |
109 if (!ParseHostPatterns(result.get(), | |
110 SocketPermissionRequest::UDP_SEND_TO, | |
111 sockets->udp->send, | |
112 error)) { | |
113 return scoped_ptr<SocketsManifestPermission>(); | |
114 } | |
115 if (!ParseHostPatterns(result.get(), | |
116 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, | |
117 sockets->udp->multicast_membership, | |
118 error)) { | |
119 return scoped_ptr<SocketsManifestPermission>(); | |
120 } | |
121 } | |
122 if (sockets->tcp) { | |
123 if (!ParseHostPatterns(result.get(), | |
124 SocketPermissionRequest::TCP_CONNECT, | |
125 sockets->tcp->connect, | |
126 error)) { | |
127 return scoped_ptr<SocketsManifestPermission>(); | |
128 } | |
129 } | |
130 if (sockets->tcp_server) { | |
131 if (!ParseHostPatterns(result.get(), | |
132 SocketPermissionRequest::TCP_LISTEN, | |
133 sockets->tcp_server->listen, | |
134 error)) { | |
135 return scoped_ptr<SocketsManifestPermission>(); | |
136 } | |
137 } | |
138 return result.Pass(); | |
139 } | |
140 | |
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)) | |
147 return true; | |
148 } | |
149 return false; | |
150 } | |
151 | |
152 std::string SocketsManifestPermission::name() const { | |
153 return manifest_keys::kSockets; | |
154 } | |
155 | |
156 std::string SocketsManifestPermission::id() const { | |
157 return name(); | |
158 } | |
159 | |
160 bool SocketsManifestPermission::HasMessages() const { | |
161 bool is_empty = permissions_.empty(); | |
162 return !is_empty; | |
163 } | |
164 | |
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); | |
172 } | |
173 AddNetworkListMessage(result); | |
174 return result; | |
175 } | |
176 | |
177 bool SocketsManifestPermission::FromValue(const base::Value* value) { | |
178 if (!value) | |
179 return false; | |
180 base::string16 error; | |
181 scoped_ptr<SocketsManifestPermission> manifest_permission( | |
182 SocketsManifestPermission::FromValue(*value, &error)); | |
183 | |
184 if (!manifest_permission) | |
185 return false; | |
186 | |
187 permissions_ = manifest_permission->permissions_; | |
188 return true; | |
189 } | |
190 | |
191 scoped_ptr<base::Value> SocketsManifestPermission::ToValue() const { | |
192 Sockets sockets; | |
193 | |
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); | |
205 } | |
206 | |
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); | |
212 } | |
213 | |
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); | |
219 } | |
220 | |
221 return scoped_ptr<base::Value>(sockets.ToValue().release()).Pass(); | |
222 } | |
223 | |
224 ManifestPermission* SocketsManifestPermission::Clone() const { | |
225 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); | |
226 result->permissions_ = permissions_; | |
227 return result.release(); | |
228 } | |
229 | |
230 ManifestPermission* SocketsManifestPermission::Diff( | |
231 const ManifestPermission* rhs) const { | |
232 const SocketsManifestPermission* other = | |
233 static_cast<const SocketsManifestPermission*>(rhs); | |
234 | |
235 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); | |
236 result->permissions_ = base::STLSetDifference<SocketPermissionEntrySet>( | |
237 permissions_, other->permissions_); | |
238 return result.release(); | |
239 } | |
240 | |
241 ManifestPermission* SocketsManifestPermission::Union( | |
242 const ManifestPermission* rhs) const { | |
243 const SocketsManifestPermission* other = | |
244 static_cast<const SocketsManifestPermission*>(rhs); | |
245 | |
246 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); | |
247 result->permissions_ = base::STLSetUnion<SocketPermissionEntrySet>( | |
248 permissions_, other->permissions_); | |
249 return result.release(); | |
250 } | |
251 | |
252 ManifestPermission* SocketsManifestPermission::Intersect( | |
253 const ManifestPermission* rhs) const { | |
254 const SocketsManifestPermission* other = | |
255 static_cast<const SocketsManifestPermission*>(rhs); | |
256 | |
257 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); | |
258 result->permissions_ = base::STLSetIntersection<SocketPermissionEntrySet>( | |
259 permissions_, other->permissions_); | |
260 return result.release(); | |
261 } | |
262 | |
263 bool SocketsManifestPermission::Contains(const ManifestPermission* rhs) const { | |
264 const SocketsManifestPermission* other = | |
265 static_cast<const SocketsManifestPermission*>(rhs); | |
266 | |
267 return base::STLIncludes<SocketPermissionEntrySet>(permissions_, | |
268 other->permissions_); | |
269 } | |
270 | |
271 bool SocketsManifestPermission::Equal(const ManifestPermission* rhs) const { | |
272 const SocketsManifestPermission* other = | |
273 static_cast<const SocketsManifestPermission*>(rhs); | |
274 | |
275 return (permissions_ == other->permissions_); | |
276 } | |
277 | |
278 void SocketsManifestPermission::Write(IPC::Message* m) const { | |
279 IPC::WriteParam(m, permissions_); | |
280 } | |
281 | |
282 bool SocketsManifestPermission::Read(const IPC::Message* m, | |
283 PickleIterator* iter) { | |
284 return IPC::ReadParam(m, iter, &permissions_); | |
285 } | |
286 | |
287 void SocketsManifestPermission::Log(std::string* log) const { | |
288 IPC::LogParam(permissions_, log); | |
289 } | |
290 | |
291 void SocketsManifestPermission::AddPermission( | |
292 const SocketPermissionEntry& entry) { | |
293 permissions_.insert(entry); | |
294 } | |
295 | |
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))); | |
306 return true; | |
307 } | |
308 } | |
309 return false; | |
310 } | |
311 | |
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)); | |
319 } | |
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( | |
327 id, | |
328 JoinString( | |
329 std::vector<base::string16>( | |
330 domains.begin(), domains.end()), ' ')))); | |
331 } | |
332 } | |
333 | |
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)); | |
341 } | |
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( | |
349 id, | |
350 JoinString( | |
351 std::vector<base::string16>( | |
352 hostnames.begin(), hostnames.end()), ' ')))); | |
353 } | |
354 } | |
355 | |
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))); | |
365 } | |
366 } | |
367 } | |
368 | |
369 } // namespace extensions | |
OLD | NEW |