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