Home | History | Annotate | Download | only in sockets
      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