| Index: extensions/browser/api/lock_screen_data/data_item.cc
|
| diff --git a/extensions/browser/api/lock_screen_data/data_item.cc b/extensions/browser/api/lock_screen_data/data_item.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..af14d5a51b0a0a5fd7daa5b8f103b68ff379caf0
|
| --- /dev/null
|
| +++ b/extensions/browser/api/lock_screen_data/data_item.cc
|
| @@ -0,0 +1,233 @@
|
| +// Copyright 2017 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 "extensions/browser/api/lock_screen_data/data_item.h"
|
| +
|
| +#include <utility>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/files/file.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/files/file_util.h"
|
| +#include "base/location.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/sequenced_task_runner.h"
|
| +#include "base/task_scheduler/post_task.h"
|
| +#include "base/values.h"
|
| +#include "crypto/encryptor.h"
|
| +#include "crypto/symmetric_key.h"
|
| +#include "extensions/browser/api/lock_screen_data/operation_result.h"
|
| +
|
| +namespace extensions {
|
| +namespace lock_screen_data {
|
| +
|
| +namespace {
|
| +
|
| +// Keys used to describe a data item in its dictionary value representation:
|
| +const char kPrefKeyId[] = "id";
|
| +const char kPrefKeyBackingFile[] = "backing_file";
|
| +
|
| +// Writes |data| to file specified by |path|. The written data will be encrypted
|
| +// using symmetric AES key |encryption_key|.
|
| +// |result| - set to the resulting write operation status.
|
| +// Expected to be called on worker thread.
|
| +void WriteImpl(const base::FilePath& path,
|
| + const std::vector<char>& data,
|
| + const std::string& encryption_key,
|
| + OperationResult* result) {
|
| + std::string iv(16, ' ');
|
| + std::unique_ptr<crypto::SymmetricKey> key =
|
| + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, encryption_key);
|
| + if (!key) {
|
| + *result = OperationResult::kInvalidKey;
|
| + return;
|
| + }
|
| +
|
| + crypto::Encryptor encryptor;
|
| + if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)) {
|
| + *result = OperationResult::kInvalidKey;
|
| + return;
|
| + }
|
| +
|
| + std::string encrypted;
|
| + if (!encryptor.Encrypt(std::string(data.data(), data.size()), &encrypted)) {
|
| + *result = OperationResult::kInvalidKey;
|
| + return;
|
| + }
|
| +
|
| + base::File::Error error;
|
| + if (!base::DirectoryExists(path.DirName()) &&
|
| + !base::CreateDirectoryAndGetError(path.DirName(), &error)) {
|
| + *result = OperationResult::kFileCreationFailed;
|
| + return;
|
| + }
|
| +
|
| + int write_size = base::WriteFile(path, encrypted.data(), encrypted.size());
|
| + *result = (write_size == static_cast<int>(encrypted.size()))
|
| + ? OperationResult::kSuccess
|
| + : OperationResult::kFileWriteFailed;
|
| +}
|
| +
|
| +// Reads encrypted data from file specified by |path|. The read data will be
|
| +// decrypted using using symmetric AES key |encryption_key| before being
|
| +// returned.
|
| +// |result| - set to the resulting write operation status.
|
| +// |data| - set to the clear-text data read from the file.
|
| +// Expected to be called on worker thread.
|
| +void ReadImpl(const base::FilePath& path,
|
| + const std::string& decryption_key,
|
| + OperationResult* result,
|
| + std::vector<char>* data) {
|
| + std::string read_data;
|
| + if (!base::ReadFileToString(path, &read_data)) {
|
| + *result = base::PathExists(path) ? OperationResult::kFileReadFailed
|
| + : OperationResult::kNotFound;
|
| + return;
|
| + }
|
| +
|
| + std::string iv(16, ' ');
|
| + std::unique_ptr<crypto::SymmetricKey> key =
|
| + crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, decryption_key);
|
| + if (!key) {
|
| + *result = OperationResult::kInvalidKey;
|
| + return;
|
| + }
|
| +
|
| + crypto::Encryptor encryptor;
|
| + if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv)) {
|
| + *result = OperationResult::kInvalidKey;
|
| + return;
|
| + }
|
| +
|
| + std::string decrypted;
|
| + if (!encryptor.Decrypt(read_data, &decrypted)) {
|
| + *result = OperationResult::kWrongKey;
|
| + return;
|
| + }
|
| +
|
| + std::vector<char> result_data(decrypted.data(),
|
| + decrypted.data() + decrypted.size());
|
| + data->swap(result_data);
|
| + *result = OperationResult::kSuccess;
|
| +}
|
| +
|
| +// Deletes file under |file_path|.
|
| +void DeleteImpl(const base::FilePath& file_path,
|
| + bool recursive,
|
| + OperationResult* result) {
|
| + *result = base::DeleteFile(file_path, recursive)
|
| + ? OperationResult::kSuccess
|
| + : OperationResult::kFileDeleteFailed;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +DataItem::DataItem(const std::string& id) : id_(id), weak_ptr_factory_(this) {}
|
| +
|
| +DataItem::~DataItem() = default;
|
| +
|
| +std::unique_ptr<base::DictionaryValue> DataItem::ToValue() {
|
| + std::unique_ptr<base::DictionaryValue> result =
|
| + base::MakeUnique<base::DictionaryValue>();
|
| + result->SetString(kPrefKeyId, id_);
|
| + result->SetString(kPrefKeyBackingFile, backing_file_.value());
|
| + return result;
|
| +}
|
| +
|
| +bool DataItem::InitFromValue(const base::Value& value) {
|
| + const base::DictionaryValue* dict_value = nullptr;
|
| + if (!value.GetAsDictionary(&dict_value))
|
| + return false;
|
| +
|
| + std::string item_id;
|
| + if (!dict_value->GetString(kPrefKeyId, &item_id) || id() != item_id)
|
| + return false;
|
| +
|
| + std::string backing_file;
|
| + if (dict_value->GetString(kPrefKeyBackingFile, &backing_file))
|
| + set_backing_file(base::FilePath(backing_file));
|
| +
|
| + return true;
|
| +}
|
| +
|
| +OperationResult DataItem::Write(
|
| + const std::vector<char>& data,
|
| + const std::string& crypto_key,
|
| + const scoped_refptr<base::SequencedTaskRunner>& task_runner,
|
| + const WriteCallback& callback) {
|
| + if (backing_file_.empty())
|
| + return OperationResult::kNoBackingFile;
|
| +
|
| + std::unique_ptr<OperationResult> result =
|
| + base::MakeUnique<OperationResult>(OperationResult::kFailed);
|
| + OperationResult* result_ptr = result.get();
|
| +
|
| + task_runner->PostTaskAndReply(
|
| + FROM_HERE,
|
| + base::Bind(&WriteImpl, backing_file_, data, crypto_key, result_ptr),
|
| + base::Bind(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(),
|
| + callback, base::Passed(&result)));
|
| + return OperationResult::kPending;
|
| +}
|
| +
|
| +OperationResult DataItem::Read(
|
| + const std::string& crypto_key,
|
| + const scoped_refptr<base::SequencedTaskRunner>& task_runner,
|
| + const ReadCallback& callback) {
|
| + if (backing_file_.empty())
|
| + return OperationResult::kNoBackingFile;
|
| +
|
| + std::unique_ptr<OperationResult> result =
|
| + base::MakeUnique<OperationResult>(OperationResult::kFailed);
|
| + OperationResult* result_ptr = result.get();
|
| +
|
| + std::unique_ptr<std::vector<char>> data =
|
| + base::MakeUnique<std::vector<char>>();
|
| + std::vector<char>* data_ptr = data.get();
|
| +
|
| + task_runner->PostTaskAndReply(
|
| + FROM_HERE,
|
| + base::Bind(&ReadImpl, backing_file_, crypto_key, result_ptr, data_ptr),
|
| + base::Bind(&DataItem::OnReadDone, weak_ptr_factory_.GetWeakPtr(),
|
| + callback, base::Passed(&result), base::Passed(&data)));
|
| + return OperationResult::kPending;
|
| +}
|
| +
|
| +OperationResult DataItem::Delete(
|
| + const scoped_refptr<base::SequencedTaskRunner>& task_runner,
|
| + const DeleteCallback& callback) {
|
| + if (backing_file_.empty())
|
| + return OperationResult::kNoBackingFile;
|
| +
|
| + std::unique_ptr<OperationResult> result =
|
| + base::MakeUnique<OperationResult>(OperationResult::kFailed);
|
| + OperationResult* result_ptr = result.get();
|
| +
|
| + task_runner->PostTaskAndReply(
|
| + FROM_HERE, base::Bind(&DeleteImpl, backing_file_, false, result_ptr),
|
| + base::Bind(&DataItem::OnDeleteDone, weak_ptr_factory_.GetWeakPtr(),
|
| + callback, base::Passed(&result)));
|
| +
|
| + backing_file_ = base::FilePath();
|
| + return OperationResult::kPending;
|
| +}
|
| +
|
| +void DataItem::OnWriteDone(const DataItem::WriteCallback& callback,
|
| + std::unique_ptr<OperationResult> success) {
|
| + callback.Run(*success);
|
| +}
|
| +
|
| +void DataItem::OnReadDone(const DataItem::ReadCallback& callback,
|
| + std::unique_ptr<OperationResult> success,
|
| + std::unique_ptr<std::vector<char>> data) {
|
| + callback.Run(*success, std::move(data));
|
| +}
|
| +
|
| +void DataItem::OnDeleteDone(const DataItem::DeleteCallback& callback,
|
| + std::unique_ptr<OperationResult> success) {
|
| + callback.Run(*success);
|
| +}
|
| +
|
| +} // namespace lock_screen_data
|
| +} // namespace extensions
|
|
|