chromium/remoting/ios/persistence/host_pairing_info.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/ios/persistence/host_pairing_info.h"

#include <memory>

#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/values.h"
#include "remoting/ios/persistence/remoting_keychain.h"

namespace remoting {

namespace {

const char kPairingIdKey[] = "id";
const char kPairingSecretKey[] = "secret";

static remoting::Keychain* g_keychain =
    remoting::RemotingKeychain::GetInstance();

base::Value::Dict GetHostPairingListForUser(const std::string& user_id) {
  std::string data =
      g_keychain->GetData(remoting::Keychain::Key::PAIRING_INFO, user_id);
  if (data.empty()) {
    return base::Value::Dict();
  }
  JSONStringValueDeserializer deserializer(data);
  int error_code = 0;
  std::string error_message;
  std::unique_ptr<base::Value> value =
      deserializer.Deserialize(&error_code, &error_message);
  if (error_code || !error_message.empty()) {
    LOG(ERROR) << "Failed to decode host pairing list. Code: " << error_code
               << " message: " << error_message;
    return base::Value::Dict();
  }
  if (!value->is_dict()) {
    LOG(ERROR) << "Decoded host list is not a dictionary.";
    return base::Value::Dict();
  }
  return std::move(*value).TakeDict();
}

}  // namespace

HostPairingInfo::HostPairingInfo(const std::string& user_id,
                                 const std::string& host_id,
                                 const std::string& pairing_id,
                                 const std::string& pairing_secret)
    : user_id_(user_id),
      host_id_(host_id),
      pairing_id_(pairing_id),
      pairing_secret_(pairing_secret) {}

HostPairingInfo::HostPairingInfo(const HostPairingInfo&) = default;

HostPairingInfo::HostPairingInfo(HostPairingInfo&&) = default;

HostPairingInfo::~HostPairingInfo() {}

// static
HostPairingInfo HostPairingInfo::GetPairingInfo(const std::string& user_id,
                                                const std::string& host_id) {
  base::Value::Dict host_pairings = GetHostPairingListForUser(user_id);
  base::Value::Dict* host_pairing = host_pairings.FindDict(host_id);
  if (host_pairing) {
    std::string* pairing_id = host_pairing->FindString(kPairingIdKey);
    std::string* pairing_secret = host_pairing->FindString(kPairingSecretKey);
    if (pairing_id && pairing_secret) {
      return HostPairingInfo(user_id, host_id, *pairing_id, *pairing_secret);
    }
  }
  // Pairing not exist or entry corrupted.
  return HostPairingInfo(user_id, host_id, "", "");
}

void HostPairingInfo::Save() {
  base::Value::Dict host_pairings = GetHostPairingListForUser(user_id_);

  base::Value::Dict host_pairing;
  host_pairing.Set(kPairingIdKey, pairing_id_);
  host_pairing.Set(kPairingSecretKey, pairing_secret_);

  host_pairings.Set(host_id_, std::move(host_pairing));

  std::string json_string;
  JSONStringValueSerializer serializer(&json_string);
  serializer.Serialize(host_pairings);
  g_keychain->SetData(remoting::Keychain::Key::PAIRING_INFO, user_id_,
                      json_string);
}

// static
void HostPairingInfo::SetKeychainForTesting(Keychain* keychain) {
  g_keychain = keychain ? keychain : remoting::RemotingKeychain::GetInstance();
}

}  // namespace remoting