blob: d67e6a10048a3398016aca28174611c8fbc9ede7 [file] [log] [blame]
joedowea77cec2015-02-25 23:12:511// Copyright 2015 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/test/refresh_token_store.h"
6
7#include "base/files/file_util.h"
joedow9c2502772015-06-11 19:43:198#include "base/files/important_file_writer.h"
9#include "base/json/json_reader.h"
10#include "base/json/json_writer.h"
joedowea77cec2015-02-25 23:12:5111#include "base/logging.h"
avi5a080f012015-12-22 23:15:4312#include "base/macros.h"
dcheng0765c492016-04-06 22:41:5313#include "base/memory/ptr_util.h"
joedow9c2502772015-06-11 19:43:1914#include "base/values.h"
joedowea77cec2015-02-25 23:12:5115
16namespace {
17const base::FilePath::CharType kTokenFileName[] =
joedow9c2502772015-06-11 19:43:1918 FILE_PATH_LITERAL("refresh_tokens.json");
joedowea77cec2015-02-25 23:12:5119const base::FilePath::CharType kRemotingFolder[] =
20 FILE_PATH_LITERAL("remoting");
21const base::FilePath::CharType kRefreshTokenStoreFolder[] =
joedow9c2502772015-06-11 19:43:1922 FILE_PATH_LITERAL("token_store");
joedowea77cec2015-02-25 23:12:5123} // namespace
24
25namespace remoting {
26namespace test {
27
28// Provides functionality to write a refresh token to a local folder on disk and
29// read it back during subsequent tool runs.
30class RefreshTokenStoreOnDisk : public RefreshTokenStore {
31 public:
joedow9c2502772015-06-11 19:43:1932 RefreshTokenStoreOnDisk(const std::string& user_name,
33 const base::FilePath& refresh_token_file_path);
joedowea77cec2015-02-25 23:12:5134 ~RefreshTokenStoreOnDisk() override;
35
36 // RefreshTokenStore interface.
37 std::string FetchRefreshToken() override;
38 bool StoreRefreshToken(const std::string& refresh_token) override;
39
40 private:
joedow9c2502772015-06-11 19:43:1941 // Returns the path for the file used to read from or store a refresh token
42 // for the user.
43 base::FilePath GetPathForRefreshTokenFile();
44
joedowea77cec2015-02-25 23:12:5145 // Used to access the user specific token file.
46 std::string user_name_;
47
joedow9c2502772015-06-11 19:43:1948 // Path used to retrieve the refresh token file.
49 base::FilePath refresh_token_file_path_;
50
joedowea77cec2015-02-25 23:12:5151 DISALLOW_COPY_AND_ASSIGN(RefreshTokenStoreOnDisk);
52};
53
joedow9c2502772015-06-11 19:43:1954RefreshTokenStoreOnDisk::RefreshTokenStoreOnDisk(
55 const std::string& user_name,
joedowd6fad1942015-06-20 01:08:2156 const base::FilePath& refresh_token_path)
57 : user_name_(user_name),
58 refresh_token_file_path_(base::MakeAbsoluteFilePath(refresh_token_path)) {
joedow13648c62015-03-26 03:47:5559}
joedowea77cec2015-02-25 23:12:5160
joedow13648c62015-03-26 03:47:5561RefreshTokenStoreOnDisk::~RefreshTokenStoreOnDisk() {
62}
joedowea77cec2015-02-25 23:12:5163
64std::string RefreshTokenStoreOnDisk::FetchRefreshToken() {
joedow9c2502772015-06-11 19:43:1965 base::FilePath refresh_token_file_path(GetPathForRefreshTokenFile());
66 DCHECK(!refresh_token_file_path.empty());
joedow9cfae7c2015-07-06 18:44:1867 VLOG(1) << "Reading token from: " << refresh_token_file_path.value();
joedowea77cec2015-02-25 23:12:5168
joedow9c2502772015-06-11 19:43:1969 std::string file_contents;
70 if (!base::ReadFileToString(refresh_token_file_path, &file_contents)) {
joedow9cfae7c2015-07-06 18:44:1871 VLOG(1) << "Couldn't read token file: " << refresh_token_file_path.value();
joedow9c2502772015-06-11 19:43:1972 return std::string();
73 }
74
dcheng0765c492016-04-06 22:41:5375 std::unique_ptr<base::Value> token_data(
76 base::JSONReader::Read(file_contents));
joedow9c2502772015-06-11 19:43:1977 base::DictionaryValue* tokens = nullptr;
78 if (!token_data || !token_data->GetAsDictionary(&tokens)) {
79 LOG(ERROR) << "Refresh token file contents were not valid JSON, "
80 << "could not retrieve token.";
81 return std::string();
82 }
joedowea77cec2015-02-25 23:12:5183
84 std::string refresh_token;
joedow9c2502772015-06-11 19:43:1985 if (!tokens->GetStringWithoutPathExpansion(user_name_, &refresh_token)) {
86 // This may not be an error as the file could exist but contain refresh
87 // tokens for other users.
joedow9cfae7c2015-07-06 18:44:1888 VLOG(1) << "Could not find token for: " << user_name_;
joedowea77cec2015-02-25 23:12:5189 return std::string();
90 }
91
92 return refresh_token;
93}
94
95bool RefreshTokenStoreOnDisk::StoreRefreshToken(
96 const std::string& refresh_token) {
97 DCHECK(!refresh_token.empty());
98
joedow9c2502772015-06-11 19:43:1999 base::FilePath file_path(GetPathForRefreshTokenFile());
100 DCHECK(!file_path.empty());
joedow9cfae7c2015-07-06 18:44:18101 VLOG(2) << "Storing token to: " << file_path.value();
joedowea77cec2015-02-25 23:12:51102
joedow9c2502772015-06-11 19:43:19103 base::FilePath refresh_token_file_dir(file_path.DirName());
104 if (!base::DirectoryExists(refresh_token_file_dir) &&
105 !base::CreateDirectory(refresh_token_file_dir)) {
joedowea77cec2015-02-25 23:12:51106 LOG(ERROR) << "Failed to create directory, refresh token not stored.";
107 return false;
108 }
109
joedow9c2502772015-06-11 19:43:19110 std::string file_contents("{}");
111 if (base::PathExists(file_path)) {
112 if (!base::ReadFileToString(file_path, &file_contents)) {
113 LOG(ERROR) << "Invalid token file: " << file_path.value();
114 return false;
115 }
116 }
joedowea77cec2015-02-25 23:12:51117
dcheng0765c492016-04-06 22:41:53118 std::unique_ptr<base::Value> token_data(
119 base::JSONReader::Read(file_contents));
joedow9c2502772015-06-11 19:43:19120 base::DictionaryValue* tokens = nullptr;
121 if (!token_data || !token_data->GetAsDictionary(&tokens)) {
122 LOG(ERROR) << "Invalid refresh token file format, could not store token.";
joedowea77cec2015-02-25 23:12:51123 return false;
124 }
125
joedow9c2502772015-06-11 19:43:19126 std::string json_string;
127 tokens->SetStringWithoutPathExpansion(user_name_, refresh_token);
128 if (!base::JSONWriter::Write(*token_data, &json_string)) {
129 LOG(ERROR) << "Couldn't convert JSON data to string";
joedowea77cec2015-02-25 23:12:51130 return false;
131 }
132
joedow9c2502772015-06-11 19:43:19133 if (!base::ImportantFileWriter::WriteFileAtomically(file_path, json_string)) {
joedowea77cec2015-02-25 23:12:51134 LOG(ERROR) << "Failed to save refresh token to the file on disk.";
135 return false;
136 }
137
138 return true;
joedow9c2502772015-06-11 19:43:19139}
140
141base::FilePath RefreshTokenStoreOnDisk::GetPathForRefreshTokenFile() {
142 base::FilePath refresh_token_file_path(refresh_token_file_path_);
143
144 // If we weren't given a specific file path, then use the default path.
145 if (refresh_token_file_path.empty()) {
146 if (!GetTempDir(&refresh_token_file_path)) {
147 LOG(WARNING) << "Failed to retrieve temporary directory path.";
148 return base::FilePath();
149 }
150
151 refresh_token_file_path = refresh_token_file_path.Append(kRemotingFolder);
152 refresh_token_file_path =
153 refresh_token_file_path.Append(kRefreshTokenStoreFolder);
154 }
155
156 // If no file has been specified, then we will use a default file name.
157 if (refresh_token_file_path.Extension().empty()) {
158 refresh_token_file_path = refresh_token_file_path.Append(kTokenFileName);
159 }
160
161 return refresh_token_file_path;
joedowea77cec2015-02-25 23:12:51162}
163
dcheng0765c492016-04-06 22:41:53164std::unique_ptr<RefreshTokenStore> RefreshTokenStore::OnDisk(
joedow9c2502772015-06-11 19:43:19165 const std::string& user_name,
166 const base::FilePath& refresh_token_file_path) {
dcheng0765c492016-04-06 22:41:53167 return base::WrapUnique<RefreshTokenStore>(
joedow9c2502772015-06-11 19:43:19168 new RefreshTokenStoreOnDisk(user_name, refresh_token_file_path));
joedowea77cec2015-02-25 23:12:51169}
170
171} // namespace test
172} // namespace remoting