[Author: andreip]
[google-gears.git] / gears / base / common / permissions_db.cc
blob8e3d49fa8c2d1c600515d355ed57ef87c9e8f737
1 // Copyright 2007, Google Inc.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without
13 // specific prior written permission.
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "gears/base/common/permissions_db.h"
27 #include "gears/base/common/sqlite_wrapper.h"
28 #include "gears/base/common/thread_locals.h"
29 #include "gears/localserver/common/localserver_db.h"
31 static const char16 *kDatabaseName = STRING16(L"permissions.db");
32 static const char16 *kVersionTableName = STRING16(L"VersionInfo");
33 static const char16 *kVersionKeyName = STRING16(L"Version");
34 static const char16 *kAccessTableName = STRING16(L"Access");
35 static const int kCurrentVersion = 4;
36 static const int kOldestUpgradeableVersion = 1;
39 const std::string PermissionsDB::kThreadLocalKey("base:permissions");
42 PermissionsDB *PermissionsDB::GetDB() {
43 if (ThreadLocals::HasValue(kThreadLocalKey)) {
44 return reinterpret_cast<PermissionsDB*>(
45 ThreadLocals::GetValue(kThreadLocalKey));
48 PermissionsDB *db = new PermissionsDB();
50 // If we can't initialize, we store NULL in the map so that we don't keep
51 // trying to Init() over and over.
52 if (!db->Init()) {
53 delete db;
54 db = NULL;
57 ThreadLocals::SetValue(kThreadLocalKey, db, &DestroyDB);
58 return db;
62 void PermissionsDB::DestroyDB(void *context) {
63 PermissionsDB *db = reinterpret_cast<PermissionsDB*>(context);
64 if (db) {
65 delete db;
70 PermissionsDB::PermissionsDB()
71 : version_table_(&db_, kVersionTableName),
72 access_table_(&db_, kAccessTableName),
73 shortcut_table_(&db_) {
77 bool PermissionsDB::Init() {
78 // Initialize the database and tables
79 if (!db_.Open(kDatabaseName)) {
80 return false;
83 // Examine the contents of the database and determine if we have to
84 // instantiate or updgrade the schema.
85 int version = 0;
86 version_table_.GetInt(kVersionKeyName, &version);
88 // if its the version we're expecting, great
89 if (version == kCurrentVersion) {
90 return true;
93 // Doing this in a transaction effectively locks the database file and
94 // ensures that this is synchronized across all threads and processes
95 SQLTransaction transaction(&db_, "PermissionsDB::Init");
96 if (!transaction.Begin()) {
97 return false;
100 // Fetch the version again in case someone else beat us to the
101 // upgrade.
102 version_table_.GetInt(kVersionKeyName, &version);
103 if (version == kCurrentVersion) {
104 return true;
107 if (0 == version) {
108 // No database in place, create it.
110 // TODO(shess) Verify that this is true. Is it _no_ database, or
111 // is there a database which didn't have a version? The latter
112 // case would be masked by the CREATE IF NOT EXISTS statements
113 // we're using.
114 if (!CreateDatabase()) {
115 return false;
117 } else {
118 if (!UpgradeToVersion4()) {
119 return false;
123 // Double-check that we ended up with the right version.
124 version_table_.GetInt(kVersionKeyName, &version);
125 if (version != kCurrentVersion) {
126 return false;
129 return transaction.Commit();
133 PermissionsDB::PermissionValue PermissionsDB::GetCanAccessGears(
134 const SecurityOrigin &origin) {
135 int retval_int = PERMISSION_DEFAULT;
136 access_table_.GetInt(origin.url().c_str(), &retval_int);
137 return static_cast<PermissionsDB::PermissionValue>(retval_int);
141 void PermissionsDB::SetCanAccessGears(const SecurityOrigin &origin,
142 PermissionsDB::PermissionValue value) {
143 if (origin.url().empty()) {
144 assert(false);
145 return;
148 if (value == PERMISSION_DEFAULT) {
149 access_table_.Clear(origin.url().c_str());
150 } else if (value == PERMISSION_ALLOWED || value == PERMISSION_DENIED) {
151 access_table_.SetInt(origin.url().c_str(), value);
152 } else {
153 LOG(("PermissionsDB::SetCanAccessGears invalid value: %d", value));
154 assert(false);
157 if (value == PERMISSION_DENIED || value == PERMISSION_DEFAULT) {
158 WebCacheDB *webcacheDB = WebCacheDB::GetDB();
159 if (webcacheDB) {
160 webcacheDB->DeleteServersForOrigin(origin);
166 bool PermissionsDB::GetOriginsByValue(PermissionsDB::PermissionValue value,
167 std::vector<SecurityOrigin> *result) {
168 if (PERMISSION_ALLOWED != value && PERMISSION_DENIED != value) {
169 LOG(("Unexpected value: %d", value));
170 return false;
173 // TODO(aa): Refactor into NameValueTable::FindNamesByIntValue().
174 std::string16 sql(STRING16(L"SELECT Name FROM "));
175 sql += kAccessTableName;
176 sql += STRING16(L" WHERE Value = ? ORDER BY Name ASC");
178 SQLStatement statement;
179 if (SQLITE_OK != statement.prepare16(&db_, sql.c_str())) {
180 return false;
183 if (SQLITE_OK != statement.bind_int(0, value)) {
184 return false;
187 int rv;
188 while (SQLITE_DONE != (rv = statement.step())) {
189 if (SQLITE_ROW != rv) {
190 LOG(("PermissionsDB::ListGearsAccess: Could not iterate. Error was: %d",
191 db_.GetErrorCode()));
192 return false;
195 SecurityOrigin origin;
196 if (!origin.InitFromUrl(statement.column_text16_safe(0))) {
197 LOG(("PermissionsDB::ListGearsAccess: InitFromUrl() failed."));
198 // If we can't initialize a single URL, don't freak out. Try to do the
199 // other ones.
200 continue;
202 result->push_back(origin);
205 return true;
209 bool PermissionsDB::EnableGearsForWorker(const SecurityOrigin &origin) {
210 SQLTransaction transaction(&db_, "PermissionsDB::EnableGearsForWorker");
211 if (!transaction.Begin()) {
212 return false;
215 switch (GetCanAccessGears(origin)) {
216 case PERMISSION_ALLOWED:
217 return true;
218 case PERMISSION_DENIED:
219 return false;
220 case PERMISSION_DEFAULT:
221 if (!access_table_.SetInt(origin.url().c_str(), PERMISSION_ALLOWED)) {
222 return false;
224 return transaction.Commit();
225 default:
226 LOG(("Unexpected permission value"));
227 return false;
231 bool PermissionsDB::SetShortcut(const SecurityOrigin &origin,
232 const char16 *name, const char16 *app_url,
233 const std::vector<std::string16> &icon_urls,
234 const char16 *msg) {
235 return shortcut_table_.SetShortcut(origin.url().c_str(), name,
236 app_url, icon_urls, msg);
239 bool PermissionsDB::GetOriginsWithShortcuts(
240 std::vector<SecurityOrigin> *result) {
242 std::vector<std::string16> origin_urls;
243 if (!shortcut_table_.GetOriginsWithShortcuts(&origin_urls)) {
244 return false;
247 for (size_t ii = 0; ii < origin_urls.size(); ++ii) {
248 SecurityOrigin origin;
249 if (!origin.InitFromUrl(origin_urls[ii].c_str())) {
250 LOG(("PermissionsDB::GetOriginsWithShortcuts: InitFromUrl() failed."));
251 // If we can't initialize a single URL, don't freak out. Try to do the
252 // other ones.
253 continue;
255 result->push_back(origin);
257 return true;
260 bool PermissionsDB::GetOriginShortcuts(const SecurityOrigin &origin,
261 std::vector<std::string16> *names) {
262 return shortcut_table_.GetOriginShortcuts(origin.url().c_str(), names);
265 bool PermissionsDB::GetShortcut(const SecurityOrigin &origin,
266 const char16 *name, std::string16 *app_url,
267 std::vector<std::string16> *icon_urls,
268 std::string16 *msg) {
269 return shortcut_table_.GetShortcut(origin.url().c_str(), name,
270 app_url, icon_urls, msg);
273 bool PermissionsDB::DeleteShortcut(const SecurityOrigin &origin,
274 const char16 *name) {
275 return shortcut_table_.DeleteShortcut(origin.url().c_str(), name);
278 bool PermissionsDB::DeleteShortcuts(const SecurityOrigin &origin) {
279 return shortcut_table_.DeleteShortcuts(origin.url().c_str());
282 bool PermissionsDB::CreateDatabase() {
283 ASSERT_SINGLE_THREAD();
285 SQLTransaction transaction(&db_, "PermissionsDB::CreateDatabase");
286 if (!transaction.Begin()) {
287 return false;
290 if (!db_.DropAllObjects()) {
291 return false;
294 if (!version_table_.MaybeCreateTable() ||
295 !access_table_.MaybeCreateTable() ||
296 !shortcut_table_.MaybeCreateTable()) {
297 return false;
300 // set the current version
301 if (!version_table_.SetInt(kVersionKeyName, kCurrentVersion)) {
302 return false;
305 return transaction.Commit();
308 bool PermissionsDB::UpgradeToVersion2() {
309 SQLTransaction transaction(&db_, "PermissionsDB::UpgradeToVersion2");
310 if (!transaction.Begin()) {
311 return false;
314 int version = 0;
315 version_table_.GetInt(kVersionKeyName, &version);
317 if (version != 1) {
318 LOG(("PermissionsDB::UpgradeToVersion2 unexpected version: %d", version));
319 return false;
322 // There was a bug in v1 of this db where we inserted some corrupt UTF-8
323 // characters into the db. This was pre-release, so it's not worth trying
324 // to clean it up. Instead just remove old permissions.
326 // TODO(shess) I'm inclined to say "DROP TABLE IF EXISTS
327 // ScourAccess". Or, since this was from a pre-release schema,
328 // "upgrade" version 1 by calling CreateDatabase(), which will drop
329 // all existing tables.
330 if (SQLITE_OK != db_.Execute("DELETE FROM ScourAccess")) {
331 return false;
334 if (!version_table_.SetInt(kVersionKeyName, 2)) {
335 return false;
338 return transaction.Commit();
341 bool PermissionsDB::UpgradeToVersion3() {
342 SQLTransaction transaction(&db_, "PermissionsDB::UpgradeToVersion3");
343 if (!transaction.Begin()) {
344 return false;
347 int version = 0;
348 version_table_.GetInt(kVersionKeyName, &version);
350 if (version < 2) {
351 if (!UpgradeToVersion2()) {
352 return false;
354 version_table_.GetInt(kVersionKeyName, &version);
357 if (version != 2) {
358 LOG(("PermissionsDB::UpgradeToVersion3 unexpected version: %d", version));
359 return false;
362 if (!shortcut_table_.UpgradeToVersion3()) {
363 return false;
366 if (!version_table_.SetInt(kVersionKeyName, 3)) {
367 return false;
370 return transaction.Commit();
373 bool PermissionsDB::UpgradeToVersion4() {
374 SQLTransaction transaction(&db_, "PermissionsDB::UpgradeToVersion4");
375 if (!transaction.Begin()) {
376 return false;
379 int version = 0;
380 version_table_.GetInt(kVersionKeyName, &version);
382 if (version < 3) {
383 if (!UpgradeToVersion3()) {
384 return false;
386 version_table_.GetInt(kVersionKeyName, &version);
389 if (version != 3) {
390 LOG(("PermissionsDB::UpgradeToVersion4 unexpected version: %d", version));
391 return false;
394 if (!shortcut_table_.UpgradeFromVersion3ToVersion4()) {
395 return false;
398 if (!version_table_.SetInt(kVersionKeyName, 4)) {
399 return false;
402 return transaction.Commit();