| 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..b02585e028fa316b84d1b4796a423c6698a78471
|
| --- /dev/null
|
| +++ b/services/authentication/accounts_db_manager.cc
|
| @@ -0,0 +1,212 @@
|
| +// 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() {}
|
| +
|
| +void AccountsDbManager::GetUpdatedDbContents(
|
| + const mojo::String& username,
|
| + const mojo::String& new_account_data,
|
| + const bool user_exists,
|
| + mojo::String& new_db_contents) {
|
| + if (username.is_null() || new_account_data.is_null()) {
|
| + return;
|
| + }
|
| + std::string buffer;
|
| + if (user_exists) {
|
| + // Account identified as new user, add a fresh record for this user in
|
| + // accounts DB in Append mode.
|
| + if (!AccountsDbManager::contents_.empty()) {
|
| + buffer += "\n";
|
| + }
|
| + buffer += new_account_data;
|
| + } else {
|
| + // Existing user account, replace the credentials/tokens to newly
|
| + // generated auth tokens in-place.
|
| + base::StringTokenizer lines(AccountsDbManager::contents_, "\n");
|
| + std::string user_record;
|
| + while (lines.GetNext()) {
|
| + user_record = lines.token();
|
| + if (!new_db_contents.is_null() || !user_record.empty()) {
|
| + buffer += "\n";
|
| + }
|
| + if (user_record.find(username) != std::string::npos) {
|
| + buffer += new_account_data; // replace with new auth data
|
| + } else {
|
| + buffer += user_record;
|
| + }
|
| + }
|
| + }
|
| +
|
| + new_db_contents = buffer;
|
| + return;
|
| +}
|
| +
|
| +bool AccountsDbManager::UpdateAccount(const mojo::String& username,
|
| + const mojo::String& new_account_data) {
|
| + if (username.is_null() || new_account_data.is_null()) {
|
| + return false;
|
| + }
|
| + mojo::String existing_user_data;
|
| + AccountsDbManager::GetAccountDataForUser(username, existing_user_data);
|
| + mojo::String new_db_contents;
|
| + GetUpdatedDbContents(username, new_account_data, existing_user_data.is_null(),
|
| + new_db_contents);
|
| + if (new_db_contents.is_null()) {
|
| + return false;
|
| + }
|
| +
|
| + // Open accounts db file
|
| + mojo::files::FilePtr file;
|
| + mojo::files::Error error = mojo::files::Error::INTERNAL;
|
| + bool write_failed = false;
|
| + 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) {
|
| + write_failed = true;
|
| + } else {
|
| + // Write to it.
|
| + std::vector<uint8_t> bytes_to_write(new_db_contents.get().begin(),
|
| + new_db_contents.get().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) {
|
| + write_failed = true;
|
| + }
|
| + }
|
| +
|
| + // Close the accounts db file
|
| + error = mojo::files::Error::INTERNAL;
|
| + file->Close(Capture(&error));
|
| + file.WaitForIncomingResponse();
|
| + if (mojo::files::Error::OK != error) {
|
| + return false;
|
| + }
|
| +
|
| + if (write_failed) {
|
| + return false;
|
| + }
|
| +
|
| + // Update the existing contents with new data
|
| + AccountsDbManager::contents_.assign(new_db_contents.data(),
|
| + new_db_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;
|
| + bool read_failed = false;
|
| + mojo::Array<uint8_t> bytes_read;
|
| +
|
| + // 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) {
|
| + read_failed = true;
|
| + } else {
|
| + // Read from it.
|
| + 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) {
|
| + read_failed = true;
|
| + }
|
| + }
|
| +
|
| + // 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>();
|
| + }
|
| +
|
| + if (read_failed) {
|
| + return mojo::Array<uint8_t>();
|
| + }
|
| +
|
| + const std::vector<uint8_t> vec = bytes_read.storage();
|
| + AccountsDbManager::contents_.assign((char*)vec.data(), vec.size());
|
| +
|
| + return bytes_read.Pass();
|
| +}
|
| +
|
| +} // namespace authentication
|
|
|