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/strings/utf_string_conversions.h" |
| 9 #include "base/values.h" |
| 10 #include "chrome/common/extensions/api/manifest_types.h" |
| 11 #include "chrome/common/extensions/api/sockets/sockets_manifest_data.h" |
| 12 #include "chrome/common/extensions/extension_messages.h" |
| 13 #include "extensions/common/error_utils.h" |
| 14 #include "extensions/common/manifest_constants.h" |
| 15 #include "grit/generated_resources.h" |
| 16 #include "ipc/ipc_message.h" |
| 17 #include "ui/base/l10n/l10n_util.h" |
| 18 |
| 19 namespace extensions { |
| 20 |
| 21 namespace sockets_errors { |
| 22 const char kErrorInvalidHostPattern[] = "Invalid host:port pattern '*'"; |
| 23 } |
| 24 |
| 25 namespace errors = sockets_errors; |
| 26 using api::manifest_types::Sockets; |
| 27 using content::SocketPermissionRequest; |
| 28 |
| 29 SocketsManifestPermission::SocketsManifestPermission() |
| 30 : kinds_(kNone) { |
| 31 } |
| 32 |
| 33 SocketsManifestPermission::~SocketsManifestPermission() {} |
| 34 |
| 35 // static |
| 36 scoped_ptr<SocketsManifestPermission> SocketsManifestPermission::FromValue( |
| 37 const base::Value& value, |
| 38 string16* error) { |
| 39 scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error); |
| 40 if (!sockets) |
| 41 return scoped_ptr<SocketsManifestPermission>(); |
| 42 |
| 43 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); |
| 44 if (sockets->udp) { |
| 45 result->kinds_ |= kUdpPermission; |
| 46 if (!ParseHostPattern(result.get(), |
| 47 SocketPermissionRequest::UDP_BIND, |
| 48 sockets->udp->bind, |
| 49 error)) { |
| 50 return scoped_ptr<SocketsManifestPermission>(); |
| 51 } |
| 52 if (!ParseHostPattern(result.get(), |
| 53 SocketPermissionRequest::UDP_SEND_TO, |
| 54 sockets->udp->send, |
| 55 error)) { |
| 56 return scoped_ptr<SocketsManifestPermission>(); |
| 57 } |
| 58 if (!ParseHostPattern(result.get(), |
| 59 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, |
| 60 sockets->udp->multicast_membership, |
| 61 error)) { |
| 62 return scoped_ptr<SocketsManifestPermission>(); |
| 63 } |
| 64 } |
| 65 if (sockets->tcp) { |
| 66 result->kinds_ |= kTcpPermission; |
| 67 if (!ParseHostPattern(result.get(), |
| 68 SocketPermissionRequest::TCP_CONNECT, |
| 69 sockets->tcp->connect, |
| 70 error)) { |
| 71 return scoped_ptr<SocketsManifestPermission>(); |
| 72 } |
| 73 } |
| 74 if (sockets->tcp_server) { |
| 75 result->kinds_ |= kTcpServerPermission; |
| 76 if (!ParseHostPattern(result.get(), |
| 77 SocketPermissionRequest::TCP_LISTEN, |
| 78 sockets->tcp_server->listen, |
| 79 error)) { |
| 80 return scoped_ptr<SocketsManifestPermission>(); |
| 81 } |
| 82 } |
| 83 return result.Pass(); |
| 84 } |
| 85 |
| 86 bool SocketsManifestPermission::CheckRequest( |
| 87 const Extension* extension, |
| 88 const SocketPermissionRequest& request) const { |
| 89 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin(); |
| 90 it != permissions_.end(); ++it) { |
| 91 if (it->Check(request)) |
| 92 return true; |
| 93 } |
| 94 return false; |
| 95 } |
| 96 |
| 97 std::string SocketsManifestPermission::name() const { |
| 98 return manifest_keys::kSockets; |
| 99 } |
| 100 |
| 101 std::string SocketsManifestPermission::id() const { |
| 102 return name(); |
| 103 } |
| 104 |
| 105 bool SocketsManifestPermission::HasMessages() const { |
| 106 bool is_empty = permissions_.empty() && (kinds_ == kNone); |
| 107 return !is_empty; |
| 108 } |
| 109 |
| 110 PermissionMessages SocketsManifestPermission::GetMessages() const { |
| 111 // TODO(rpaquay): This function and callees is (almost) a copy/paste |
| 112 // from extensions::SocketPermissiona. |
| 113 PermissionMessages result; |
| 114 if (!AddAnyHostMessage(result)) { |
| 115 AddSpecificHostMessage(result); |
| 116 AddSubdomainHostMessage(result); |
| 117 } |
| 118 AddNetworkListMessage(result); |
| 119 return result; |
| 120 } |
| 121 |
| 122 bool SocketsManifestPermission::FromValue(const base::Value* value) { |
| 123 if (!value) |
| 124 return false; |
| 125 string16 error; |
| 126 scoped_ptr<SocketsManifestPermission> data( |
| 127 SocketsManifestPermission::FromValue(*value, &error)); |
| 128 |
| 129 if (!data) |
| 130 return false; |
| 131 |
| 132 permissions_ = data->permissions_; |
| 133 kinds_ = data->kinds_; |
| 134 return true; |
| 135 } |
| 136 |
| 137 scoped_ptr<base::Value> SocketsManifestPermission::ToValue() const { |
| 138 Sockets sockets; |
| 139 if (has_udp()) { |
| 140 sockets.udp.reset(new Sockets::Udp()); |
| 141 sockets.udp->bind = CreateHostPattern(SocketPermissionRequest::UDP_BIND); |
| 142 sockets.udp->send = CreateHostPattern(SocketPermissionRequest::UDP_SEND_TO); |
| 143 sockets.udp->multicast_membership = |
| 144 CreateHostPattern(SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP); |
| 145 } |
| 146 if (has_tcp()) { |
| 147 sockets.tcp.reset(new Sockets::Tcp()); |
| 148 sockets.tcp->connect = |
| 149 CreateHostPattern(SocketPermissionRequest::TCP_CONNECT); |
| 150 } |
| 151 if (has_tcp_server()) { |
| 152 sockets.tcp_server.reset(new Sockets::TcpServer()); |
| 153 sockets.tcp_server->listen = |
| 154 CreateHostPattern(SocketPermissionRequest::TCP_LISTEN); |
| 155 } |
| 156 |
| 157 return scoped_ptr<base::Value>(sockets.ToValue().release()).Pass(); |
| 158 } |
| 159 |
| 160 ManifestPermission* SocketsManifestPermission::Clone() const { |
| 161 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); |
| 162 result->permissions_ = permissions_; |
| 163 result->kinds_ = kinds_; |
| 164 return result.release(); |
| 165 } |
| 166 |
| 167 ManifestPermission* SocketsManifestPermission::Diff( |
| 168 const ManifestPermission* rhs) const { |
| 169 const SocketsManifestPermission* other = |
| 170 static_cast<const SocketsManifestPermission*>(rhs); |
| 171 |
| 172 scoped_ptr<SocketsManifestPermission> data(new SocketsManifestPermission()); |
| 173 std::set_difference( |
| 174 permissions_.begin(), permissions_.end(), |
| 175 other->permissions_.begin(), other->permissions_.end(), |
| 176 std::inserter<SocketPermissionEntrySet>( |
| 177 data->permissions_, data->permissions_.begin())); |
| 178 |
| 179 data->kinds_ = (kinds_ & (~other->kinds_)); |
| 180 |
| 181 // Note: We may need to fix up |kinds_| because any permission entry |
| 182 // in a given group (udp, tcp, etc.) implies the corresponding kind bit set. |
| 183 data->kinds_ |= HasOperationType(data->permissions_, |
| 184 SocketPermissionRequest::UDP_BIND, kUdpPermission); |
| 185 data->kinds_ |= HasOperationType(data->permissions_, |
| 186 SocketPermissionRequest::UDP_SEND_TO, kUdpPermission); |
| 187 data->kinds_ |= HasOperationType(data->permissions_, |
| 188 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, kUdpPermission); |
| 189 data->kinds_ |= HasOperationType(data->permissions_, |
| 190 SocketPermissionRequest::TCP_CONNECT, kTcpPermission); |
| 191 data->kinds_ |= HasOperationType(data->permissions_, |
| 192 SocketPermissionRequest::TCP_LISTEN, kTcpServerPermission); |
| 193 return data.release(); |
| 194 } |
| 195 |
| 196 ManifestPermission* SocketsManifestPermission::Union( |
| 197 const ManifestPermission* rhs) const { |
| 198 const SocketsManifestPermission* other = |
| 199 static_cast<const SocketsManifestPermission*>(rhs); |
| 200 |
| 201 scoped_ptr<SocketsManifestPermission> data(new SocketsManifestPermission()); |
| 202 std::set_union( |
| 203 permissions_.begin(), permissions_.end(), |
| 204 other->permissions_.begin(), other->permissions_.end(), |
| 205 std::inserter<SocketPermissionEntrySet>( |
| 206 data->permissions_, data->permissions_.begin())); |
| 207 |
| 208 data->kinds_ = (kinds_ | other->kinds_); |
| 209 return data.release(); |
| 210 } |
| 211 |
| 212 ManifestPermission* SocketsManifestPermission::Intersect( |
| 213 const ManifestPermission* rhs) const { |
| 214 const SocketsManifestPermission* other = |
| 215 static_cast<const SocketsManifestPermission*>(rhs); |
| 216 |
| 217 scoped_ptr<SocketsManifestPermission> data(new SocketsManifestPermission()); |
| 218 std::set_intersection( |
| 219 permissions_.begin(), permissions_.end(), |
| 220 other->permissions_.begin(), other->permissions_.end(), |
| 221 std::inserter<SocketPermissionEntrySet>( |
| 222 data->permissions_, data->permissions_.begin())); |
| 223 |
| 224 data->kinds_ = (kinds_ & other->kinds_); |
| 225 return data.release(); |
| 226 } |
| 227 |
| 228 bool SocketsManifestPermission::Contains(const ManifestPermission* rhs) const { |
| 229 const SocketsManifestPermission* other = |
| 230 static_cast<const SocketsManifestPermission*>(rhs); |
| 231 |
| 232 return std::includes( |
| 233 permissions_.begin(), permissions_.end(), |
| 234 other->permissions_.begin(), other->permissions_.end()) && |
| 235 ((kinds_ | other->kinds_) == kinds_); |
| 236 } |
| 237 |
| 238 bool SocketsManifestPermission::Equal(const ManifestPermission* rhs) const { |
| 239 const SocketsManifestPermission* other = |
| 240 static_cast<const SocketsManifestPermission*>(rhs); |
| 241 |
| 242 return (permissions_ == other->permissions_) && |
| 243 (kinds_ == other->kinds_); |
| 244 } |
| 245 |
| 246 void SocketsManifestPermission::Write(IPC::Message* m) const { |
| 247 IPC::WriteParam(m, permissions_); |
| 248 IPC::WriteParam(m, kinds_); |
| 249 } |
| 250 |
| 251 bool SocketsManifestPermission::Read(const IPC::Message* m, |
| 252 PickleIterator* iter) { |
| 253 return IPC::ReadParam(m, iter, &permissions_) && |
| 254 IPC::ReadParam(m, iter, &kinds_); |
| 255 } |
| 256 |
| 257 void SocketsManifestPermission::Log(std::string* log) const { |
| 258 IPC::LogParam(permissions_, log); |
| 259 IPC::LogParam(kinds_, log); |
| 260 } |
| 261 |
| 262 // static |
| 263 bool SocketsManifestPermission::ParseHostPattern( |
| 264 SocketsManifestPermission* manifest_data, |
| 265 SocketPermissionRequest::OperationType operation_type, |
| 266 const scoped_ptr<std::string>& value, |
| 267 string16* error) { |
| 268 if (value) { |
| 269 SocketPermissionEntry entry; |
| 270 if (!SocketPermissionEntry::ParseHostPattern( |
| 271 operation_type, *value, &entry)) { |
| 272 *error = ErrorUtils::FormatErrorMessageUTF16( |
| 273 errors::kErrorInvalidHostPattern, *value); |
| 274 return false; |
| 275 } |
| 276 manifest_data->AddPermission(entry); |
| 277 } |
| 278 return true; |
| 279 } |
| 280 |
| 281 // static |
| 282 SocketsManifestPermission::PermissionKind SocketsManifestPermission:: |
| 283 HasOperationType(const SocketPermissionEntrySet& set, |
| 284 SocketPermissionRequest::OperationType operation_type, |
| 285 PermissionKind kind) { |
| 286 for (SocketPermissionEntrySet::const_iterator it = set.begin(); |
| 287 it != set.end() ; ++it) { |
| 288 if (it->pattern().type == operation_type) |
| 289 return kind; |
| 290 } |
| 291 return kNone; |
| 292 } |
| 293 |
| 294 |
| 295 scoped_ptr<std::string> SocketsManifestPermission::CreateHostPattern( |
| 296 SocketPermissionRequest::OperationType operation_type) const { |
| 297 scoped_ptr<std::string> result; |
| 298 for (SocketPermissionEntrySet::const_iterator it = |
| 299 entries().begin(); it != entries().end() ; ++it) { |
| 300 if (it->pattern().type == operation_type) { |
| 301 result.reset(new std::string(it->GetHostPatternAsString())); |
| 302 break; |
| 303 } |
| 304 } |
| 305 return result.Pass(); |
| 306 } |
| 307 |
| 308 void SocketsManifestPermission::AddPermission( |
| 309 const SocketPermissionEntry& entry) { |
| 310 permissions_.insert(entry); |
| 311 } |
| 312 |
| 313 bool SocketsManifestPermission::AddAnyHostMessage( |
| 314 PermissionMessages& messages) const { |
| 315 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin(); |
| 316 it != permissions_.end(); ++it) { |
| 317 if (it->IsAddressBoundType() && |
| 318 it->GetHostType() == SocketPermissionEntry::ANY_HOST) { |
| 319 messages.push_back(PermissionMessage( |
| 320 PermissionMessage::kSocketAnyHost, |
| 321 l10n_util::GetStringUTF16( |
| 322 IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST))); |
| 323 return true; |
| 324 } |
| 325 } |
| 326 return false; |
| 327 } |
| 328 |
| 329 void SocketsManifestPermission::AddSubdomainHostMessage( |
| 330 PermissionMessages& messages) const { |
| 331 std::set<string16> domains; |
| 332 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin(); |
| 333 it != permissions_.end(); ++it) { |
| 334 if (it->GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS) |
| 335 domains.insert(UTF8ToUTF16(it->pattern().host)); |
| 336 } |
| 337 if (!domains.empty()) { |
| 338 int id = (domains.size() == 1) ? |
| 339 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAIN : |
| 340 IDS_EXTENSION_PROMPT_WARNING_SOCKET_HOSTS_IN_DOMAINS; |
| 341 messages.push_back(PermissionMessage( |
| 342 PermissionMessage::kSocketDomainHosts, |
| 343 l10n_util::GetStringFUTF16( |
| 344 id, |
| 345 JoinString( |
| 346 std::vector<string16>( |
| 347 domains.begin(), domains.end()), ' ')))); |
| 348 } |
| 349 } |
| 350 |
| 351 void SocketsManifestPermission::AddSpecificHostMessage( |
| 352 PermissionMessages& messages) const { |
| 353 std::set<string16> hostnames; |
| 354 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin(); |
| 355 it != permissions_.end(); ++it) { |
| 356 if (it->GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS) |
| 357 hostnames.insert(UTF8ToUTF16(it->pattern().host)); |
| 358 } |
| 359 if (!hostnames.empty()) { |
| 360 int id = (hostnames.size() == 1) ? |
| 361 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOST : |
| 362 IDS_EXTENSION_PROMPT_WARNING_SOCKET_SPECIFIC_HOSTS; |
| 363 messages.push_back(PermissionMessage( |
| 364 PermissionMessage::kSocketSpecificHosts, |
| 365 l10n_util::GetStringFUTF16( |
| 366 id, |
| 367 JoinString( |
| 368 std::vector<string16>( |
| 369 hostnames.begin(), hostnames.end()), ' ')))); |
| 370 } |
| 371 } |
| 372 |
| 373 void SocketsManifestPermission::AddNetworkListMessage( |
| 374 PermissionMessages& messages) const { |
| 375 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin(); |
| 376 it != permissions_.end(); ++it) { |
| 377 if (it->pattern().type == SocketPermissionRequest::NETWORK_STATE) { |
| 378 messages.push_back(PermissionMessage( |
| 379 PermissionMessage::kNetworkState, |
| 380 l10n_util::GetStringUTF16( |
| 381 IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE))); |
| 382 } |
| 383 } |
| 384 } |
| 385 |
| 386 } // namespace extensions |
OLD | NEW |