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