1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "remoting/host/pairing_registry_delegate_linux.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind.h"
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/file_util.h"
9a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/files/file_enumerator.h"
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/files/important_file_writer.h"
11a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/json/json_file_value_serializer.h"
12a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/json/json_string_value_serializer.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/location.h"
14a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/strings/stringprintf.h"
15a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "base/values.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "remoting/host/branding.h"
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace {
19a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
20a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// The pairing registry path relative to the configuration directory.
21a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const char kRegistryDirectory[] = "paired-clients";
22a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
23a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const char kPairingFilenameFormat[] = "%s.json";
24a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)const char kPairingFilenamePattern[] = "*.json";
25a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace remoting {
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing protocol::PairingRegistry;
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)PairingRegistryDelegateLinux::PairingRegistryDelegateLinux() {
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochPairingRegistryDelegateLinux::~PairingRegistryDelegateLinux() {
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)scoped_ptr<base::ListValue> PairingRegistryDelegateLinux::LoadAll() {
39a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  scoped_ptr<base::ListValue> pairings(new base::ListValue());
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
41a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Enumerate all pairing files in the pairing registry.
42a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath registry_path = GetRegistryPath();
43a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FileEnumerator enumerator(registry_path, false,
44a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                  base::FileEnumerator::FILES,
45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                  kPairingFilenamePattern);
46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (base::FilePath pairing_file = enumerator.Next(); !pairing_file.empty();
47a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       pairing_file = enumerator.Next()) {
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // Read the JSON containing pairing data.
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    JSONFileValueSerializer serializer(pairing_file);
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    int error_code;
51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    std::string error_message;
52a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    scoped_ptr<base::Value> pairing_json(
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        serializer.Deserialize(&error_code, &error_message));
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (!pairing_json) {
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      LOG(WARNING) << "Failed to load '" << pairing_file.value() << "' ("
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                   << error_code << ").";
57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      continue;
58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
60a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    pairings->Append(pairing_json.release());
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
63a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return pairings.Pass();
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
66a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool PairingRegistryDelegateLinux::DeleteAll() {
67a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Delete all pairing files in the pairing registry.
68a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath registry_path = GetRegistryPath();
69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FileEnumerator enumerator(registry_path, false,
70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                  base::FileEnumerator::FILES,
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                  kPairingFilenamePattern);
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool success = true;
74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  for (base::FilePath pairing_file = enumerator.Next(); !pairing_file.empty();
75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)       pairing_file = enumerator.Next()) {
76a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    success = success && base::DeleteFile(pairing_file, false);
77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
78a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
79a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return success;
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
82a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)PairingRegistry::Pairing PairingRegistryDelegateLinux::Load(
83a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& client_id) {
84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath registry_path = GetRegistryPath();
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath pairing_file = registry_path.Append(
86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::StringPrintf(kPairingFilenameFormat, client_id.c_str()));
87a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
88a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  JSONFileValueSerializer serializer(pairing_file);
89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  int error_code;
90a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::string error_message;
91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  scoped_ptr<base::Value> pairing(
92a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      serializer.Deserialize(&error_code, &error_message));
93a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!pairing) {
94a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    LOG(WARNING) << "Failed to load pairing information: " << error_message
95a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                 << " (" << error_code << ").";
96a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return PairingRegistry::Pairing();
97a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
98a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
994311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  base::DictionaryValue* pairing_dictionary;
1004311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  if (!pairing->GetAsDictionary(&pairing_dictionary)) {
1014311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    LOG(WARNING) << "Failed to parse pairing information: not a dictionary.";
1024311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    return PairingRegistry::Pairing();
1034311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  }
1044311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch
1054311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  return PairingRegistry::Pairing::CreateFromValue(*pairing_dictionary);
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool PairingRegistryDelegateLinux::Save(
109a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const PairingRegistry::Pairing& pairing) {
110a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath registry_path = GetRegistryPath();
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::PlatformFileError error;
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!file_util::CreateDirectoryAndGetError(registry_path, &error)) {
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Could not create pairing registry directory: " << error;
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return false;
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
116a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
117a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  std::string pairing_json;
118a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  JSONStringValueSerializer serializer(&pairing_json);
119a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!serializer.Serialize(*pairing.ToValue())) {
120a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    LOG(ERROR) << "Failed to serialize pairing data for "
121a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)               << pairing.client_id();
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return false;
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath pairing_file = registry_path.Append(
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::StringPrintf(kPairingFilenameFormat, pairing.client_id().c_str()));
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!base::ImportantFileWriter::WriteFileAtomically(pairing_file,
128a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                                      pairing_json)) {
129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    LOG(ERROR) << "Could not save pairing data for " << pairing.client_id();
130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return false;
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
132a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return true;
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)bool PairingRegistryDelegateLinux::Delete(const std::string& client_id) {
137a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath registry_path = GetRegistryPath();
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::FilePath pairing_file = registry_path.Append(
139a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::StringPrintf(kPairingFilenameFormat, client_id.c_str()));
140a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
141a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return base::DeleteFile(pairing_file, false);
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
144a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)base::FilePath PairingRegistryDelegateLinux::GetRegistryPath() {
145a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!registry_path_for_testing_.empty()) {
146a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return registry_path_for_testing_;
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath config_dir = remoting::GetConfigDir();
150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return config_dir.Append(kRegistryDirectory);
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void PairingRegistryDelegateLinux::SetRegistryPathForTesting(
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const base::FilePath& registry_path) {
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  registry_path_for_testing_ = registry_path;
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)scoped_ptr<PairingRegistry::Delegate> CreatePairingRegistryDelegate() {
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return scoped_ptr<PairingRegistry::Delegate>(
161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      new PairingRegistryDelegateLinux());
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace remoting
165