Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: extensions/browser/api/lock_screen_data/data_item.cc

Issue 2934293003: The chrome.lockScreen.data API implementation (Closed)
Patch Set: . Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "extensions/browser/api/lock_screen_data/data_item.h"
6
7 #include <utility>
8
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/task_scheduler/post_task.h"
18 #include "base/values.h"
19 #include "crypto/encryptor.h"
20 #include "crypto/symmetric_key.h"
21 #include "extensions/browser/api/lock_screen_data/operation_result.h"
22 #include "extensions/browser/api/storage/local_value_store_cache.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/value_store/value_store.h"
25
26 namespace extensions {
27 namespace lock_screen_data {
28
29 namespace {
30
31 // Key for the dictionary in the value store containing all items registered
32 // for the extension.
33 const char kStoreKeyRegisteredItems[] = "registered_items";
34
35 // Encrypts |data| with AES key |raw_key|. Returns whether the encryption was
36 // successful, in which case |*result| will be set to the encrypted data.
37 bool EncryptData(const std::vector<char> data,
38 const std::string& raw_key,
39 std::string* result) {
40 std::string iv(16, ' ');
rkc 2017/07/10 20:04:00 I have no idea what 16 is; should this be a descri
tbarzic 2017/07/10 22:29:48 Done.
41 std::unique_ptr<crypto::SymmetricKey> key =
42 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key);
43 if (!key)
44 return false;
45
46 crypto::Encryptor encryptor;
47 if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv))
48 return false;
49
50 return encryptor.Encrypt(std::string(data.data(), data.size()), result);
51 }
52
53 // Decrypts |data| content using AES key |raw_key|. Returns the operation result
54 // code. On success, |*result| will be set to the cleartext data.
55 OperationResult DecryptData(const std::string& data,
56 const std::string& raw_key,
57 std::vector<char>* result) {
58 std::string iv(16, ' ');
59 std::unique_ptr<crypto::SymmetricKey> key =
60 crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key);
61 if (!key)
62 return OperationResult::kInvalidKey;
63
64 crypto::Encryptor encryptor;
65 if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv))
66 return OperationResult::kInvalidKey;
67
68 std::string decrypted;
69 if (!encryptor.Decrypt(data, &decrypted))
70 return OperationResult::kWrongKey;
71
72 *result =
73 std::vector<char>(decrypted.data(), decrypted.data() + decrypted.size());
74
75 return OperationResult::kSuccess;
76 }
77
78 // Returns whether the value store |store| contains a registered item with ID
79 // |item_id|.
80 bool IsItemRegistered(ValueStore* store, const std::string& item_id) {
81 ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
82
83 const base::DictionaryValue* registered_items = nullptr;
84 return read->status().ok() &&
85 read->settings().GetDictionary(kStoreKeyRegisteredItems,
86 &registered_items) &&
87 registered_items->HasKey(item_id);
88 }
89
90 // Gets a dictionary value that contains set of all registered data items from
91 // the values store |store|.
92 // |result| - the item fetch operation status code.
93 // |value| - on success, set to the dictionary containing registered data items.
94 // Note that the dictionary will not contain data item content.
95 void GetRegisteredItems(OperationResult* result,
96 std::unique_ptr<base::DictionaryValue>* values,
97 ValueStore* store) {
98 ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
99
100 std::unique_ptr<base::Value> registered_items;
101 if (!read->status().ok()) {
102 *result = OperationResult::kFailed;
103 return;
104 }
105
106 // If the registered items dictionary cannot be found, assume no items have
107 // yet been registered, and return empty result.
108 if (!read->settings().Remove(kStoreKeyRegisteredItems, &registered_items)) {
109 *values = base::MakeUnique<base::DictionaryValue>();
110 *result = OperationResult::kSuccess;
111 return;
112 }
113
114 *values = base::DictionaryValue::From(std::move(registered_items));
115 *result =
116 values->get() ? OperationResult::kSuccess : OperationResult::kFailed;
117 }
118
119 // Registers a data item with ID |item_id| in value store |store|.
120 void RegisterItem(OperationResult* result,
121 const std::string& item_id,
122 ValueStore* store) {
123 ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
124
125 std::unique_ptr<base::Value> registered_items;
126 if (!read->status().ok()) {
127 *result = OperationResult::kFailed;
128 return;
129 }
130 if (!read->settings().Remove(kStoreKeyRegisteredItems, &registered_items))
131 registered_items = base::MakeUnique<base::DictionaryValue>();
132
133 std::unique_ptr<base::DictionaryValue> dict =
134 base::DictionaryValue::From(std::move(registered_items));
135 if (!dict) {
136 *result = OperationResult::kFailed;
137 return;
138 }
139
140 if (dict->HasKey(item_id)) {
141 *result = OperationResult::kAlreadyRegistered;
142 return;
143 }
144
145 dict->Set(item_id, base::MakeUnique<base::DictionaryValue>());
146
147 ValueStore::WriteResult write =
148 store->Set(ValueStore::DEFAULTS, kStoreKeyRegisteredItems, *dict);
149 *result = write->status().ok() ? OperationResult::kSuccess
150 : OperationResult::kFailed;
151 }
152
153 // Encrypts |data| with AES key |encryption_key| and saved it as |item_id|
154 // content to the value store |store|. The encrypted data is saved base64
155 // encoded.
156 void WriteImpl(OperationResult* result,
157 const std::string item_id,
158 const std::vector<char>& data,
159 const std::string& encryption_key,
160 ValueStore* store) {
161 if (!IsItemRegistered(store, item_id)) {
162 *result = OperationResult::kNotFound;
163 return;
164 }
165
166 std::string encrypted;
167 if (!EncryptData(data, encryption_key, &encrypted)) {
168 *result = OperationResult::kInvalidKey;
169 return;
170 }
171 base::Base64Encode(encrypted, &encrypted);
172
173 ValueStore::WriteResult write = store->Set(ValueStore::DEFAULTS, item_id,
174 base::Value(std::move(encrypted)));
175
176 *result = write->status().ok() ? OperationResult::kSuccess
177 : OperationResult::kFailed;
178 }
179
180 // Gets content of the data item with ID |item_id| from value store |store|,
181 // and decrypts it using |decryption_key|. On success, the decrypted data is
182 // returned as |*data| contents. Note that this method expects the encrypted
183 // data content in the value store is base64 encoded.
184 void ReadImpl(OperationResult* result,
185 std::vector<char>* data,
186 const std::string& item_id,
187 const std::string& decryption_key,
188 ValueStore* store) {
189 if (!IsItemRegistered(store, item_id)) {
190 *result = OperationResult::kNotFound;
191 return;
192 }
193
194 ValueStore::ReadResult read = store->Get(item_id);
195 if (!read->status().ok()) {
196 *result = OperationResult::kNotFound;
197 return;
198 }
199
200 std::unique_ptr<base::Value> item;
201 if (!read->settings().Remove(item_id, &item)) {
202 *result = OperationResult::kSuccess;
203 *data = std::vector<char>();
204 return;
205 }
206
207 std::string read_data;
208 if (!item->is_string() ||
209 !base::Base64Decode(item->GetString(), &read_data)) {
210 *result = OperationResult::kFailed;
211 return;
212 }
213
214 *result = DecryptData(read_data, decryption_key, data);
215 }
216
217 void DeleteImpl(OperationResult* result,
218 const std::string& item_id,
219 ValueStore* store) {
220 ValueStore::WriteResult remove =
221 store->Remove(std::vector<std::string>({item_id}));
222 if (!remove->status().ok()) {
223 *result = OperationResult::kFailed;
224 return;
225 }
226
227 ValueStore::ReadResult read = store->Get(kStoreKeyRegisteredItems);
228 if (!read->status().ok()) {
229 *result = OperationResult::kFailed;
230 return;
231 }
232
233 base::DictionaryValue* registered_items = nullptr;
234 if (!read->settings().GetDictionary(kStoreKeyRegisteredItems,
235 &registered_items) ||
236 !registered_items->Remove(item_id, nullptr)) {
237 *result = OperationResult::kNotFound;
238 return;
239 }
240
241 ValueStore::WriteResult write = store->Set(
242 ValueStore::DEFAULTS, kStoreKeyRegisteredItems, *registered_items);
243 *result = write->status().ok() ? OperationResult::kSuccess
244 : OperationResult::kFailed;
245 }
246
247 void OnGetRegisteredValues(const DataItem::RegisteredValuesCallback& callback,
248 std::unique_ptr<OperationResult> result,
249 std::unique_ptr<base::DictionaryValue>* values) {
250 callback.Run(*result, std::move(*values));
251 }
252
253 } // namespace
254
255 // static
256 void DataItem::GetRegisteredValuesForExtension(
257 content::BrowserContext* context,
258 ValueStoreCache* value_store_cache,
259 base::SequencedTaskRunner* task_runner,
260 const std::string& extension_id,
261 const RegisteredValuesCallback& callback) {
262 scoped_refptr<const Extension> extension =
263 ExtensionRegistry::Get(context)->GetExtensionById(
264 extension_id, ExtensionRegistry::ENABLED);
265 if (!extension) {
266 callback.Run(OperationResult::kUnknownExtension, nullptr);
267 return;
268 }
269
270 std::unique_ptr<OperationResult> result =
271 base::MakeUnique<OperationResult>(OperationResult::kFailed);
272 OperationResult* result_ptr = result.get();
273 std::unique_ptr<base::DictionaryValue>* values =
274 new std::unique_ptr<base::DictionaryValue>();
275
276 task_runner->PostTaskAndReply(
277 FROM_HERE,
278 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension,
279 base::Unretained(value_store_cache),
280 base::Bind(&GetRegisteredItems, result_ptr, values),
281 extension),
282 base::Bind(&OnGetRegisteredValues, callback,
283 base::Passed(std::move(result)), base::Owned(values)));
284 }
285
286 // static
287 void DataItem::DeleteAllItemsForExtension(
288 content::BrowserContext* context,
289 ValueStoreCache* value_store_cache,
290 base::SequencedTaskRunner* task_runner,
291 const std::string& extension_id,
292 const base::Closure& callback) {
293 task_runner->PostTaskAndReply(
294 FROM_HERE,
295 base::Bind(&ValueStoreCache::DeleteStorageSoon,
296 base::Unretained(value_store_cache), extension_id),
297 callback);
298 }
299
300 DataItem::DataItem(const std::string& id,
301 const std::string& extension_id,
302 content::BrowserContext* context,
303 ValueStoreCache* value_store_cache,
304 base::SequencedTaskRunner* task_runner,
305 const std::string& crypto_key)
306 : id_(id),
307 extension_id_(extension_id),
308 context_(context),
309 value_store_cache_(value_store_cache),
310 task_runner_(task_runner),
311 crypto_key_(crypto_key),
312 weak_ptr_factory_(this) {}
313
314 DataItem::~DataItem() = default;
315
316 void DataItem::Register(const WriteCallback& callback) {
317 scoped_refptr<const Extension> extension =
318 ExtensionRegistry::Get(context_)->GetExtensionById(
319 extension_id_, ExtensionRegistry::ENABLED);
320 if (!extension) {
321 callback.Run(OperationResult::kUnknownExtension);
322 return;
323 }
324
325 std::unique_ptr<OperationResult> result =
326 base::MakeUnique<OperationResult>(OperationResult::kFailed);
327 OperationResult* result_ptr = result.get();
328
329 task_runner_->PostTaskAndReply(
330 FROM_HERE,
331 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension,
332 base::Unretained(value_store_cache_),
333 base::Bind(&RegisterItem, result_ptr, id()), extension),
334 base::Bind(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(),
335 callback, base::Passed(std::move(result))));
336 }
337
338 void DataItem::Write(const std::vector<char>& data,
339 const WriteCallback& callback) {
340 scoped_refptr<const Extension> extension =
341 ExtensionRegistry::Get(context_)->GetExtensionById(
342 extension_id_, ExtensionRegistry::ENABLED);
343 if (!extension) {
344 callback.Run(OperationResult::kUnknownExtension);
345 return;
346 }
347
348 std::unique_ptr<OperationResult> result =
349 base::MakeUnique<OperationResult>(OperationResult::kFailed);
350 OperationResult* result_ptr = result.get();
351
352 task_runner_->PostTaskAndReply(
353 FROM_HERE,
354 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension,
355 base::Unretained(value_store_cache_),
356 base::Bind(&WriteImpl, result_ptr, id_, data, crypto_key_),
357 extension),
358 base::Bind(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(),
359 callback, base::Passed(&result)));
360 }
361
362 void DataItem::Read(const ReadCallback& callback) {
363 scoped_refptr<const Extension> extension =
364 ExtensionRegistry::Get(context_)->GetExtensionById(
365 extension_id_, ExtensionRegistry::ENABLED);
366 if (!extension) {
367 callback.Run(OperationResult::kUnknownExtension, nullptr);
368 return;
369 }
370
371 std::unique_ptr<OperationResult> result =
372 base::MakeUnique<OperationResult>(OperationResult::kFailed);
373 OperationResult* result_ptr = result.get();
374
375 std::unique_ptr<std::vector<char>> data =
376 base::MakeUnique<std::vector<char>>();
377 std::vector<char>* data_ptr = data.get();
378
379 task_runner_->PostTaskAndReply(
380 FROM_HERE,
381 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension,
382 base::Unretained(value_store_cache_),
383 base::Bind(&ReadImpl, result_ptr, data_ptr, id_, crypto_key_),
384 extension),
385 base::Bind(&DataItem::OnReadDone, weak_ptr_factory_.GetWeakPtr(),
386 callback, base::Passed(&result), base::Passed(&data)));
387 }
388
389 void DataItem::Delete(const WriteCallback& callback) {
390 scoped_refptr<const Extension> extension =
391 ExtensionRegistry::Get(context_)->GetExtensionById(
392 extension_id_, ExtensionRegistry::ENABLED);
393 if (!extension) {
394 callback.Run(OperationResult::kUnknownExtension);
395 return;
396 }
397 std::unique_ptr<OperationResult> result =
398 base::MakeUnique<OperationResult>(OperationResult::kFailed);
399 OperationResult* result_ptr = result.get();
400
401 task_runner_->PostTaskAndReply(
402 FROM_HERE,
403 base::Bind(&ValueStoreCache::RunWithValueStoreForExtension,
404 base::Unretained(value_store_cache_),
405 base::Bind(&DeleteImpl, result_ptr, id_), extension),
406 base::Bind(&DataItem::OnWriteDone, weak_ptr_factory_.GetWeakPtr(),
407 callback, base::Passed(&result)));
408 }
409
410 void DataItem::OnWriteDone(const DataItem::WriteCallback& callback,
411 std::unique_ptr<OperationResult> success) {
412 callback.Run(*success);
413 }
414
415 void DataItem::OnReadDone(const DataItem::ReadCallback& callback,
416 std::unique_ptr<OperationResult> success,
417 std::unique_ptr<std::vector<char>> data) {
418 callback.Run(*success, std::move(data));
419 }
420
421 } // namespace lock_screen_data
422 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698