Index: services/authentication/accounts_db_manager.cc |
diff --git a/services/authentication/accounts_db_manager.cc b/services/authentication/accounts_db_manager.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a2a2f2a447b84168f59fe3335159c7e5703b3f16 |
--- /dev/null |
+++ b/services/authentication/accounts_db_manager.cc |
@@ -0,0 +1,183 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "services/authentication/accounts_db_manager.h" |
+ |
+#include <vector> |
+ |
+#include "base/logging.h" |
+#include "base/strings/string_tokenizer.h" |
+#include "mojo/public/cpp/bindings/array.h" |
+#include "mojo/public/cpp/bindings/type_converter.h" |
+#include "mojo/services/files/interfaces/files.mojom.h" |
+ |
+namespace authentication { |
+ |
+const char* kAccountsDbFileName = "accounts_db.txt"; |
+AccountsDbManager::AccountsDbManager() |
+ : directory_(nullptr), contents_(nullptr) {} |
+ |
+AccountsDbManager::AccountsDbManager(mojo::files::FilesPtr files) { |
+ // TODO: Move to a file system with secure privileges as the accounts db needs |
+ // to persist across multiple invocations and apps, and the temporary root |
+ // solution here is just a short term path. |
+ mojo::files::Error error = mojo::files::Error::INTERNAL; |
+ files->OpenFileSystem(nullptr, GetProxy(&directory_), Capture(&error)); |
+ files.WaitForIncomingResponse(); |
+ if (mojo::files::Error::OK != error) { |
+ LOG(FATAL) << "Unable to initialize accounts DB"; |
+ } |
+} |
+ |
+AccountsDbManager::~AccountsDbManager() {} |
+ |
+bool AccountsDbManager::UpdateAccount(const mojo::String& username, |
+ const mojo::String& new_account_data) { |
+ if (username.is_null() || new_account_data.is_null()) { |
+ return false; |
+ } |
+ |
+ std::string buffer; |
+ std::string new_contents(AccountsDbManager::contents_); |
jln (very slow on Chromium)
2015/12/08 22:27:29
No need for AccountsDbManager:: qualifier.
ukode
2015/12/16 19:24:12
Done.
|
+ mojo::String existing_user_data; |
+ AccountsDbManager::GetAccountDataForUser(username, existing_user_data); |
+ |
+ if (existing_user_data.is_null()) { // new account to be added |
jln (very slow on Chromium)
2015/12/08 22:27:29
I don't quite understand what's happening here yet
ukode
2015/12/16 19:24:12
This is very specific to account db functionality.
|
+ if (!AccountsDbManager::contents_.empty()) { |
+ buffer += "\n"; |
+ } |
+ buffer += new_account_data.get(); |
+ new_contents += buffer; |
+ } else { |
+ // Parse the existing account data and replace the token |
+ base::StringTokenizer lines(AccountsDbManager::contents_, "\n"); |
+ std::string user_data; |
+ while (lines.GetNext()) { |
+ user_data = lines.token(); |
+ if (user_data.find(username) != std::string::npos) { |
+ buffer += new_account_data.get(); // replace with new contents |
+ } else { |
+ buffer += user_data; // carry forward the existing user data |
+ } |
+ buffer += "\n"; |
+ } |
+ if (!buffer.empty()) { |
+ buffer.pop_back(); |
+ } |
+ new_contents.assign(buffer.c_str(), buffer.size()); |
jln (very slow on Chromium)
2015/12/08 22:27:29
Why are new_contents and buffer both needed. It lo
ukode
2015/12/16 19:24:13
Fixed it as part of refactoring.
|
+ } |
+ |
+ // Open accounts db file |
+ mojo::files::FilePtr file; |
+ mojo::files::Error error = mojo::files::Error::INTERNAL; |
+ if (existing_user_data.is_null()) { |
+ // Append to existing File |
+ directory_->OpenFile(kAccountsDbFileName, GetProxy(&file), |
+ mojo::files::kOpenFlagWrite | |
+ mojo::files::kOpenFlagCreate | |
+ mojo::files::kOpenFlagAppend, |
+ Capture(&error)); |
+ } else { |
+ // Rewrite the file contents with updated info |
+ directory_->OpenFile( |
+ kAccountsDbFileName, GetProxy(&file), |
+ mojo::files::kOpenFlagWrite | mojo::files::kOpenFlagCreate, |
+ Capture(&error)); |
+ } |
+ directory_.WaitForIncomingResponse(); |
+ if (mojo::files::Error::OK != error) { |
+ return false; |
jln (very slow on Chromium)
2015/12/08 22:27:29
Looks like the opened file is not getting closed h
ukode
2015/12/16 19:24:12
Good catch. Fixed it.
|
+ } |
+ |
+ // Write to it. |
+ std::vector<uint8_t> bytes_to_write(buffer.begin(), buffer.end()); |
+ bytes_to_write.push_back('\0'); |
+ error = mojo::files::Error::INTERNAL; |
+ uint32_t num_bytes_written = 0; |
+ file->Write(mojo::Array<uint8_t>::From(bytes_to_write), 0, |
+ mojo::files::Whence::FROM_CURRENT, |
+ Capture(&error, &num_bytes_written)); |
+ file.WaitForIncomingResponse(); |
+ if (mojo::files::Error::OK != error) { |
+ return false; |
+ } |
+ |
+ // Close the accounts db file |
+ error = mojo::files::Error::INTERNAL; |
+ file->Close(Capture(&error)); |
+ file.WaitForIncomingResponse(); |
+ if (mojo::files::Error::OK != error) { |
+ return false; |
+ } |
+ |
+ // Update the existing contents with new data |
+ AccountsDbManager::contents_.assign(new_contents.c_str(), |
+ new_contents.size()); |
+ return true; |
+} |
+ |
+void AccountsDbManager::GetAccountDataForUser(const mojo::String& username, |
+ mojo::String& user_data) { |
+ if (username.is_null()) { |
+ return; |
+ } |
+ |
+ if (AccountsDbManager::contents_.empty()) { |
+ mojo::Array<uint8_t> all_accounts_data( |
+ AccountsDbManager::FetchAllAccounts()); |
+ if (!all_accounts_data.size()) { |
+ return; |
+ } |
+ } |
+ |
+ base::StringTokenizer lines(AccountsDbManager::contents_, "\n"); |
+ std::string entry; |
+ while (lines.GetNext()) { |
+ entry = lines.token(); |
+ if (entry.find(username) != std::string::npos) { |
+ user_data.Swap(&entry); |
+ return; |
+ } |
+ } |
+} |
+ |
+mojo::Array<uint8_t> AccountsDbManager::FetchAllAccounts() { |
+ const size_t kMaxReadSize = 1 * 1024 * 1024; |
+ |
+ // Open accounts db file |
+ mojo::files::FilePtr file; |
+ mojo::files::Error error = mojo::files::Error::INTERNAL; |
+ directory_->OpenFile(kAccountsDbFileName, GetProxy(&file), |
+ mojo::files::kOpenFlagRead, Capture(&error)); |
+ directory_.WaitForIncomingResponse(); |
+ if (mojo::files::Error::OK != error) { |
+ return mojo::Array<uint8_t>(); |
+ } |
+ |
+ // Read from it. |
+ mojo::Array<uint8_t> bytes_read; |
+ error = mojo::files::Error::INTERNAL; |
+ file->Read(kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, |
+ Capture(&error, &bytes_read)); |
+ |
+ file.WaitForIncomingResponse(); |
+ if (mojo::files::Error::OK != error) { |
+ return mojo::Array<uint8_t>(); |
+ } |
+ |
+ // Close the accounts db file |
+ error = mojo::files::Error::INTERNAL; |
+ file->Close(Capture(&error)); |
+ file.WaitForIncomingResponse(); |
+ if (mojo::files::Error::OK != error) { |
+ return mojo::Array<uint8_t>(); |
+ } |
+ |
+ const std::vector<uint8_t> vec = bytes_read.storage(); |
jln (very slow on Chromium)
2015/12/08 22:27:29
I'm surprised if Mojo doesn't offer a better way t
ukode
2015/12/16 19:24:12
+vtl/mitch - do you have any other suggestion here
|
+ AccountsDbManager::contents_.assign((char*)vec.data(), vec.size()); |
+ |
+ return bytes_read.Pass(); |
+} |
+ |
+} // namespace authentication |