Chromium Code Reviews| 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)); | |
|
viettrungluu
2015/12/18 20:59:49
I don't think you should block the thread (and eve
ukode
2016/01/06 23:52:59
Good point. Made the change.
| |
| 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)); | |
|
viettrungluu
2015/12/18 20:59:49
In general, you shouldn't do synchronous I/O (i.e.
ukode
2016/01/06 23:52:59
Moved the opening and closing files to ctor and dt
| |
| 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 |