Home | History | Annotate | Download | only in manifest_handlers
      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/manifest_handlers/settings_overrides_handler.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/strings/string_util.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/values.h"
     12 #include "chrome/common/extensions/extension_messages.h"
     13 #include "chrome/common/extensions/permissions/settings_override_permission.h"
     14 #include "extensions/common/error_utils.h"
     15 #include "extensions/common/feature_switch.h"
     16 #include "extensions/common/manifest_constants.h"
     17 #include "extensions/common/permissions/api_permission_set.h"
     18 #include "extensions/common/permissions/manifest_permission.h"
     19 #include "extensions/common/permissions/permissions_data.h"
     20 #include "extensions/common/permissions/permissions_info.h"
     21 #include "grit/generated_resources.h"
     22 #include "ipc/ipc_message.h"
     23 #include "ui/base/l10n/l10n_util.h"
     24 #include "url/gurl.h"
     25 
     26 using extensions::api::manifest_types::ChromeSettingsOverrides;
     27 
     28 namespace extensions {
     29 namespace {
     30 
     31 const char* kWwwPrefix = "www.";
     32 
     33 scoped_ptr<GURL> CreateManifestURL(const std::string& url) {
     34   scoped_ptr<GURL> manifest_url(new GURL(url));
     35   if (!manifest_url->is_valid() ||
     36       !manifest_url->SchemeIsHTTPOrHTTPS())
     37     return scoped_ptr<GURL>();
     38   return manifest_url.Pass();
     39 }
     40 
     41 scoped_ptr<GURL> ParseHomepage(const ChromeSettingsOverrides& overrides,
     42                                base::string16* error) {
     43   if (!overrides.homepage)
     44     return scoped_ptr<GURL>();
     45   scoped_ptr<GURL> manifest_url = CreateManifestURL(*overrides.homepage);
     46   if (!manifest_url) {
     47     *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
     48         manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage);
     49   }
     50   return manifest_url.Pass();
     51 }
     52 
     53 std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides,
     54                                    base::string16* error) {
     55   std::vector<GURL> urls;
     56   if (!overrides.startup_pages)
     57     return urls;
     58 
     59   for (std::vector<std::string>::const_iterator i =
     60        overrides.startup_pages->begin(); i != overrides.startup_pages->end();
     61        ++i) {
     62     scoped_ptr<GURL> manifest_url = CreateManifestURL(*i);
     63     if (!manifest_url) {
     64       *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
     65           manifest_errors::kInvalidStartupOverrideURL, *i);
     66     } else {
     67       urls.push_back(GURL());
     68       urls.back().Swap(manifest_url.get());
     69     }
     70   }
     71   return urls;
     72 }
     73 
     74 scoped_ptr<ChromeSettingsOverrides::Search_provider> ParseSearchEngine(
     75     ChromeSettingsOverrides* overrides,
     76     base::string16* error) {
     77   if (!overrides->search_provider)
     78     return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
     79   if (!CreateManifestURL(overrides->search_provider->favicon_url)) {
     80     *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
     81         manifest_errors::kInvalidSearchEngineURL,
     82         overrides->search_provider->favicon_url);
     83     return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
     84   }
     85   if (!CreateManifestURL(overrides->search_provider->search_url)) {
     86     *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
     87         manifest_errors::kInvalidSearchEngineURL,
     88         overrides->search_provider->search_url);
     89     return scoped_ptr<ChromeSettingsOverrides::Search_provider>();
     90   }
     91   return overrides->search_provider.Pass();
     92 }
     93 
     94 // A www. prefix is not informative and thus not worth the limited real estate
     95 // in the permissions UI.
     96 std::string RemoveWwwPrefix(const std::string& url) {
     97   if (StartsWithASCII(url, kWwwPrefix, false))
     98     return url.substr(strlen(kWwwPrefix));
     99   return url;
    100 }
    101 
    102 }  // namespace
    103 
    104 // The manifest permission implementation supports a permission for hiding
    105 // the bookmark button.
    106 class SettingsOverridesHandler::ManifestPermissionImpl
    107     : public ManifestPermission {
    108  public:
    109   explicit ManifestPermissionImpl(bool hide_bookmark_button_permission)
    110       : hide_bookmark_button_permission_(hide_bookmark_button_permission) {}
    111 
    112   // extensions::ManifestPermission overrides.
    113   virtual std::string name() const OVERRIDE {
    114     return manifest_keys::kSettingsOverride;
    115   }
    116 
    117   virtual std::string id() const OVERRIDE {
    118     return name();
    119   }
    120 
    121   virtual bool HasMessages() const OVERRIDE {
    122     return hide_bookmark_button_permission_;
    123   }
    124 
    125   virtual PermissionMessages GetMessages() const OVERRIDE {
    126     PermissionMessages result;
    127     if (hide_bookmark_button_permission_) {
    128       result.push_back(PermissionMessage(
    129           PermissionMessage::kHideBookmarkButton,
    130           l10n_util::GetStringUTF16(
    131               IDS_EXTENSION_PROMPT_WARNING_HIDE_BOOKMARK_STAR)));
    132     }
    133     return result;
    134   }
    135 
    136   virtual bool FromValue(const base::Value* value) OVERRIDE {
    137     return value && value->GetAsBoolean(&hide_bookmark_button_permission_);
    138   }
    139 
    140   virtual scoped_ptr<base::Value> ToValue() const OVERRIDE {
    141     return scoped_ptr<base::Value>(
    142         new base::FundamentalValue(hide_bookmark_button_permission_)).Pass();
    143   }
    144 
    145   virtual ManifestPermission* Clone() const OVERRIDE {
    146     return scoped_ptr<ManifestPermissionImpl>(
    147         new ManifestPermissionImpl(hide_bookmark_button_permission_)).release();
    148   }
    149 
    150   virtual ManifestPermission* Diff(const ManifestPermission* rhs) const
    151       OVERRIDE {
    152     const ManifestPermissionImpl* other =
    153         static_cast<const ManifestPermissionImpl*>(rhs);
    154 
    155     return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
    156         hide_bookmark_button_permission_ &&
    157         !other->hide_bookmark_button_permission_)).release();
    158   }
    159 
    160   virtual ManifestPermission* Union(const ManifestPermission* rhs) const
    161       OVERRIDE {
    162     const ManifestPermissionImpl* other =
    163         static_cast<const ManifestPermissionImpl*>(rhs);
    164 
    165     return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
    166         hide_bookmark_button_permission_ ||
    167         other->hide_bookmark_button_permission_)).release();
    168   }
    169 
    170   virtual ManifestPermission* Intersect(const ManifestPermission* rhs) const
    171       OVERRIDE {
    172     const ManifestPermissionImpl* other =
    173         static_cast<const ManifestPermissionImpl*>(rhs);
    174 
    175     return scoped_ptr<ManifestPermissionImpl>(new ManifestPermissionImpl(
    176         hide_bookmark_button_permission_ &&
    177         other->hide_bookmark_button_permission_)).release();
    178   }
    179 
    180   virtual bool Contains(const ManifestPermission* rhs) const OVERRIDE {
    181     const ManifestPermissionImpl* other =
    182         static_cast<const ManifestPermissionImpl*>(rhs);
    183 
    184     return !other->hide_bookmark_button_permission_ ||
    185         hide_bookmark_button_permission_;
    186   }
    187 
    188   virtual bool Equal(const ManifestPermission* rhs) const OVERRIDE {
    189     const ManifestPermissionImpl* other =
    190         static_cast<const ManifestPermissionImpl*>(rhs);
    191 
    192     return hide_bookmark_button_permission_ ==
    193         other->hide_bookmark_button_permission_;
    194   }
    195 
    196   virtual void Write(IPC::Message* m) const OVERRIDE {
    197     IPC::WriteParam(m, hide_bookmark_button_permission_);
    198   }
    199 
    200   virtual bool Read(const IPC::Message* m, PickleIterator* iter) OVERRIDE {
    201     return IPC::ReadParam(m, iter, &hide_bookmark_button_permission_);
    202   }
    203 
    204   virtual void Log(std::string* log) const OVERRIDE {
    205     IPC::LogParam(hide_bookmark_button_permission_, log);
    206   }
    207 
    208  private:
    209   bool hide_bookmark_button_permission_;
    210 };
    211 
    212 SettingsOverrides::SettingsOverrides() {}
    213 
    214 SettingsOverrides::~SettingsOverrides() {}
    215 
    216 const SettingsOverrides* SettingsOverrides::Get(
    217     const Extension* extension) {
    218   return static_cast<SettingsOverrides*>(
    219       extension->GetManifestData(manifest_keys::kSettingsOverride));
    220 }
    221 
    222 bool SettingsOverrides::RequiresHideBookmarkButtonPermission() const {
    223   return bookmarks_ui && bookmarks_ui->hide_bookmark_button &&
    224       *bookmarks_ui->hide_bookmark_button;
    225 }
    226 
    227 SettingsOverridesHandler::SettingsOverridesHandler() {}
    228 
    229 SettingsOverridesHandler::~SettingsOverridesHandler() {}
    230 
    231 bool SettingsOverridesHandler::Parse(Extension* extension,
    232                                      base::string16* error) {
    233   const base::Value* dict = NULL;
    234   CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict));
    235   scoped_ptr<ChromeSettingsOverrides> settings(
    236       ChromeSettingsOverrides::FromValue(*dict, error));
    237   if (!settings)
    238     return false;
    239 
    240   scoped_ptr<SettingsOverrides> info(new SettingsOverrides);
    241   info->bookmarks_ui.swap(settings->bookmarks_ui);
    242   info->homepage = ParseHomepage(*settings, error);
    243   info->search_engine = ParseSearchEngine(settings.get(), error);
    244   info->startup_pages = ParseStartupPage(*settings, error);
    245   if (!info->bookmarks_ui && !info->homepage &&
    246       !info->search_engine && info->startup_pages.empty()) {
    247     *error = ASCIIToUTF16(manifest_errors::kInvalidEmptySettingsOverrides);
    248     return false;
    249   }
    250   info->manifest_permission.reset(new ManifestPermissionImpl(
    251       info->RequiresHideBookmarkButtonPermission()));
    252 
    253   APIPermissionSet* permission_set =
    254       PermissionsData::GetInitialAPIPermissions(extension);
    255   DCHECK(permission_set);
    256   if (info->search_engine) {
    257     permission_set->insert(new SettingsOverrideAPIPermission(
    258         PermissionsInfo::GetInstance()->GetByID(APIPermission::kSearchProvider),
    259         RemoveWwwPrefix(CreateManifestURL(info->search_engine->search_url)->
    260             GetOrigin().host())));
    261   }
    262   if (!info->startup_pages.empty()) {
    263     permission_set->insert(new SettingsOverrideAPIPermission(
    264         PermissionsInfo::GetInstance()->GetByID(APIPermission::kStartupPages),
    265         // We only support one startup page even though the type of the manifest
    266         // property is a list, only the first one is used.
    267         RemoveWwwPrefix(info->startup_pages[0].GetContent())));
    268   }
    269   if (info->homepage) {
    270     permission_set->insert(new SettingsOverrideAPIPermission(
    271         PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage),
    272         RemoveWwwPrefix(info->homepage.get()->GetContent())));
    273   }
    274   extension->SetManifestData(manifest_keys::kSettingsOverride,
    275                              info.release());
    276   return true;
    277 }
    278 
    279 bool SettingsOverridesHandler::Validate(
    280     const Extension* extension,
    281     std::string* error,
    282     std::vector<InstallWarning>* warnings) const {
    283   const SettingsOverrides* settings_overrides =
    284       SettingsOverrides::Get(extension);
    285 
    286   if (settings_overrides && settings_overrides->bookmarks_ui &&
    287       !FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) {
    288     warnings->push_back(InstallWarning(
    289         ErrorUtils::FormatErrorMessage(
    290             manifest_errors::kUnrecognizedManifestProperty,
    291             manifest_keys::kHideBookmarkButton,
    292             manifest_keys::kBookmarkUI)));
    293   }
    294 
    295   return true;
    296 }
    297 
    298 ManifestPermission* SettingsOverridesHandler::CreatePermission() {
    299   return new ManifestPermissionImpl(false);
    300 }
    301 
    302 ManifestPermission* SettingsOverridesHandler::CreateInitialRequiredPermission(
    303     const Extension* extension) {
    304   const SettingsOverrides* data = SettingsOverrides::Get(extension);
    305   if (data)
    306     return data->manifest_permission->Clone();
    307   return NULL;
    308 }
    309 const std::vector<std::string> SettingsOverridesHandler::Keys() const {
    310   return SingleKey(manifest_keys::kSettingsOverride);
    311 }
    312 
    313 }  // namespace extensions
    314