// Copyright (c) 2012 The Chromium OS 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 "login_manager/device_local_account_manager.h"

#include <utility>

#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/memory/ptr_util.h>
#include <base/strings/string_util.h>
#include <brillo/cryptohome.h>

#include "bindings/chrome_device_policy.pb.h"
#include "login_manager/policy_service.h"
#include "login_manager/policy_store.h"

namespace em = enterprise_management;

namespace login_manager {

// Device-local account state directory.
constexpr char DeviceLocalAccountManager::kPolicyDir[] = "policy";

DeviceLocalAccountManager::DeviceLocalAccountManager(
    const base::FilePath& state_dir, PolicyKey* owner_key)
    : state_dir_(state_dir), owner_key_(owner_key) {}

DeviceLocalAccountManager::~DeviceLocalAccountManager() = default;

void DeviceLocalAccountManager::UpdateDeviceSettings(
    const em::ChromeDeviceSettingsProto& device_settings) {
  // Update the policy map.
  typedef google::protobuf::RepeatedPtrField<em::DeviceLocalAccountInfoProto>
      DeviceLocalAccountList;
  std::map<std::string, std::unique_ptr<PolicyService>> new_policy_map;
  const DeviceLocalAccountList& list(
      device_settings.device_local_accounts().account());
  for (DeviceLocalAccountList::const_iterator account(list.begin());
       account != list.end(); ++account) {
    std::string account_key;
    if (account->has_account_id()) {
      account_key = GetAccountKey(account->account_id());
    } else if (!account->has_type() &&
               account->has_deprecated_public_session_id()) {
      account_key = GetAccountKey(account->deprecated_public_session_id());
    }
    if (!account_key.empty()) {
      new_policy_map[account_key] = std::move(policy_map_[account_key]);
    }
  }
  policy_map_.swap(new_policy_map);

  MigrateUppercaseDirs();

  // Purge all existing on-disk accounts that are no longer defined.
  base::FileEnumerator enumerator(state_dir_, false,
                                  base::FileEnumerator::DIRECTORIES);
  base::FilePath subdir;
  while (!(subdir = enumerator.Next()).empty()) {
    if (IsValidAccountKey(subdir.BaseName().value()) &&
        policy_map_.find(subdir.BaseName().value()) == policy_map_.end()) {
      LOG(INFO) << "Purging " << subdir.value();
      if (!base::DeleteFile(subdir, true))
        LOG(ERROR) << "Failed to delete " << subdir.value();
    }
  }
}

bool DeviceLocalAccountManager::MigrateUppercaseDirs() {
  base::FileEnumerator enumerator(state_dir_, false,
                                  base::FileEnumerator::DIRECTORIES);
  base::FilePath subdir;

  while (!(subdir = enumerator.Next()).empty()) {
    std::string upper = subdir.BaseName().value();
    std::string lower = base::ToLowerASCII(upper);
    if (IsValidAccountKey(lower) && lower != upper) {
      base::FilePath subdir_to(subdir.DirName().Append(lower));
      LOG(INFO) << "Migrating " << upper << " to " << lower;
      if (!base::ReplaceFile(subdir, subdir_to, nullptr))
        LOG(ERROR) << "Failed to migrate " << subdir.value();
    }
  }

  return true;
}

PolicyService* DeviceLocalAccountManager::GetPolicyService(
    const std::string& account_id) {
  const std::string key = GetAccountKey(account_id);
  auto entry = policy_map_.find(key);
  if (entry == policy_map_.end())
    return nullptr;

  // Lazily create and initialize the policy service instance.
  if (!entry->second) {
    const base::FilePath policy_dir =
        state_dir_.AppendASCII(key).Append(kPolicyDir);
    if (!base::CreateDirectory(policy_dir)) {
      LOG(ERROR) << "Failed to create device-local account policy directory "
                 << policy_dir.value();
      return nullptr;
    }

    entry->second =
        std::make_unique<PolicyService>(policy_dir, owner_key_, nullptr, false);
  }

  return entry->second.get();
}

void DeviceLocalAccountManager::PersistAllPolicy() {
  for (const auto& kv : policy_map_) {
    if (kv.second)
      kv.second->PersistAllPolicy();
  }
}

std::string DeviceLocalAccountManager::GetAccountKey(
    const std::string& account_id) {
  return brillo::cryptohome::home::SanitizeUserName(account_id);
}

bool DeviceLocalAccountManager::IsValidAccountKey(const std::string& str) {
  return brillo::cryptohome::home::IsSanitizedUserName(str);
}

}  // namespace login_manager
