<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_permissions_api.h"

#include "base/json/json_writer.h"
#include "base/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_permissions_api_constants.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_permission_set.h"
#include "chrome/common/extensions/url_pattern_set.h"
#include "content/common/notification_service.h"
#include "googleurl/src/gurl.h"


namespace keys = extension_permissions_module_constants;

namespace {

enum AutoConfirmForTest {
  DO_NOT_SKIP = 0,
  PROCEED,
  ABORT
};
AutoConfirmForTest auto_confirm_for_tests = DO_NOT_SKIP;

DictionaryValue* PackPermissionsToValue(const ExtensionPermissionSet* set) {
  DictionaryValue* value = new DictionaryValue();

  // Generate the list of API permissions.
  ListValue* apis = new ListValue();
  ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
  for (ExtensionAPIPermissionSet::const_iterator i = set->apis().begin();
       i != set->apis().end(); ++i)
    apis->Append(Value::CreateStringValue(info->GetByID(*i)->name()));

  // TODO(jstritar): Include hosts once the API supports them. At that point,
  // we could also shared this code with ExtensionPermissionSet methods in
  // ExtensionPrefs.

  value->Set(keys::kApisKey, apis);
  return value;
}

// Creates a new ExtensionPermissionSet from its |value| and passes ownership to
// the caller through |ptr|. Sets |bad_message| to true if the message is badly
// formed. Returns false if the method fails to unpack a permission set.
bool UnpackPermissionsFromValue(DictionaryValue* value,
                                scoped_refptr<ExtensionPermissionSet>* ptr,
                                bool* bad_message,
                                std::string* error) {
  ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
  ExtensionAPIPermissionSet apis;
  if (value->HasKey(keys::kApisKey)) {
    ListValue* api_list = NULL;
    if (!value->GetList(keys::kApisKey, &api_list)) {
      *bad_message = true;
      return false;
    }
    for (size_t i = 0; i < api_list->GetSize(); ++i) {
      std::string api_name;
      if (!api_list->GetString(i, &api_name)) {
        *bad_message = true;
        return false;
      }

      ExtensionAPIPermission* permission = info->GetByName(api_name);
      if (!permission) {
        *error = base::StringPrintf(
            keys::kUnknownPermissionError, api_name.c_str());
        return false;
      }
      apis.insert(permission->id());
    }
  }

  // Ignore host permissions for now.
  URLPatternSet empty_set;
  *ptr = new ExtensionPermissionSet(apis, empty_set, empty_set);
  return true;
}

} // namespace

ExtensionPermissionsManager::ExtensionPermissionsManager(
    ExtensionService* extension_service)
    : extension_service_(extension_service) {
  RegisterWhitelist();
}

ExtensionPermissionsManager::~ExtensionPermissionsManager() {
}

void ExtensionPermissionsManager::AddPermissions(
    const Extension* extension, const ExtensionPermissionSet* permissions) {
  scoped_refptr<const ExtensionPermissionSet> existing(
      extension->GetActivePermissions());
  scoped_refptr<ExtensionPermissionSet> total(
      ExtensionPermissionSet::CreateUnion(existing, permissions));
  scoped_refptr<ExtensionPermissionSet> added(
      ExtensionPermissionSet::CreateDifference(total.get(), existing));

  extension_service_->UpdateActivePermissions(extension, total.get());

  // Update the granted permissions so we don't auto-disable the extension.
  extension_service_->GrantPermissions(extension);

  NotifyPermissionsUpdated(extension, total.get(), added.get(), ADDED);
}

void ExtensionPermissionsManager::RemovePermissions(
    const Extension* extension, const ExtensionPermissionSet* permissions) {
  scoped_refptr<const ExtensionPermissionSet> existing(
      extension->GetActivePermissions());
  scoped_refptr<ExtensionPermissionSet> total(
      ExtensionPermissionSet::CreateDifference(existing, permissions));
  scoped_refptr<ExtensionPermissionSet> removed(
      ExtensionPermissionSet::CreateDifference(existing, total.get()));

  // We update the active permissions, and not the granted permissions, because
  // the extension, not the user, removed the permissions. This allows the
  // extension to add them again without prompting the user.
  extension_service_->UpdateActivePermissions(extension, total.get());

  NotifyPermissionsUpdated(extension, total.get(), removed.get(), REMOVED);
}

void ExtensionPermissionsManager::DispatchEvent(
    const std::string& extension_id,
    const char* event_name,
    const ExtensionPermissionSet* changed_permissions) {
  Profile* profile = extension_service_->profile();
  if (profile && profile->GetExtensionEventRouter()) {
    ListValue value;
    value.Append(PackPermissionsToValue(changed_permissions));
    std::string json_value;
    base::JSONWriter::Write(&value, false, &json_value);
    profile->GetExtensionEventRouter()->DispatchEventToExtension(
        extension_id, event_name, json_value, profile, GURL());
  }
}

void ExtensionPermissionsManager::NotifyPermissionsUpdated(
    const Extension* extension,
    const ExtensionPermissionSet* active,
    const ExtensionPermissionSet* changed,
    EventType event_type) {
  if (!changed || changed->IsEmpty())
    return;

  UpdatedExtensionPermissionsInfo::Reason reason;
  const char* event_name = NULL;

  if (event_type == REMOVED) {
    reason = UpdatedExtensionPermissionsInfo::REMOVED;
    event_name = keys::kOnRemoved;
  } else {
    CHECK_EQ(ADDED, event_type);
    reason = UpdatedExtensionPermissionsInfo::ADDED;
    event_name = keys::kOnAdded;
  }

  // Notify other APIs or interested parties.
  UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
      extension, changed, reason);
  NotificationService::current()->Notify(
      chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
      Source<Profile>(extension_service_->profile()),
      Details<UpdatedExtensionPermissionsInfo>(&info));

  // Trigger the onAdded and onRemoved events in the extension.
  DispatchEvent(extension->id(), event_name, changed);

  // Send the new permissions to the renderers.
  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
       !i.IsAtEnd(); i.Advance()) {
    RenderProcessHost* host = i.GetCurrentValue();
    Profile* profile = Profile::FromBrowserContext(host->browser_context());
    if (extension_service_->profile()->IsSameProfile(profile))
      host->Send(new ExtensionMsg_UpdatePermissions(
          extension->id(),
          active->apis(),
          active->explicit_hosts(),
          active->scriptable_hosts()));
  }
}

void ExtensionPermissionsManager::RegisterWhitelist() {
  // TODO(jstritar): This could be a field on ExtensionAPIPermission.
  ExtensionAPIPermissionSet api_whitelist;
  api_whitelist.insert(ExtensionAPIPermission::kClipboardRead);<commit_msg>Revert 94337 - Fix missed use.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_permissions_api.h"

#include "base/json/json_writer.h"
#include "base/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_event_router.h"
#include "chrome/browser/extensions/extension_permissions_api_constants.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_permission_set.h"
#include "chrome/common/extensions/url_pattern_set.h"
#include "content/common/notification_service.h"
#include "googleurl/src/gurl.h"


namespace keys = extension_permissions_module_constants;

namespace {

enum AutoConfirmForTest {
  DO_NOT_SKIP = 0,
  PROCEED,
  ABORT
};
AutoConfirmForTest auto_confirm_for_tests = DO_NOT_SKIP;

DictionaryValue* PackPermissionsToValue(const ExtensionPermissionSet* set) {
  DictionaryValue* value = new DictionaryValue();

  // Generate the list of API permissions.
  ListValue* apis = new ListValue();
  ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
  for (ExtensionAPIPermissionSet::const_iterator i = set->apis().begin();
       i != set->apis().end(); ++i)
    apis->Append(Value::CreateStringValue(info->GetByID(*i)->name()));

  // TODO(jstritar): Include hosts once the API supports them. At that point,
  // we could also shared this code with ExtensionPermissionSet methods in
  // ExtensionPrefs.

  value->Set(keys::kApisKey, apis);
  return value;
}

// Creates a new ExtensionPermissionSet from its |value| and passes ownership to
// the caller through |ptr|. Sets |bad_message| to true if the message is badly
// formed. Returns false if the method fails to unpack a permission set.
bool UnpackPermissionsFromValue(DictionaryValue* value,
                                scoped_refptr<ExtensionPermissionSet>* ptr,
                                bool* bad_message,
                                std::string* error) {
  ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
  ExtensionAPIPermissionSet apis;
  if (value->HasKey(keys::kApisKey)) {
    ListValue* api_list = NULL;
    if (!value->GetList(keys::kApisKey, &api_list)) {
      *bad_message = true;
      return false;
    }
    for (size_t i = 0; i < api_list->GetSize(); ++i) {
      std::string api_name;
      if (!api_list->GetString(i, &api_name)) {
        *bad_message = true;
        return false;
      }

      ExtensionAPIPermission* permission = info->GetByName(api_name);
      if (!permission) {
        *error = base::StringPrintf(
            keys::kUnknownPermissionError, api_name.c_str());
        return false;
      }
      apis.insert(permission->id());
    }
  }

  // Ignore host permissions for now.
  URLPatternSet empty_set;
  *ptr = new ExtensionPermissionSet(apis, empty_set, empty_set);
  return true;
}

} // namespace

ExtensionPermissionsManager::ExtensionPermissionsManager(
    ExtensionService* extension_service)
    : extension_service_(extension_service) {
  RegisterWhitelist();
}

ExtensionPermissionsManager::~ExtensionPermissionsManager() {
}

void ExtensionPermissionsManager::AddPermissions(
    const Extension* extension, const ExtensionPermissionSet* permissions) {
  scoped_refptr<const ExtensionPermissionSet> existing(
      extension->GetActivePermissions());
  scoped_refptr<ExtensionPermissionSet> total(
      ExtensionPermissionSet::CreateUnion(existing, permissions));
  scoped_refptr<ExtensionPermissionSet> added(
      ExtensionPermissionSet::CreateDifference(total.get(), existing));

  extension_service_->UpdateActivePermissions(extension, total.get());

  // Update the granted permissions so we don't auto-disable the extension.
  extension_service_->GrantPermissions(extension);

  NotifyPermissionsUpdated(extension, total.get(), added.get(), ADDED);
}

void ExtensionPermissionsManager::RemovePermissions(
    const Extension* extension, const ExtensionPermissionSet* permissions) {
  scoped_refptr<const ExtensionPermissionSet> existing(
      extension->GetActivePermissions());
  scoped_refptr<ExtensionPermissionSet> total(
      ExtensionPermissionSet::CreateDifference(existing, permissions));
  scoped_refptr<ExtensionPermissionSet> removed(
      ExtensionPermissionSet::CreateDifference(existing, total.get()));

  // We update the active permissions, and not the granted permissions, because
  // the extension, not the user, removed the permissions. This allows the
  // extension to add them again without prompting the user.
  extension_service_->UpdateActivePermissions(extension, total.get());

  NotifyPermissionsUpdated(extension, total.get(), removed.get(), REMOVED);
}

void ExtensionPermissionsManager::DispatchEvent(
    const std::string& extension_id,
    const char* event_name,
    const ExtensionPermissionSet* changed_permissions) {
  Profile* profile = extension_service_->profile();
  if (profile && profile->GetExtensionEventRouter()) {
    ListValue value;
    value.Append(PackPermissionsToValue(changed_permissions));
    std::string json_value;
    base::JSONWriter::Write(&value, false, &json_value);
    profile->GetExtensionEventRouter()->DispatchEventToExtension(
        extension_id, event_name, json_value, profile, GURL());
  }
}

void ExtensionPermissionsManager::NotifyPermissionsUpdated(
    const Extension* extension,
    const ExtensionPermissionSet* active,
    const ExtensionPermissionSet* changed,
    EventType event_type) {
  if (!changed || changed->IsEmpty())
    return;

  UpdatedExtensionPermissionsInfo::Reason reason;
  const char* event_name = NULL;

  if (event_type == REMOVED) {
    reason = UpdatedExtensionPermissionsInfo::REMOVED;
    event_name = keys::kOnRemoved;
  } else {
    CHECK_EQ(ADDED, event_type);
    reason = UpdatedExtensionPermissionsInfo::ADDED;
    event_name = keys::kOnAdded;
  }

  // Notify other APIs or interested parties.
  UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
      extension, changed, reason);
  NotificationService::current()->Notify(
      chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
      Source<Profile>(extension_service_->profile()),
      Details<UpdatedExtensionPermissionsInfo>(&info));

  // Trigger the onAdded and onRemoved events in the extension.
  DispatchEvent(extension->id(), event_name, changed);

  // Send the new permissions to the renderers.
  for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
       !i.IsAtEnd(); i.Advance()) {
    RenderProcessHost* host = i.GetCurrentValue();
    if (extension_service_->profile()->IsSameProfile(host->profile()))
      host->Send(new ExtensionMsg_UpdatePermissions(
          extension->id(),
          active->apis(),
          active->explicit_hosts(),
          active->scriptable_hosts()));
  }
}

void ExtensionPermissionsManager::RegisterWhitelist() {
  // TODO(jstritar): This could be a field on ExtensionAPIPermission.
  ExtensionAPIPermissionSet api_whitelist;
  api_whitelist.insert(ExtensionAPIPermission::kClipboardRead);
{'fraction_non_alphanumeric': 0.10615753698520591, 'fraction_numerical': 0.001132880181260829, 'mean_word_length': 4.719131097560975, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5708755', 'n_tokens_mistral': 4117, 'n_tokens_neox': 4104, 'n_words': 938}