Upstream version 8.37.186.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / application_storage_impl.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/application/common/application_storage_impl.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/file_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/json/json_file_value_serializer.h"
15 #include "base/json/json_string_value_serializer.h"
16 #include "sql/statement.h"
17 #include "sql/transaction.h"
18 #include "xwalk/application/common/application_storage.h"
19 #include "xwalk/application/common/application_storage_constants.h"
20 #include "xwalk/application/common/id_util.h"
21
22 namespace db_fields = xwalk::application_storage_constants;
23 namespace xwalk {
24 namespace application {
25
26 const base::FilePath::CharType ApplicationStorageImpl::kDBFileName[] =
27     FILE_PATH_LITERAL("applications.db");
28
29 const char kPermissionSeparator = '^';
30
31 // Switching the JSON format DB(version 0) to SQLite backend version 1,
32 // should migrate all data from JSON DB to SQLite applications table.
33 static const int kVersionNumber = 1;
34
35 namespace {
36
37 const std::string StoredPermissionStr[] = {
38     "ALLOW",
39     "DENY",
40     "PROMPT",
41 };
42
43 std::string ToString(StoredPermission permission) {
44   if (permission == UNDEFINED_STORED_PERM)
45     return std::string("");
46   return StoredPermissionStr[permission];
47 }
48
49 StoredPermission ToPermission(const std::string& str) {
50   unsigned int i;
51   for (i = 0; i < UNDEFINED_STORED_PERM; ++i) {
52     if (str == StoredPermissionStr[i])
53       break;
54   }
55   return static_cast<StoredPermission>(i);
56 }
57
58 inline const base::FilePath GetDBPath(const base::FilePath& path) {
59   return path.Append(ApplicationStorageImpl::kDBFileName);
60 }
61
62 // Initializes the applications table, returning true on success.
63 bool InitApplicationsTable(sql::Connection* db) {
64   sql::Transaction transaction(db);
65   transaction.Begin();
66   // The table is named "applications", the primary key is "id".
67   if (!db->DoesTableExist(db_fields::kAppTableName)) {
68     if (!db->Execute(db_fields::kCreateAppTableOp))
69       return false;
70   }
71   return transaction.Commit();
72 }
73
74 // Permissions are stored like "bluetooth^ALLOW;calendar^DENY;contacts^ALLOW"
75 std::string ToString(StoredPermissionMap permissions) {
76   std::string str;
77   StoredPermissionMap::iterator iter;
78   for (iter = permissions.begin(); iter != permissions.end(); ++iter) {
79     if (!str.empty())
80       str += ";";
81     str += (iter->first + kPermissionSeparator + ToString(iter->second));
82   }
83   return str;
84 }
85
86 StoredPermissionMap ToPermissionMap(const std::string& str) {
87   StoredPermissionMap map;
88   std::vector<std::string> vec;
89   base::SplitString(str, ';', &vec);
90   if (!vec.empty()) {
91     for (std::vector<std::string>::iterator iter = vec.begin();
92         iter != vec.end(); ++iter) {
93       std::vector<std::string> perm_item;
94       base::SplitString(*iter, kPermissionSeparator, &perm_item);
95       if (perm_item.size() != 2) {
96         LOG(ERROR) << "Permission format error! Corrupted database?";
97         map.clear();
98         break;
99       }
100       map[perm_item[0]] = ToPermission(perm_item[1]);
101     }
102   }
103   return map;
104 }
105
106 bool InitPermissionsTable(sql::Connection* db) {
107   sql::Transaction transaction(db);
108   transaction.Begin();
109   if (!db->DoesTableExist(db_fields::kPermissionTableName)) {
110     if (!db->Execute(db_fields::kCreatePermissionTableOp))
111      return false;
112   }
113   return transaction.Commit();
114 }
115
116 }  // namespace
117
118 ApplicationStorageImpl::ApplicationStorageImpl(const base::FilePath& path)
119     : data_path_(path),
120       db_initialized_(false) {
121   // Ensure the parent directory for database file is created before reading
122   // from it.
123   if (!base::PathExists(path) && !base::CreateDirectory(path))
124     return;
125 }
126
127 bool ApplicationStorageImpl::UpgradeToVersion1(const base::FilePath& v0_file) {
128   JSONFileValueSerializer serializer(v0_file);
129   int error_code;
130   std::string error;
131   base::Value* old_db = serializer.Deserialize(&error_code, &error);
132   if (!old_db) {
133     LOG(ERROR) << "Unable to read applications information from JSON DB, "
134                   "the error message is: "
135                << error;
136     return false;
137   }
138
139   scoped_ptr<base::DictionaryValue> value;
140   for (base::DictionaryValue::Iterator it(
141            *static_cast<base::DictionaryValue*>(old_db));
142        !it.IsAtEnd(); it.Advance()) {
143     value.reset(static_cast<base::DictionaryValue*>(it.value().DeepCopy()));
144     base::DictionaryValue* manifest;
145     value->GetDictionary("manifest", &manifest);
146     std::string path;
147     value->GetString("path", &path);
148     std::string error;
149     scoped_refptr<ApplicationData> application =
150         ApplicationData::Create(base::FilePath::FromUTF8Unsafe(path),
151                                 Manifest::INTERNAL,
152                                 *manifest,
153                                 it.key(),
154                                 &error);
155     if (!application) {
156       LOG(ERROR) << "Unable to migrate the information to Version 1: " << error;
157       return false;
158     }
159
160     double install_time;
161     value->GetDouble("install_time", &install_time);
162     if (!AddApplication(application, base::Time::FromDoubleT(install_time)))
163       return false;
164   }
165   meta_table_.SetVersionNumber(1);
166
167   return true;
168 }
169
170 ApplicationStorageImpl::~ApplicationStorageImpl() {
171 }
172
173 bool ApplicationStorageImpl::Init() {
174   bool does_db_exist = base::PathExists(GetDBPath(data_path_));
175   scoped_ptr<sql::Connection> sqlite_db(new sql::Connection);
176   if (!sqlite_db->Open(GetDBPath(data_path_))) {
177     LOG(ERROR) << "Unable to open applications DB.";
178     return false;
179   }
180   sqlite_db->Preload();
181
182   if (!meta_table_.Init(sqlite_db.get(), kVersionNumber, kVersionNumber) ||
183       meta_table_.GetVersionNumber() != kVersionNumber) {
184     LOG(ERROR) << "Unable to init the META table.";
185     return false;
186   }
187
188   if (!InitApplicationsTable(sqlite_db.get())) {
189     LOG(ERROR) << "Unable to open applications table.";
190     return false;
191   }
192
193   if (!InitPermissionsTable(sqlite_db.get())) {
194     LOG(ERROR) << "Unable to open registered permissions table.";
195     return false;
196   }
197
198   if (!sqlite_db->Execute("PRAGMA foreign_keys=ON")) {
199     LOG(ERROR) << "Unable to enforce foreign key contraints.";
200     return false;
201   }
202
203   sqlite_db_.reset(sqlite_db.release());
204
205   db_initialized_ = (sqlite_db_ && sqlite_db_->is_open());
206
207   base::FilePath v0_file = data_path_.Append(
208       FILE_PATH_LITERAL("applications_db"));
209   if (base::PathExists(v0_file) &&
210       !does_db_exist) {
211     if (!UpgradeToVersion1(v0_file)) {
212       LOG(ERROR) << "Unable to migrate database from JSON format to SQLite.";
213       return false;
214     }
215     // After migrated to SQLite, delete the old JSON DB file is safe,
216     // since all information has been migrated and it will not be used anymore.
217     if (!base::DeleteFile(v0_file, false)) {
218       LOG(ERROR) << "Unalbe to delete old JSON DB file.";
219       return false;
220     }
221   }
222
223   db_initialized_ = true;
224
225   return db_initialized_;
226 }
227
228 scoped_refptr<ApplicationData> ApplicationStorageImpl::ExtractApplicationData(
229     const sql::Statement& smt) {
230   std::string id = smt.ColumnString(0);
231
232   int error_code;
233   std::string manifest_str = smt.ColumnString(1);
234   JSONStringValueSerializer serializer(&manifest_str);
235   std::string error_msg;
236   scoped_ptr<base::DictionaryValue> manifest(
237       static_cast<base::DictionaryValue*>(
238           serializer.Deserialize(&error_code, &error_msg)));
239
240   if (!manifest) {
241     LOG(ERROR) << "An error occured when deserializing the manifest, "
242                   "the error message is: "
243                << error_msg;
244     return NULL;
245   }
246   std::string path = smt.ColumnString(2);
247   double install_time = smt.ColumnDouble(3);
248
249   std::string error;
250   scoped_refptr<ApplicationData> app_data =
251       ApplicationData::Create(
252           base::FilePath::FromUTF8Unsafe(path),
253           Manifest::INTERNAL,
254           *manifest,
255           id,
256           &error);
257   if (!app_data) {
258     LOG(ERROR) << "Load appliation error: " << error;
259     return NULL;
260   }
261
262   app_data->install_time_ = base::Time::FromDoubleT(install_time);
263
264   app_data->permission_map_ = ToPermissionMap(smt.ColumnString(4));
265
266   return app_data;
267 }
268
269 scoped_refptr<ApplicationData> ApplicationStorageImpl::GetApplicationData(
270     const std::string& app_id) {
271   if (!db_initialized_) {
272     LOG(ERROR) << "The database hasn't been initilized.";
273     return NULL;
274   }
275
276   sql::Statement smt(sqlite_db_->GetUniqueStatement(
277       db_fields::kGetRowFromAppTableOp));
278   smt.BindString(0, app_id);
279   if (!smt.is_valid())
280     return NULL;
281
282   if (!smt.Step())
283     return NULL;
284
285   return ExtractApplicationData(smt);
286 }
287
288 bool ApplicationStorageImpl::GetInstalledApplications(
289     ApplicationData::ApplicationDataMap& applications) {  // NOLINT
290   if (!db_initialized_) {
291     LOG(ERROR) << "The database hasn't been initilized.";
292     return false;
293   }
294
295   sql::Statement smt(sqlite_db_->GetUniqueStatement(
296       db_fields::kGetAllRowsFromAppTableOp));
297   if (!smt.is_valid())
298     return false;
299
300   while (smt.Step()) {
301     scoped_refptr<ApplicationData> data = ExtractApplicationData(smt);
302     if (!data) {
303       LOG(ERROR) << "Failed to obtain ApplicationData from SQL query";
304       return false;
305     }
306     applications.insert(
307           std::pair<std::string, scoped_refptr<ApplicationData> >(
308               data->ID(), data));
309   }
310
311   return true;
312 }
313
314 bool ApplicationStorageImpl::GetInstalledApplicationIDs(
315   std::vector<std::string>& app_ids) {  // NOLINT
316   if (!db_initialized_) {
317     LOG(ERROR) << "The database hasn't been initilized.";
318     return false;
319   }
320
321   sql::Statement smt(sqlite_db_->GetUniqueStatement(
322       db_fields::kGetAllIDsFromAppTableOp));
323   if (!smt.is_valid())
324     return false;
325
326   while (smt.Step()) {
327     const std::string& id = smt.ColumnString(0);
328     if (!IsValidApplicationID(id)) {
329       LOG(ERROR) << "Failed to obtain Application ID from SQL query";
330       return false;
331     }
332     app_ids.push_back(id);
333   }
334
335   return true;
336 }
337
338 bool ApplicationStorageImpl::AddApplication(const ApplicationData* application,
339                                             const base::Time& install_time) {
340   if (!db_initialized_) {
341     LOG(ERROR) << "The database hasn't been initilized.";
342     return false;
343   }
344
345   return (SetApplicationValue(
346       application, install_time, db_fields::kSetApplicationWithBindOp) &&
347           SetPermissions(application->ID(), application->permission_map_));
348 }
349
350 bool ApplicationStorageImpl::UpdateApplication(
351     ApplicationData* application, const base::Time& install_time) {
352   if (!db_initialized_) {
353     LOG(ERROR) << "The database hasn't been initilized.";
354     return false;
355   }
356
357   if (SetApplicationValue(
358           application, install_time, db_fields::kUpdateApplicationWithBindOp) &&
359       UpdatePermissions(application->ID(), application->permission_map_)) {
360     return true;
361   }
362
363   return false;
364 }
365
366 bool ApplicationStorageImpl::RemoveApplication(const std::string& id) {
367   if (!db_initialized_) {
368     LOG(ERROR) << "The database hasn't been initilized.";
369     return false;
370   }
371
372   sql::Transaction transaction(sqlite_db_.get());
373   if (!transaction.Begin())
374     return false;
375
376   sql::Statement smt(sqlite_db_->GetUniqueStatement(
377       db_fields::kDeleteApplicationWithBindOp));
378   smt.BindString(0, id);
379   if (!smt.Run()) {
380     LOG(ERROR) << "Could not delete application "
381                   "information from DB.";
382     return false;
383   }
384
385   return transaction.Commit();
386 }
387
388 bool ApplicationStorageImpl::ContainsApplication(const std::string& app_id) {
389   return GetApplicationData(app_id) != NULL;
390 }
391
392 bool ApplicationStorageImpl::SetApplicationValue(
393     const ApplicationData* application,
394     const base::Time& install_time,
395     const std::string& operation) {
396   if (!application) {
397     LOG(ERROR) << "A value is needed when inserting/updating in DB.";
398     return false;
399   }
400
401   std::string manifest;
402   JSONStringValueSerializer serializer(&manifest);
403   if (!serializer.Serialize(*(application->GetManifest()->value()))) {
404     LOG(ERROR) << "An error occured when serializing the manifest value.";
405     return false;
406   }
407
408   sql::Transaction transaction(sqlite_db_.get());
409   if (!transaction.Begin())
410     return false;
411
412   sql::Statement smt(sqlite_db_->GetUniqueStatement(operation.c_str()));
413   if (!smt.is_valid()) {
414     LOG(ERROR) << "Unable to insert/update application info in DB.";
415     return false;
416   }
417   smt.BindString(0, manifest);
418   smt.BindString(1, application->Path().AsUTF8Unsafe());
419   smt.BindDouble(2, install_time.ToDoubleT());
420   smt.BindString(3, application->ID());
421   if (!smt.Run()) {
422     LOG(ERROR) << "An error occured when inserting/updating "
423                   "application info in DB.";
424     return false;
425   }
426
427   return transaction.Commit();
428 }
429
430 bool ApplicationStorageImpl::SetPermissions(const std::string& id,
431     const StoredPermissionMap& permissions) {
432   if (!db_initialized_) {
433     LOG(ERROR) << "Database is not initialized.";
434     return false;
435   }
436   return SetPermissionsValue(id, permissions,
437       db_fields::kInsertPermissionsWithBindOp);
438 }
439
440 bool ApplicationStorageImpl::UpdatePermissions(const std::string& id,
441     const StoredPermissionMap& permissions) {
442   if (!db_initialized_) {
443     LOG(ERROR) << "Database is not initialized.";
444     return false;
445   }
446   if (permissions.empty())
447     return RevokePermissions(id);
448
449   return SetPermissionsValue(id, permissions,
450       db_fields::kUpdatePermissionsWithBindOp);
451 }
452
453 bool ApplicationStorageImpl::RevokePermissions(const std::string& id) {
454   sql::Transaction transaction(sqlite_db_.get());
455   if (!transaction.Begin())
456     return false;
457
458   sql::Statement statement(sqlite_db_->GetUniqueStatement(
459       db_fields::kDeletePermissionsWithBindOp));
460   statement.BindString(0, id);
461
462   if (!statement.Run()) {
463     LOG(ERROR) <<
464         "An error occurred while removing permissions.";
465     return false;
466   }
467   return transaction.Commit();
468 }
469
470 bool ApplicationStorageImpl::SetPermissionsValue(
471     const std::string& id,
472     const StoredPermissionMap& permissions,
473     const std::string& operation) {
474   sql::Transaction transaction(sqlite_db_.get());
475   std::string permission_str = ToString(permissions);
476
477   if (!transaction.Begin())
478     return false;
479
480   sql::Statement statement(sqlite_db_->GetUniqueStatement(
481       operation.c_str()));
482   statement.BindString(0, permission_str);
483   statement.BindString(1, id);
484   if (!statement.Run()) {
485     LOG(ERROR) <<
486         "An error occurred while inserting permissions.";
487     return false;
488   }
489   return transaction.Commit();
490 }
491
492 }  // namespace application
493 }  // namespace xwalk