// Copyright 2018 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/chrome_cleaner/chrome_utils/extensions_util.h"

#include <algorithm>
#include <array>
#include <map>
#include <set>
#include <string>

#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/values.h"
#include "base/win/registry.h"
#include "chrome/chrome_cleaner/chrome_utils/chrome_util.h"
#include "chrome/chrome_cleaner/os/file_path_sanitization.h"
#include "chrome/chrome_cleaner/os/registry.h"
#include "chrome/chrome_cleaner/os/registry_util.h"
#include "chrome/chrome_cleaner/os/system_util.h"

using base::WaitableEvent;

namespace chrome_cleaner {
namespace {

const int kExtensionIdLength = 32;

class ParseTasksRemainingCounter
    : public base::RefCountedThreadSafe<ParseTasksRemainingCounter> {
 public:
  ParseTasksRemainingCounter(int count, WaitableEvent* done)
      : count_(count), done_(done) {}

  void Increment() {
    DCHECK(count_ > 0);
    count_++;
  }

  void Decrement() {
    count_--;
    if (count_ == 0) {
      done_->Signal();
    }
  }

 private:
  friend class base::RefCountedThreadSafe<ParseTasksRemainingCounter>;
  ~ParseTasksRemainingCounter() = default;

  int count_;
  WaitableEvent* done_;
};

struct RegistryKey {
  HKEY hkey;
  const wchar_t* path;
};

const RegistryKey extension_forcelist_keys[] = {
    {HKEY_LOCAL_MACHINE, kChromePoliciesForcelistKeyPath},
    {HKEY_CURRENT_USER, kChromePoliciesForcelistKeyPath}};

const RegistryKey extension_settings_keys[] = {
    {HKEY_LOCAL_MACHINE, kChromePoliciesKeyPath},
    {HKEY_CURRENT_USER, kChromePoliciesKeyPath}};
const wchar_t kExtensionSettingsRegistryEntryName[] = L"ExtensionSettings";
const char kExtensionSettingsInstallationModeName[] = "installation_mode";
const char kExtensionSettingsForceInstalledValue[] = "force_installed";

const wchar_t kExternalExtensionsFilePath[] =
    L"default_apps\\external_extensions.json";
// Extension IDs that are expected to be in external_extensions.json, or have
// been in past versions, gathered from
// chrome/browser/resources/default_apps/external_extensions.json
constexpr std::array<const base::char16*, 8> default_extension_whitelist = {
    L"blpcfgokakmgnkcojhhkbfbldkacnbeo", L"pjkljhegncpnkpknbcohdijeoejaedia",
    L"apdfllckaahabafndbhieahigkjlhalf", L"aohghmighlieiainnegkcijnfilokake",
    L"aapocclcgogkmnckokdopfmhonfmgoek", L"felcaaldnbdncclmgdcncolpebgiejap",
    L"ghbmnnjooekpmoecnnnilnnbdlolhkhi", L"coobgpohoikkiipiblmjeljniedjpjpf"};

const wchar_t kMasterPreferencesFileName[] = L"master_preferences";

void GetForcelistPoliciesForAccessMask(
    REGSAM access_mask,
    std::vector<ExtensionPolicyRegistryEntry>* policies) {
  for (size_t i = 0; i < base::size(extension_forcelist_keys); ++i) {
    base::win::RegistryValueIterator forcelist_it(
        extension_forcelist_keys[i].hkey, extension_forcelist_keys[i].path,
        access_mask);
    for (; forcelist_it.Valid(); ++forcelist_it) {
      base::string16 entry;
      GetRegistryValueAsString(forcelist_it.Value(), forcelist_it.ValueSize(),
                               forcelist_it.Type(), &entry);

      // Extract the extension ID from the beginning of the registry entry,
      // since it also contains an update URL.
      if (entry.length() >= kExtensionIdLength) {
        base::string16 extension_id = entry.substr(0, kExtensionIdLength);

        policies->emplace_back(extension_id, extension_forcelist_keys[i].hkey,
                               extension_forcelist_keys[i].path,
                               forcelist_it.Name());
      }
    }
  }
}

void GetExtensionSettingsPoliciesFromParsedJson(
    const RegistryKey& registry_key,
    std::vector<ExtensionPolicyRegistryEntry>* policies,
    scoped_refptr<ParseTasksRemainingCounter> counter,
    base::Optional<base::Value> json,
    const base::Optional<std::string>& error) {
  base::ScopedClosureRunner closure(
      base::BindOnce(&ParseTasksRemainingCounter::Decrement, counter.get()));

  base::DictionaryValue* extension_settings = nullptr;
  if (!json.has_value() || !json->is_dict() ||
      !json->GetAsDictionary(&extension_settings)) {
    LOG(ERROR) << "Could not read JSON from " << registry_key.hkey << "\\"
               << registry_key.path;
    if (error.has_value()) {
      LOG(ERROR) << "JSON parser error " << error.value();
    }
    return;
  }

  for (const auto& entry : *extension_settings) {
    const base::string16& extension_id = base::UTF8ToUTF16(entry.first);
    const std::unique_ptr<base::Value>& settings_value = entry.second;

    if (settings_value->is_dict()) {
      base::Value* installation_mode =
          settings_value->FindKey(kExtensionSettingsInstallationModeName);
      if (installation_mode != nullptr &&
          installation_mode->GetString() ==
              kExtensionSettingsForceInstalledValue) {
        policies->emplace_back(extension_id, registry_key.hkey,
                               registry_key.path,
                               kExtensionSettingsRegistryEntryName);
      }
    }
  }
}

void GetExtensionSettingsPoliciesForAccessMask(
    REGSAM access_mask,
    JsonParserAPI* json_parser,
    std::vector<ExtensionPolicyRegistryEntry>* policies,
    scoped_refptr<ParseTasksRemainingCounter> counter) {
  for (size_t i = 0; i < base::size(extension_settings_keys); ++i) {
    RegKeyPath key(extension_settings_keys[i].hkey,
                   extension_settings_keys[i].path, access_mask);
    base::string16 extension_settings;
    RegistryError error;
    uint32_t type;
    ReadRegistryValue(key, kExtensionSettingsRegistryEntryName,
                      &extension_settings, &type, &error);

    if (error != RegistryError::SUCCESS) {
      LOG_IF(WARNING, error != RegistryError::VALUE_NOT_FOUND)
          << "Failed to read string registry value: '"
          << extension_settings_keys[i].path << "\\"
          << kExtensionSettingsRegistryEntryName << "', error: '"
          << static_cast<int>(error) << "'.";
      continue;
    }

    counter->Increment();
    json_parser->Parse(
        base::UTF16ToUTF8(extension_settings),
        base::BindOnce(&GetExtensionSettingsPoliciesFromParsedJson,
                       extension_settings_keys[i], policies, counter));
  }
}

void GetDefaultExtensionsFromParsedJson(
    const base::FilePath& extensions_file,
    std::vector<ExtensionPolicyFile>* policies,
    scoped_refptr<ParseTasksRemainingCounter> counter,
    base::Optional<base::Value> json,
    const base::Optional<std::string>& error) {
  base::ScopedClosureRunner closure(
      base::BindOnce(&ParseTasksRemainingCounter::Decrement, counter.get()));

  base::DictionaryValue* default_extensions = nullptr;
  if (!json.has_value() || !json->is_dict() ||
      !json->GetAsDictionary(&default_extensions)) {
    LOG(ERROR) << "Could not read JSON from " << SanitizePath(extensions_file);
    if (error.has_value()) {
      LOG(ERROR) << "JSON parser error " << error.value();
    }
    return;
  }

  for (const auto& entry : *default_extensions) {
    base::string16 extension_id = base::UTF8ToUTF16(entry.first);
    if (std::find(default_extension_whitelist.begin(),
                  default_extension_whitelist.end(),
                  extension_id) == default_extension_whitelist.end()) {
      policies->emplace_back(extension_id, extensions_file);
    }
  }
}

void GetMasterPreferencesExtensionsFromParsedJson(
    const base::FilePath& extensions_file,
    std::vector<ExtensionPolicyFile>* policies,
    scoped_refptr<ParseTasksRemainingCounter> counter,
    base::Optional<base::Value> json,
    const base::Optional<std::string>& error) {
  base::ScopedClosureRunner closure(
      base::BindOnce(&ParseTasksRemainingCounter::Decrement, counter.get()));

  base::DictionaryValue* master_preferences = nullptr;
  if (!json.has_value() || !json->is_dict() ||
      !json->GetAsDictionary(&master_preferences)) {
    LOG(ERROR) << "Could not read JSON from " << SanitizePath(extensions_file);
    if (error.has_value()) {
      LOG(ERROR) << "JSON parser error " << error.value();
    }
    return;
  }

  base::Value* extension_settings = master_preferences->FindPathOfType(
      {"extensions", "settings"}, base::Value::Type::DICTIONARY);
  if (extension_settings == nullptr)
    return;

  base::DictionaryValue* extension_settings_dictionary;
  extension_settings->GetAsDictionary(&extension_settings_dictionary);
  for (const auto& entry : *extension_settings_dictionary) {
    base::string16 extension_id = base::UTF8ToUTF16(entry.first);
    policies->emplace_back(extension_id, extensions_file);
  }
}

}  // namespace

ExtensionPolicyRegistryEntry::ExtensionPolicyRegistryEntry(
    const base::string16& extension_id,
    HKEY hkey,
    const base::string16& path,
    const base::string16& name)
    : extension_id(extension_id), hkey(hkey), path(path), name(name) {}

ExtensionPolicyRegistryEntry::ExtensionPolicyRegistryEntry(
    ExtensionPolicyRegistryEntry&&) = default;

ExtensionPolicyRegistryEntry& ExtensionPolicyRegistryEntry::operator=(
    ExtensionPolicyRegistryEntry&&) = default;

ExtensionPolicyFile::ExtensionPolicyFile(const base::string16& extension_id,
                                         const base::FilePath& path)
    : extension_id(extension_id), path(path) {}

ExtensionPolicyFile::ExtensionPolicyFile(ExtensionPolicyFile&&) = default;

ExtensionPolicyFile& ExtensionPolicyFile::operator=(ExtensionPolicyFile&&) =
    default;

void GetExtensionForcelistRegistryPolicies(
    std::vector<ExtensionPolicyRegistryEntry>* policies) {
  GetForcelistPoliciesForAccessMask(KEY_WOW64_32KEY, policies);
  if (IsX64Architecture())
    GetForcelistPoliciesForAccessMask(KEY_WOW64_64KEY, policies);
}

void GetNonWhitelistedDefaultExtensions(
    JsonParserAPI* json_parser,
    std::vector<ExtensionPolicyFile>* policies,
    base::WaitableEvent* done) {
  std::set<base::FilePath> install_paths;
  ListChromeInstallationPaths(&install_paths);

  std::map<base::FilePath, std::string> files_read;
  for (const base::FilePath& folder : install_paths) {
    const base::FilePath& extensions_file(
        folder.Append(kExternalExtensionsFilePath));
    if (!base::PathExists(extensions_file))
      continue;

    // Read the external_extensions JSON file.
    std::string content;
    if (!base::ReadFileToString(extensions_file, &content)) {
      PLOG(ERROR) << "Failed to read file: " << SanitizePath(extensions_file);
      continue;
    }
    files_read[extensions_file] = content;
  }

  if (files_read.size() == 0) {
    done->Signal();
    return;
  }

  scoped_refptr<ParseTasksRemainingCounter> counter =
      base::MakeRefCounted<ParseTasksRemainingCounter>(files_read.size(), done);
  for (const auto& file : files_read) {
    const base::FilePath& path = file.first;
    const std::string& content = file.second;
    json_parser->Parse(content,
                       base::BindOnce(&GetDefaultExtensionsFromParsedJson, path,
                                      policies, counter));
  }
}

void GetExtensionSettingsForceInstalledExtensions(
    JsonParserAPI* json_parser,
    std::vector<ExtensionPolicyRegistryEntry>* policies,
    base::WaitableEvent* done) {
  // Make a counter with initial count 1 so it doesn't potentially signal until
  // after all parse tasks are posted.
  scoped_refptr<ParseTasksRemainingCounter> counter =
      base::MakeRefCounted<ParseTasksRemainingCounter>(1, done);
  GetExtensionSettingsPoliciesForAccessMask(KEY_WOW64_32KEY, json_parser,
                                            policies, counter);
  if (IsX64Architecture()) {
    GetExtensionSettingsPoliciesForAccessMask(KEY_WOW64_64KEY, json_parser,
                                              policies, counter);
  }
  // Decrement so that the counter can signal when it hits 0.
  counter->Decrement();
}

void GetMasterPreferencesExtensions(JsonParserAPI* json_parser,
                                    std::vector<ExtensionPolicyFile>* policies,
                                    base::WaitableEvent* done) {
  std::set<base::FilePath> exe_paths;
  ListChromeExePaths(&exe_paths);

  std::map<base::FilePath, std::string> files_read;
  for (const base::FilePath& path : exe_paths) {
    const base::FilePath& master_preferences(
        path.Append(kMasterPreferencesFileName));
    if (!base::PathExists(master_preferences))
      continue;

    std::string content;
    if (!base::ReadFileToString(master_preferences, &content)) {
      PLOG(ERROR) << "Failed to read file: "
                  << SanitizePath(master_preferences);
      continue;
    }
    files_read[master_preferences] = content;
  }

  if (files_read.size() == 0) {
    done->Signal();
    return;
  }

  scoped_refptr<ParseTasksRemainingCounter> counter =
      base::MakeRefCounted<ParseTasksRemainingCounter>(files_read.size(), done);
  for (const auto& file : files_read) {
    const base::FilePath& path = file.first;
    const std::string& content = file.second;
    json_parser->Parse(
        content, base::BindOnce(&GetMasterPreferencesExtensionsFromParsedJson,
                                path, policies, counter));
  }
}

}  // namespace chrome_cleaner
