OLD | NEW |
(Empty) | |
| 1 // 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 "services/authentication/accounts_db_manager.h" |
| 6 |
| 7 #include <vector> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "base/strings/string_tokenizer.h" |
| 11 #include "mojo/public/cpp/bindings/array.h" |
| 12 #include "mojo/public/cpp/bindings/type_converter.h" |
| 13 #include "mojo/services/files/interfaces/files.mojom.h" |
| 14 |
| 15 namespace authentication { |
| 16 |
| 17 const char* kAccountsDbFileName = "accounts_db.txt"; |
| 18 |
| 19 AccountsDbManager::AccountsDbManager() |
| 20 : directory_(nullptr), contents_(nullptr) {} |
| 21 |
| 22 AccountsDbManager::AccountsDbManager(mojo::files::FilesPtr files) { |
| 23 // TODO: Move to a file system with secure privileges as the accounts db needs |
| 24 // to persist across multiple invocations and apps, and the temporary root |
| 25 // solution here is just a short term path. |
| 26 mojo::files::Error error = mojo::files::Error::INTERNAL; |
| 27 files->OpenFileSystem(nullptr, GetProxy(&directory_), Capture(&error)); |
| 28 files.WaitForIncomingResponse(); |
| 29 if (mojo::files::Error::OK != error) { |
| 30 LOG(FATAL) << "Unable to initialize accounts DB"; |
| 31 } |
| 32 } |
| 33 |
| 34 AccountsDbManager::~AccountsDbManager() {} |
| 35 |
| 36 void AccountsDbManager::GetUpdatedDbContents( |
| 37 const mojo::String& username, |
| 38 const mojo::String& new_account_data, |
| 39 const bool user_exists, |
| 40 mojo::String& new_db_contents) { |
| 41 if (username.is_null() || new_account_data.is_null()) { |
| 42 return; |
| 43 } |
| 44 std::string buffer; |
| 45 if (user_exists) { |
| 46 // Account identified as new user, add a fresh record for this user in |
| 47 // accounts DB in Append mode. |
| 48 if (!AccountsDbManager::contents_.empty()) { |
| 49 buffer += "\n"; |
| 50 } |
| 51 buffer += new_account_data; |
| 52 } else { |
| 53 // Existing user account, replace the credentials/tokens to newly |
| 54 // generated auth tokens in-place. |
| 55 base::StringTokenizer lines(AccountsDbManager::contents_, "\n"); |
| 56 std::string user_record; |
| 57 while (lines.GetNext()) { |
| 58 user_record = lines.token(); |
| 59 if (!new_db_contents.is_null() || !user_record.empty()) { |
| 60 buffer += "\n"; |
| 61 } |
| 62 if (user_record.find(username) != std::string::npos) { |
| 63 buffer += new_account_data; // replace with new auth data |
| 64 } else { |
| 65 buffer += user_record; |
| 66 } |
| 67 } |
| 68 } |
| 69 |
| 70 new_db_contents = buffer; |
| 71 return; |
| 72 } |
| 73 |
| 74 bool AccountsDbManager::UpdateAccount(const mojo::String& username, |
| 75 const mojo::String& new_account_data) { |
| 76 if (username.is_null() || new_account_data.is_null()) { |
| 77 return false; |
| 78 } |
| 79 mojo::String existing_user_data; |
| 80 AccountsDbManager::GetAccountDataForUser(username, existing_user_data); |
| 81 mojo::String new_db_contents; |
| 82 GetUpdatedDbContents(username, new_account_data, existing_user_data.is_null(), |
| 83 new_db_contents); |
| 84 if (new_db_contents.is_null()) { |
| 85 return false; |
| 86 } |
| 87 |
| 88 // Open accounts db file |
| 89 mojo::files::FilePtr file; |
| 90 mojo::files::Error error = mojo::files::Error::INTERNAL; |
| 91 bool write_failed = false; |
| 92 if (existing_user_data.is_null()) { |
| 93 // Append to existing file |
| 94 directory_->OpenFile(kAccountsDbFileName, GetProxy(&file), |
| 95 mojo::files::kOpenFlagWrite | |
| 96 mojo::files::kOpenFlagCreate | |
| 97 mojo::files::kOpenFlagAppend, |
| 98 Capture(&error)); |
| 99 } else { |
| 100 // Rewrite the file contents with updated info |
| 101 directory_->OpenFile( |
| 102 kAccountsDbFileName, GetProxy(&file), |
| 103 mojo::files::kOpenFlagWrite | mojo::files::kOpenFlagCreate, |
| 104 Capture(&error)); |
| 105 } |
| 106 directory_.WaitForIncomingResponse(); |
| 107 if (mojo::files::Error::OK != error) { |
| 108 write_failed = true; |
| 109 } else { |
| 110 // Write to it. |
| 111 std::vector<uint8_t> bytes_to_write(new_db_contents.get().begin(), |
| 112 new_db_contents.get().end()); |
| 113 bytes_to_write.push_back('\0'); |
| 114 error = mojo::files::Error::INTERNAL; |
| 115 uint32_t num_bytes_written = 0; |
| 116 file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0, |
| 117 mojo::files::Whence::FROM_CURRENT, |
| 118 Capture(&error, &num_bytes_written)); |
| 119 file.WaitForIncomingResponse(); |
| 120 |
| 121 if (mojo::files::Error::OK != error) { |
| 122 write_failed = true; |
| 123 } |
| 124 } |
| 125 |
| 126 // Close the accounts db file |
| 127 error = mojo::files::Error::INTERNAL; |
| 128 file->Close(Capture(&error)); |
| 129 file.WaitForIncomingResponse(); |
| 130 if (mojo::files::Error::OK != error) { |
| 131 return false; |
| 132 } |
| 133 |
| 134 if (write_failed) { |
| 135 return false; |
| 136 } |
| 137 |
| 138 // Update the existing contents with new data |
| 139 AccountsDbManager::contents_.assign(new_db_contents.data(), |
| 140 new_db_contents.size()); |
| 141 return true; |
| 142 } |
| 143 |
| 144 void AccountsDbManager::GetAccountDataForUser(const mojo::String& username, |
| 145 mojo::String& user_data) { |
| 146 if (username.is_null()) { |
| 147 return; |
| 148 } |
| 149 |
| 150 if (AccountsDbManager::contents_.empty()) { |
| 151 mojo::Array<uint8_t> all_accounts_data( |
| 152 AccountsDbManager::FetchAllAccounts()); |
| 153 if (!all_accounts_data.size()) { |
| 154 return; |
| 155 } |
| 156 } |
| 157 |
| 158 base::StringTokenizer lines(AccountsDbManager::contents_, "\n"); |
| 159 std::string entry; |
| 160 while (lines.GetNext()) { |
| 161 entry = lines.token(); |
| 162 if (entry.find(username) != std::string::npos) { |
| 163 user_data.Swap(&entry); |
| 164 return; |
| 165 } |
| 166 } |
| 167 } |
| 168 |
| 169 mojo::Array<uint8_t> AccountsDbManager::FetchAllAccounts() { |
| 170 const size_t kMaxReadSize = 1 * 1024 * 1024; |
| 171 bool read_failed = false; |
| 172 mojo::Array<uint8_t> bytes_read; |
| 173 |
| 174 // Open accounts db file |
| 175 mojo::files::FilePtr file; |
| 176 mojo::files::Error error = mojo::files::Error::INTERNAL; |
| 177 directory_->OpenFile(kAccountsDbFileName, GetProxy(&file), |
| 178 mojo::files::kOpenFlagRead, Capture(&error)); |
| 179 directory_.WaitForIncomingResponse(); |
| 180 if (mojo::files::Error::OK != error) { |
| 181 read_failed = true; |
| 182 } else { |
| 183 // Read from it. |
| 184 error = mojo::files::Error::INTERNAL; |
| 185 file->Read(kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, |
| 186 Capture(&error, &bytes_read)); |
| 187 |
| 188 file.WaitForIncomingResponse(); |
| 189 if (mojo::files::Error::OK != error) { |
| 190 read_failed = true; |
| 191 } |
| 192 } |
| 193 |
| 194 // Close the accounts db file |
| 195 error = mojo::files::Error::INTERNAL; |
| 196 file->Close(Capture(&error)); |
| 197 file.WaitForIncomingResponse(); |
| 198 if (mojo::files::Error::OK != error) { |
| 199 return mojo::Array<uint8_t>(); |
| 200 } |
| 201 |
| 202 if (read_failed) { |
| 203 return mojo::Array<uint8_t>(); |
| 204 } |
| 205 |
| 206 const std::vector<uint8_t> vec = bytes_read.storage(); |
| 207 AccountsDbManager::contents_.assign((char*)vec.data(), vec.size()); |
| 208 |
| 209 return bytes_read.Pass(); |
| 210 } |
| 211 |
| 212 } // namespace authentication |
OLD | NEW |