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. 4 5 #include "extensions/common/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 "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" 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 core_api::extensions_manifest_types::Sockets; 27 using core_api::extensions_manifest_types::SocketHostPatterns; 28 using content::SocketPermissionRequest; 29 30 namespace { 31 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); 42 return false; 43 } 44 permission->AddPermission(entry); 45 return true; 46 } 47 48 static bool ParseHostPatterns( 49 SocketsManifestPermission* permission, 50 content::SocketPermissionRequest::OperationType operation_type, 51 const scoped_ptr<SocketHostPatterns>& host_patterns, 52 base::string16* error) { 53 if (!host_patterns) 54 return true; 55 56 if (host_patterns->as_string) { 57 return ParseHostPattern( 58 permission, operation_type, *host_patterns->as_string, error); 59 } 60 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(); 65 ++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(); 81 it != permission->entries().end(); 82 ++it) { 83 if (it->pattern().type == operation_type) { 84 host_patterns->as_strings->push_back(it->GetHostPatternAsString()); 85 } 86 } 87 } 88 89 } // namespace 90 91 SocketsManifestPermission::SocketsManifestPermission() {} 92 93 SocketsManifestPermission::~SocketsManifestPermission() {} 94 95 // static 96 scoped_ptr<SocketsManifestPermission> SocketsManifestPermission::FromValue( 97 const base::Value& value, 98 base::string16* error) { 99 scoped_ptr<Sockets> sockets = Sockets::FromValue(value, error); 100 if (!sockets) 101 return scoped_ptr<SocketsManifestPermission>(); 102 103 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); 104 if (sockets->udp) { 105 if (!ParseHostPatterns(result.get(), 106 SocketPermissionRequest::UDP_BIND, 107 sockets->udp->bind, 108 error)) { 109 return scoped_ptr<SocketsManifestPermission>(); 110 } 111 if (!ParseHostPatterns(result.get(), 112 SocketPermissionRequest::UDP_SEND_TO, 113 sockets->udp->send, 114 error)) { 115 return scoped_ptr<SocketsManifestPermission>(); 116 } 117 if (!ParseHostPatterns(result.get(), 118 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, 119 sockets->udp->multicast_membership, 120 error)) { 121 return scoped_ptr<SocketsManifestPermission>(); 122 } 123 } 124 if (sockets->tcp) { 125 if (!ParseHostPatterns(result.get(), 126 SocketPermissionRequest::TCP_CONNECT, 127 sockets->tcp->connect, 128 error)) { 129 return scoped_ptr<SocketsManifestPermission>(); 130 } 131 } 132 if (sockets->tcp_server) { 133 if (!ParseHostPatterns(result.get(), 134 SocketPermissionRequest::TCP_LISTEN, 135 sockets->tcp_server->listen, 136 error)) { 137 return scoped_ptr<SocketsManifestPermission>(); 138 } 139 } 140 return result.Pass(); 141 } 142 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(); 148 ++it) { 149 if (it->Check(request)) 150 return true; 151 } 152 return false; 153 } 154 155 std::string SocketsManifestPermission::name() const { 156 return manifest_keys::kSockets; 157 } 158 159 std::string SocketsManifestPermission::id() const { return name(); } 160 161 bool SocketsManifestPermission::HasMessages() const { 162 bool is_empty = permissions_.empty(); 163 return !is_empty; 164 } 165 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); 173 } 174 AddNetworkListMessage(result); 175 return result; 176 } 177 178 bool SocketsManifestPermission::FromValue(const base::Value* value) { 179 if (!value) 180 return false; 181 base::string16 error; 182 scoped_ptr<SocketsManifestPermission> manifest_permission( 183 SocketsManifestPermission::FromValue(*value, &error)); 184 185 if (!manifest_permission) 186 return false; 187 188 permissions_ = manifest_permission->permissions_; 189 return true; 190 } 191 192 scoped_ptr<base::Value> SocketsManifestPermission::ToValue() const { 193 Sockets sockets; 194 195 sockets.udp.reset(new Sockets::Udp()); 196 SetHostPatterns(sockets.udp->bind, this, SocketPermissionRequest::UDP_BIND); 197 SetHostPatterns( 198 sockets.udp->send, this, SocketPermissionRequest::UDP_SEND_TO); 199 SetHostPatterns(sockets.udp->multicast_membership, 200 this, 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); 206 } 207 208 sockets.tcp.reset(new Sockets::Tcp()); 209 SetHostPatterns( 210 sockets.tcp->connect, this, SocketPermissionRequest::TCP_CONNECT); 211 if (sockets.tcp->connect->as_strings->size() == 0) { 212 sockets.tcp.reset(NULL); 213 } 214 215 sockets.tcp_server.reset(new Sockets::TcpServer()); 216 SetHostPatterns( 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); 220 } 221 222 return scoped_ptr<base::Value>(sockets.ToValue().release()).Pass(); 223 } 224 225 ManifestPermission* SocketsManifestPermission::Diff( 226 const ManifestPermission* rhs) const { 227 const SocketsManifestPermission* other = 228 static_cast<const SocketsManifestPermission*>(rhs); 229 230 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); 231 result->permissions_ = base::STLSetDifference<SocketPermissionEntrySet>( 232 permissions_, other->permissions_); 233 return result.release(); 234 } 235 236 ManifestPermission* SocketsManifestPermission::Union( 237 const ManifestPermission* rhs) const { 238 const SocketsManifestPermission* other = 239 static_cast<const SocketsManifestPermission*>(rhs); 240 241 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); 242 result->permissions_ = base::STLSetUnion<SocketPermissionEntrySet>( 243 permissions_, other->permissions_); 244 return result.release(); 245 } 246 247 ManifestPermission* SocketsManifestPermission::Intersect( 248 const ManifestPermission* rhs) const { 249 const SocketsManifestPermission* other = 250 static_cast<const SocketsManifestPermission*>(rhs); 251 252 scoped_ptr<SocketsManifestPermission> result(new SocketsManifestPermission()); 253 result->permissions_ = base::STLSetIntersection<SocketPermissionEntrySet>( 254 permissions_, other->permissions_); 255 return result.release(); 256 } 257 258 void SocketsManifestPermission::AddPermission( 259 const SocketPermissionEntry& entry) { 260 permissions_.insert(entry); 261 } 262 263 bool SocketsManifestPermission::AddAnyHostMessage( 264 PermissionMessages& messages) const { 265 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin(); 266 it != permissions_.end(); 267 ++it) { 268 if (it->IsAddressBoundType() && 269 it->GetHostType() == SocketPermissionEntry::ANY_HOST) { 270 messages.push_back( 271 PermissionMessage(PermissionMessage::kSocketAnyHost, 272 l10n_util::GetStringUTF16( 273 IDS_EXTENSION_PROMPT_WARNING_SOCKET_ANY_HOST))); 274 return true; 275 } 276 } 277 return false; 278 } 279 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(); 285 ++it) { 286 if (it->GetHostType() == SocketPermissionEntry::HOSTS_IN_DOMAINS) 287 domains.insert(base::UTF8ToUTF16(it->pattern().host)); 288 } 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( 296 id, 297 JoinString( 298 std::vector<base::string16>(domains.begin(), domains.end()), 299 ' ')))); 300 } 301 } 302 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(); 308 ++it) { 309 if (it->GetHostType() == SocketPermissionEntry::SPECIFIC_HOSTS) 310 hostnames.insert(base::UTF8ToUTF16(it->pattern().host)); 311 } 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( 319 id, 320 JoinString( 321 std::vector<base::string16>(hostnames.begin(), hostnames.end()), 322 ' ')))); 323 } 324 } 325 326 void SocketsManifestPermission::AddNetworkListMessage( 327 PermissionMessages& messages) const { 328 for (SocketPermissionEntrySet::const_iterator it = permissions_.begin(); 329 it != permissions_.end(); 330 ++it) { 331 if (it->pattern().type == SocketPermissionRequest::NETWORK_STATE) { 332 messages.push_back( 333 PermissionMessage(PermissionMessage::kNetworkState, 334 l10n_util::GetStringUTF16( 335 IDS_EXTENSION_PROMPT_WARNING_NETWORK_STATE))); 336 } 337 } 338 } 339 340 } // namespace extensions 341