Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules / security_origin_dao / dao / security_origin_dao.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    security_origin_dao.cpp
18  * @author  Jihoon Chung (jihoon.chung@samsung.com)
19  * @author  Kamil Lysik (k.lysik@samsung.com)
20  * @version 1.0
21  * @brief   This file contains the definition of security origin dao class.
22  */
23
24 #include <wrt-commons/security-origin-dao/security_origin_dao.h>
25 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
26 #include <dpl/wrt-dao-ro/WrtDatabase.h>
27 #include <dpl/wrt-dao-ro/widget_config.h>
28 #include <dpl/wrt-dao-ro/global_config.h>
29 #include <dpl/wrt-dao-ro/common_dao_types.h>
30 #include <dpl/log/wrt_log.h>
31 #include <sys/stat.h>
32 #include <fstream>
33 #include <unistd.h>
34 #include <db-util.h>
35
36 namespace SecurityOriginDB {
37 using namespace WrtDB;
38 #define SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN          Try
39
40 #define SQL_CONNECTION_EXCEPTION_HANDLER_END(message)   \
41     Catch(DPL::DB::SqlConnection::Exception::Base) {       \
42         WrtLogE(message);                              \
43         ReThrowMsg(SecurityOriginDAO::Exception::DatabaseError, \
44                    message);                            \
45     }
46
47 namespace {
48 DPL::DB::SqlConnection::Flag::Option SECURITY_ORIGIN_DB_OPTION =
49     DPL::DB::SqlConnection::Flag::RW;
50 DPL::DB::SqlConnection::Flag::Type SECURITY_ORIGIN_DB_TYPE =
51     DPL::DB::SqlConnection::Flag::UseLucene;
52
53 const char* const SECURITY_ORIGIN_DB_NAME = ".security_origin.db";
54 const char* const SECURITY_ORIGIN_DB_SQL_PATH =
55     "/usr/share/wrt-engine/security_origin_db.sql";
56 const char* const SECURITY_DATABASE_JOURNAL_FILENAME = "-journal";
57
58 //query strings
59 const char* const SELECT_ORIGIN_DATA_LIST =
60         "select scheme,host,port,feature from SecurityOriginInfo";
61 const char* const SELECT_ORIGIN_GET_RESULT =
62         "select result from SecurityOriginInfo"
63         " where feature=? and scheme=? and host=? and port=?";
64 const char* const SELECT_ORIGIN_GET_READONLY =
65         "select readonly from SecurityOriginInfo"
66         " where feature=? and scheme=? and host=? and port=?";
67 const char* const DELETE_SECURITY_ORIGIN =
68         "delete from SecurityOriginInfo"
69         " where feature=? and scheme=? and host=? and port=?";
70 const char* const DELETE_SECURITY_ORIGIN_BY_RESULT =
71         "delete from SecurityOriginInfo"
72         " where result=?";
73 const char* const INSERT_SECURITY_ORIGIN =
74         "insert into SecurityOriginInfo (feature, scheme, host, port, result, readonly)"
75         "values (?, ?, ?, ?, ?, ?)";
76 const char* const UPDATE_SECURITY_ORIGIN =
77         "update SecurityOriginInfo"
78         " set result=?, readonly=?"
79         " where feature=? and scheme=? and host=? and port=?";
80
81 const int WEB_APPLICATION_UID = 5000;
82 const int WEB_APPLICATION_GUID = 5000;
83
84 std::string createDatabasePath(const WrtDB::TizenPkgId &pkgName)
85 {
86     std::stringstream filename;
87
88     filename << WrtDB::WidgetConfig::GetWidgetPersistentStoragePath(pkgName)
89              << "/"
90              << SECURITY_ORIGIN_DB_NAME;
91     return filename.str();
92 }
93
94 void checkDatabase(std::string databasePath)
95 {
96     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
97     {
98         if (databasePath.empty()) {
99             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError,
100                      "Wrong database Path is passed");
101         }
102
103         struct stat buffer;
104         if (stat(databasePath.c_str(), &buffer) != 0) {
105             //Create fresh database
106             WrtLogD("Creating database %s", databasePath.c_str());
107
108             std::fstream file;
109             file.open(SECURITY_ORIGIN_DB_SQL_PATH, std::ios_base::in);
110             if (!file) {
111                 ThrowMsg(SecurityOriginDAO::Exception::DatabaseError,
112                          "Fail to get database Path");
113             }
114
115             std::stringstream ssBuffer;
116             ssBuffer << file.rdbuf();
117
118             file.close();
119
120             DPL::DB::SqlConnection con(databasePath,
121                                        SECURITY_ORIGIN_DB_TYPE,
122                                        SECURITY_ORIGIN_DB_OPTION);
123             con.ExecCommand(ssBuffer.str().c_str());
124
125             if(chown(databasePath.c_str(),
126                      WEB_APPLICATION_UID,
127                      WEB_APPLICATION_GUID) != 0)
128             {
129                 ThrowMsg(SecurityOriginDAO::Exception::DatabaseError,
130                      "Fail to change uid/guid");
131             }
132             std::string databaseJournal =
133                 databasePath + SECURITY_DATABASE_JOURNAL_FILENAME;
134             if(chown(databaseJournal.c_str(),
135                      WEB_APPLICATION_UID,
136                      WEB_APPLICATION_GUID) != 0)
137             {
138                 ThrowMsg(SecurityOriginDAO::Exception::DatabaseError,
139                      "Fail to change uid/guid");
140             }
141         }
142     }
143     SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to get database Path")
144 }
145 } // anonymous namespace
146
147 SecurityOriginDAO::SecurityOriginDAO(const WrtDB::TizenPkgId &pkgName)
148 {
149     std::string dbPath = createDatabasePath(pkgName);
150     checkDatabase(dbPath);
151     if (DB_UTIL_OK != db_util_open_with_options(
152                             dbPath.c_str(),
153                             &m_databaseInterface,
154                             SQLITE_OPEN_READWRITE | SQLITE_OPEN_NOMUTEX,
155                             NULL)) {
156         WrtLogE("Cannot open database. %s", sqlite3_errmsg(m_databaseInterface));
157         ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "Cannot open database");
158     }
159 }
160
161 SecurityOriginDAO::~SecurityOriginDAO()
162 {
163 }
164
165 SecurityOriginDataList SecurityOriginDAO::getSecurityOriginDataList(void)
166 {
167     std::lock_guard<std::mutex> lock(m_dbLock);
168     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
169     {
170         sqlite3_stmt* stmt = sqlPrepare(SELECT_ORIGIN_DATA_LIST);
171         int rw = sqlite3_step(stmt);
172
173         SecurityOriginDataList list;
174         while (SQLITE_ROW == rw)
175         {
176             //Read from row
177             Origin origin((sqlite3_column_string(stmt, 0)),
178                           (sqlite3_column_string(stmt, 1)),
179                           sqlite3_column_int(stmt, 2));
180             list.push_back(
181                 SecurityOriginDataPtr(
182                     new SecurityOriginData(
183                         static_cast<Feature>(sqlite3_column_int(stmt, 3)), origin)));
184             //Next row
185             rw = sqlite3_step(stmt);
186         }
187         releaseStatement(stmt);
188
189         if (SQLITE_DONE != rw)
190         {
191             //Error occured
192             WrtLogE("sqlite3_step error. %s", sqlite3_errmsg(m_databaseInterface));
193             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "getSecurityOriginDataList fail");
194         }
195
196         return list;
197     }
198     SQL_CONNECTION_EXCEPTION_HANDLER_END("Failed to get data  list")
199 }
200
201 Result SecurityOriginDAO::getResult(const SecurityOriginData &data)
202 {
203     std::lock_guard<std::mutex> lock(m_dbLock);
204     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
205     {
206         Result retval = RESULT_UNKNOWN;
207         sqlite3_stmt* stmt = sqlPrepare(SELECT_ORIGIN_GET_RESULT);
208         sqlBind(stmt, 1, data.feature);
209         sqlBind(stmt, 2, data.origin.scheme);
210         sqlBind(stmt, 3, data.origin.host);
211         sqlBind(stmt, 4, data.origin.port);
212         int rw = sqlite3_step(stmt);
213         if (SQLITE_ROW == rw)
214         {
215             retval = static_cast<Result>(sqlite3_column_int(stmt, 0));
216         }
217
218         releaseStatement(stmt);
219         if (SQLITE_DONE != rw && SQLITE_ROW != rw)
220         {
221             WrtLogE("sqlite3_step error. %s", sqlite3_errmsg(m_databaseInterface));
222             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "getResult fail");
223         }
224         return retval;
225     }
226     SQL_CONNECTION_EXCEPTION_HANDLER_END("getResult error")
227 }
228
229 bool SecurityOriginDAO::isReadOnly(const SecurityOriginData &data)
230 {
231     std::lock_guard<std::mutex> lock(m_dbLock);
232     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
233     {
234         int retval = 0;
235         sqlite3_stmt* stmt = sqlPrepare(SELECT_ORIGIN_GET_READONLY);
236         sqlBind(stmt, 1, data.feature);
237         sqlBind(stmt, 2, data.origin.scheme);
238         sqlBind(stmt, 3, data.origin.host);
239         sqlBind(stmt, 4, data.origin.port);
240         int rw = sqlite3_step(stmt);
241         if (SQLITE_ROW == rw)
242         {
243             retval = static_cast<int>(sqlite3_column_int(stmt, 0));
244         }
245
246         releaseStatement(stmt);
247         if (SQLITE_DONE != rw && SQLITE_ROW != rw)
248         {
249             WrtLogE("sqlite3_step error. %s", sqlite3_errmsg(m_databaseInterface));
250             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "isReadOnly fail");
251         }
252         return 1==retval;
253     }
254     SQL_CONNECTION_EXCEPTION_HANDLER_END("isReadOnly error")
255 }
256
257 void SecurityOriginDAO::setSecurityOriginData(const SecurityOriginData &data,
258                                               const Result result,
259                                               const bool readOnly)
260 {
261     if (true == hasResult(data)) {
262         updateData(data, result, readOnly);
263     } else {
264         insertData(data, result, readOnly);
265     }
266 }
267
268 void SecurityOriginDAO::setPrivilegeSecurityOriginData(
269     const Feature feature,
270     bool isOnlyAllowedLocalOrigin)
271 {
272     //TODO: this breaks app:// scheme code -> no case for app scheme
273     Origin origin(DPL::FromUTF8String("file"),
274                   DPL::FromUTF8String(""),
275                   0);
276     if (!isOnlyAllowedLocalOrigin) {
277         origin.scheme = DPL::FromUTF8String("");
278     }
279     SecurityOriginData data(feature, origin);
280     setSecurityOriginData(data, RESULT_ALLOW_ALWAYS, true);
281 }
282
283 void SecurityOriginDAO::removeSecurityOriginData(const SecurityOriginData &data)
284 {
285     if (false == hasResult(data)) {
286         // There is no data
287         return;
288     }
289
290     std::lock_guard<std::mutex> lock(m_dbLock);
291     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
292     {
293         sqlite3_stmt* stmt = sqlPrepare(DELETE_SECURITY_ORIGIN);
294         sqlBind(stmt, 1, data.feature);
295         sqlBind(stmt, 2, data.origin.scheme);
296         sqlBind(stmt, 3, data.origin.host);
297         sqlBind(stmt, 4, data.origin.port);
298
299         //TODO: Transaction?
300         int rw = sqlite3_step(stmt);
301         releaseStatement(stmt);
302         if (SQLITE_DONE != rw)
303         {
304             WrtLogE("sqlite3_step error. %s", sqlite3_errmsg(m_databaseInterface));
305             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "removeSecurityOriginData fail");
306         }
307     }
308     SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to remove security origin data")
309 }
310
311 void SecurityOriginDAO::removeSecurityOriginData(const Result result)
312 {
313     std::lock_guard<std::mutex> lock(m_dbLock);
314     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
315     {
316         sqlite3_stmt* stmt = sqlPrepare(DELETE_SECURITY_ORIGIN_BY_RESULT);
317         sqlBind(stmt, 1, static_cast<int>(result));
318
319         //TODO: Transaction?
320         int rw = sqlite3_step(stmt);
321         releaseStatement(stmt);
322         if (SQLITE_DONE != rw)
323         {
324             WrtLogE("sqlite3_step error. %s", sqlite3_errmsg(m_databaseInterface));
325             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "removeSecurityOriginData fail");
326         }
327     }
328     SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to remove data by result")
329 }
330
331 bool SecurityOriginDAO::hasResult(const SecurityOriginData &data)
332 {
333     Result ret = getResult(data);
334     return (ret != RESULT_UNKNOWN);
335 }
336
337 void SecurityOriginDAO::insertData(const SecurityOriginData &data,
338                                    const Result result,
339                                    const bool readOnly)
340 {
341     std::lock_guard<std::mutex> lock(m_dbLock);
342     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
343     {
344         sqlite3_stmt* stmt = sqlPrepare(INSERT_SECURITY_ORIGIN);
345         sqlBind(stmt, 1, data.feature);
346         sqlBind(stmt, 2, data.origin.scheme);
347         sqlBind(stmt, 3, data.origin.host);
348         sqlBind(stmt, 4, data.origin.port);
349         sqlBind(stmt, 5, static_cast<int>(result));
350         sqlBind(stmt, 6, readOnly ? 1 : 0);
351
352         //TODO: Transaction?
353         int rw = sqlite3_step(stmt);
354         releaseStatement(stmt);
355         if (SQLITE_DONE != rw)
356         {
357             WrtLogE("sqlite3_step error. %s", sqlite3_errmsg(m_databaseInterface));
358             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "insertData fail");
359         }
360     }
361     SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to insert")
362 }
363
364 void SecurityOriginDAO::updateData(const SecurityOriginData &data,
365                                    const Result result,
366                                    const bool readOnly)
367 {
368     std::lock_guard<std::mutex> lock(m_dbLock);
369     SQL_CONNECTION_EXCEPTION_HANDLER_BEGIN
370     {
371         sqlite3_stmt* stmt = sqlPrepare(UPDATE_SECURITY_ORIGIN);
372
373         sqlBind(stmt, 1, static_cast<int>(result));
374         sqlBind(stmt, 2, readOnly ? 1 : 0);
375
376         sqlBind(stmt, 3, data.feature);
377         sqlBind(stmt, 4, data.origin.scheme);
378         sqlBind(stmt, 5, data.origin.host);
379         sqlBind(stmt, 6, data.origin.port);
380
381         //TODO: Transaction?
382         int rw = sqlite3_step(stmt);
383         releaseStatement(stmt);
384         if (SQLITE_DONE != rw)
385         {
386             WrtLogE("sqlite3_step error. %s", sqlite3_errmsg(m_databaseInterface));
387             ThrowMsg(SecurityOriginDAO::Exception::DatabaseError, "updateData fail");
388         }
389     }
390     SQL_CONNECTION_EXCEPTION_HANDLER_END("Fail to update")
391 }
392
393 } // namespace SecurityOriginDB