ae89dc869b93ba5f49a88661e4ab7b314dfcecf8
[WebKit-https.git] / Source / WebCore / platform / network / blackberry / CredentialBackingStore.cpp
1 /*
2  * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20
21 #if ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)
22 #include "CredentialBackingStore.h"
23
24 #include "CredentialStorage.h"
25 #include "FileSystem.h"
26 #include "KURL.h"
27 #include "NotImplemented.h"
28 #include "ProtectionSpaceHash.h"
29 #include "SQLiteStatement.h"
30 #include <BlackBerryPlatformClient.h>
31
32 #define HANDLE_SQL_EXEC_FAILURE(statement, returnValue, ...) \
33     if (statement) { \
34         LOG_ERROR(__VA_ARGS__); \
35         return returnValue; \
36     }
37
38 namespace WebCore {
39
40 CredentialBackingStore* CredentialBackingStore::instance()
41 {
42     static CredentialBackingStore* backingStore = 0;
43     if (!backingStore) {
44         backingStore = new CredentialBackingStore;
45         backingStore->open(pathByAppendingComponent(BlackBerry::Platform::Client::get()->getApplicationDataDirectory().c_str(), "/credentials.db"));
46     }
47     return backingStore;
48 }
49
50 CredentialBackingStore::CredentialBackingStore()
51     : m_addLoginStatement(0)
52     , m_updateLoginStatement(0)
53     , m_hasLoginStatement(0)
54     , m_getLoginStatement(0)
55     , m_getLoginByURLStatement(0)
56     , m_removeLoginStatement(0)
57     , m_addNeverRememberStatement(0)
58     , m_hasNeverRememberStatement(0)
59     , m_getNeverRememberStatement(0)
60     , m_removeNeverRememberStatement(0)
61 {
62 }
63
64 CredentialBackingStore::~CredentialBackingStore()
65 {
66     if (m_database.isOpen())
67         m_database.close();
68 }
69
70 bool CredentialBackingStore::open(const String& dbPath)
71 {
72     ASSERT(!m_database.isOpen());
73
74     HANDLE_SQL_EXEC_FAILURE(!m_database.open(dbPath), false,
75         "Failed to open database file %s for login database", dbPath.utf8().data());
76
77     if (!m_database.tableExists("logins")) {
78         HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE TABLE logins (origin_url VARCHAR NOT NULL, host VARCHAR NOT NULL, port INTEGER, service_type INTEGER NOT NULL, realm VARCHAR, auth_scheme INTEGER NOT NULL, username VARCHAR, password BLOB) "),
79             false, "Failed to create table logins for login database");
80
81         // Create index for table logins.
82         HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE INDEX logins_index ON logins (host)"),
83             false, "Failed to create index for table logins");
84     }
85
86     if (!m_database.tableExists("never_remember")) {
87         HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE TABLE never_remember (origin_url VARCHAR NOT NULL, host VARCHAR NOT NULL, port INTEGER, service_type INTEGER NOT NULL, realm VARCHAR, auth_scheme INTEGER NOT NULL) "),
88             false, "Failed to create table never_remember for login database");
89
90         // Create index for table never_remember.
91         HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("CREATE INDEX never_remember_index ON never_remember (host)"),
92             false, "Failed to create index for table never_remember");
93     }
94
95     // Prepare the statements.
96     m_addLoginStatement = new SQLiteStatement(m_database, "INSERT OR REPLACE INTO logins (origin_url, host, port, service_type, realm, auth_scheme, username, password) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
97     HANDLE_SQL_EXEC_FAILURE(m_addLoginStatement->prepare() != SQLResultOk,
98         false, "Failed to prepare addLogin statement");
99
100     m_updateLoginStatement = new SQLiteStatement(m_database, "UPDATE logins SET username = ?, password = ? WHERE origin_url = ? AND host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?");
101     HANDLE_SQL_EXEC_FAILURE(m_updateLoginStatement->prepare() != SQLResultOk,
102         false, "Failed to prepare updateLogin statement");
103
104     m_hasLoginStatement = new SQLiteStatement(m_database, "SELECT COUNT(*) FROM logins WHERE origin_url = ? AND host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?");
105     HANDLE_SQL_EXEC_FAILURE(m_hasLoginStatement->prepare() != SQLResultOk,
106         false, "Failed to prepare hasLogin statement");
107
108     m_getLoginStatement = new SQLiteStatement(m_database, "SELECT username, password FROM logins WHERE host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?");
109     HANDLE_SQL_EXEC_FAILURE(m_getLoginStatement->prepare() != SQLResultOk,
110         false, "Failed to prepare getLogin statement");
111
112     m_getLoginByURLStatement = new SQLiteStatement(m_database, "SELECT username, password FROM logins WHERE origin_url = ?");
113     HANDLE_SQL_EXEC_FAILURE(m_getLoginByURLStatement->prepare() != SQLResultOk,
114         false, "Failed to prepare getLoginByURL statement");
115
116     m_removeLoginStatement = new SQLiteStatement(m_database, "DELETE FROM logins WHERE origin_url = ? AND host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?");
117     HANDLE_SQL_EXEC_FAILURE(m_removeLoginStatement->prepare() != SQLResultOk,
118         false, "Failed to prepare removeLogin statement");
119
120     m_addNeverRememberStatement = new SQLiteStatement(m_database, "INSERT OR REPLACE INTO never_remember (origin_url, host, port, service_type, realm, auth_scheme) VALUES (?, ?, ?, ?, ?, ?)");
121     HANDLE_SQL_EXEC_FAILURE(m_addNeverRememberStatement->prepare() != SQLResultOk,
122         false, "Failed to prepare addNeverRemember statement");
123
124     m_hasNeverRememberStatement = new SQLiteStatement(m_database, "SELECT COUNT(*) FROM never_remember WHERE host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?");
125     HANDLE_SQL_EXEC_FAILURE(m_hasNeverRememberStatement->prepare() != SQLResultOk,
126         false, "Failed to prepare hasNeverRemember statement");
127
128     m_getNeverRememberStatement = new SQLiteStatement(m_database, "SELECT origin_url FROM never_remember WHERE host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?");
129     HANDLE_SQL_EXEC_FAILURE(m_getNeverRememberStatement->prepare() != SQLResultOk,
130         false, "Failed to prepare getNeverRemember statement");
131
132     m_removeNeverRememberStatement = new SQLiteStatement(m_database, "DELETE FROM never_remember WHERE host = ? AND port = ? AND service_type = ? AND realm = ? AND auth_scheme = ?");
133     HANDLE_SQL_EXEC_FAILURE(m_removeNeverRememberStatement->prepare() != SQLResultOk,
134         false, "Failed to prepare removeNeverRemember statement");
135
136     return true;
137 }
138
139 void CredentialBackingStore::close()
140 {
141     delete m_addLoginStatement;
142     m_addLoginStatement = 0;
143     delete m_updateLoginStatement;
144     m_updateLoginStatement = 0;
145     delete m_hasLoginStatement;
146     m_hasLoginStatement = 0;
147     delete m_getLoginStatement;
148     m_getLoginStatement = 0;
149     delete m_getLoginByURLStatement;
150     m_getLoginByURLStatement = 0;
151     delete m_removeLoginStatement;
152     m_removeLoginStatement = 0;
153     delete m_addNeverRememberStatement;
154     m_addNeverRememberStatement = 0;
155     delete m_hasNeverRememberStatement;
156     m_hasNeverRememberStatement = 0;
157     delete m_getNeverRememberStatement;
158     m_getNeverRememberStatement = 0;
159     delete m_removeNeverRememberStatement;
160     m_removeNeverRememberStatement = 0;
161
162     if (m_database.isOpen())
163         m_database.close();
164 }
165
166 bool CredentialBackingStore::addLogin(const KURL& url, const ProtectionSpace& protectionSpace, const Credential& credential)
167 {
168     ASSERT(m_database.isOpen());
169     ASSERT(m_database.tableExists("logins"));
170
171     if (!m_addLoginStatement)
172         return false;
173
174     m_addLoginStatement->bindText(1, url.string());
175     m_addLoginStatement->bindText(2, protectionSpace.host());
176     m_addLoginStatement->bindInt(3, protectionSpace.port());
177     m_addLoginStatement->bindInt(4, static_cast<int>(protectionSpace.serverType()));
178     m_addLoginStatement->bindText(5, protectionSpace.realm());
179     m_addLoginStatement->bindInt(6, static_cast<int>(protectionSpace.authenticationScheme()));
180     m_addLoginStatement->bindText(7, credential.user());
181     m_addLoginStatement->bindBlob(8, encryptedString(credential.password()));
182
183     int result = m_addLoginStatement->step();
184     m_addLoginStatement->reset();
185     HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false,
186         "Failed to add login info into table logins - %i", result);
187
188     return true;
189 }
190
191 bool CredentialBackingStore::updateLogin(const KURL& url, const ProtectionSpace& protectionSpace, const Credential& credential)
192 {
193     ASSERT(m_database.isOpen());
194     ASSERT(m_database.tableExists("logins"));
195
196     if (!m_updateLoginStatement)
197         return false;
198
199     m_updateLoginStatement->bindText(1, credential.user());
200     m_updateLoginStatement->bindBlob(2, encryptedString(credential.password()));
201     m_updateLoginStatement->bindText(3, url.string());
202     m_updateLoginStatement->bindText(4, protectionSpace.host());
203     m_updateLoginStatement->bindInt(5, protectionSpace.port());
204     m_updateLoginStatement->bindInt(6, static_cast<int>(protectionSpace.serverType()));
205     m_updateLoginStatement->bindText(7, protectionSpace.realm());
206     m_updateLoginStatement->bindInt(8, static_cast<int>(protectionSpace.authenticationScheme()));
207
208     int result = m_updateLoginStatement->step();
209     m_updateLoginStatement->reset();
210     HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false,
211         "Failed to update login info in table logins - %i", result);
212
213     return true;
214 }
215
216 bool CredentialBackingStore::hasLogin(const KURL& url, const ProtectionSpace& protectionSpace)
217 {
218     ASSERT(m_database.isOpen());
219     ASSERT(m_database.tableExists("logins"));
220
221     if (!m_hasLoginStatement)
222         return false;
223
224     m_hasLoginStatement->bindText(1, url.string());
225     m_hasLoginStatement->bindText(2, protectionSpace.host());
226     m_hasLoginStatement->bindInt(3, protectionSpace.port());
227     m_hasLoginStatement->bindInt(4, static_cast<int>(protectionSpace.serverType()));
228     m_hasLoginStatement->bindText(5, protectionSpace.realm());
229     m_hasLoginStatement->bindInt(6, static_cast<int>(protectionSpace.authenticationScheme()));
230
231     int result = m_hasLoginStatement->step();
232     int numOfRow = m_hasLoginStatement->getColumnInt(0);
233     m_hasLoginStatement->reset();
234     HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, false,
235         "Failed to execute select login info from table logins in hasLogin - %i", result);
236
237     if (numOfRow)
238         return true;
239     return false;
240 }
241
242 Credential CredentialBackingStore::getLogin(const ProtectionSpace& protectionSpace)
243 {
244     ASSERT(m_database.isOpen());
245     ASSERT(m_database.tableExists("logins"));
246
247     if (!m_getLoginStatement)
248         return Credential();
249
250     m_getLoginStatement->bindText(1, protectionSpace.host());
251     m_getLoginStatement->bindInt(2, protectionSpace.port());
252     m_getLoginStatement->bindInt(3, static_cast<int>(protectionSpace.serverType()));
253     m_getLoginStatement->bindText(4, protectionSpace.realm());
254     m_getLoginStatement->bindInt(5, static_cast<int>(protectionSpace.authenticationScheme()));
255
256     int result = m_getLoginStatement->step();
257     String username = m_getLoginStatement->getColumnText(0);
258     String password = m_getLoginStatement->getColumnBlobAsString(1);
259     m_getLoginStatement->reset();
260     HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, Credential(),
261         "Failed to execute select login info from table logins in getLogin - %i", result);
262
263     return Credential(username, decryptedString(password), CredentialPersistencePermanent);
264 }
265
266 Credential CredentialBackingStore::getLogin(const KURL& url)
267 {
268     ASSERT(m_database.isOpen());
269     ASSERT(m_database.tableExists("logins"));
270
271     if (!m_getLoginByURLStatement)
272         return Credential();
273
274     m_getLoginByURLStatement->bindText(1, url.string());
275
276     int result = m_getLoginByURLStatement->step();
277     String username = m_getLoginByURLStatement->getColumnText(0);
278     String password = m_getLoginByURLStatement->getColumnBlobAsString(1);
279     m_getLoginByURLStatement->reset();
280     HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, Credential(),
281         "Failed to execute select login info from table logins in getLogin - %i", result);
282
283     return Credential(username, decryptedString(password), CredentialPersistencePermanent);
284 }
285
286 bool CredentialBackingStore::removeLogin(const KURL& url, const ProtectionSpace& protectionSpace)
287 {
288     ASSERT(m_database.isOpen());
289     ASSERT(m_database.tableExists("logins"));
290
291     if (!m_removeLoginStatement)
292         return false;
293
294     m_removeLoginStatement->bindText(1, url.string());
295     m_removeLoginStatement->bindText(2, protectionSpace.host());
296     m_removeLoginStatement->bindInt(3, protectionSpace.port());
297     m_removeLoginStatement->bindInt(4, static_cast<int>(protectionSpace.serverType()));
298     m_removeLoginStatement->bindText(5, protectionSpace.realm());
299     m_removeLoginStatement->bindInt(6, static_cast<int>(protectionSpace.authenticationScheme()));
300
301     int result = m_removeLoginStatement->step();
302     m_removeLoginStatement->reset();
303     HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false,
304         "Failed to remove login info from table logins - %i", result);
305
306     return true;
307 }
308
309 bool CredentialBackingStore::addNeverRemember(const KURL& url, const ProtectionSpace& protectionSpace)
310 {
311     ASSERT(m_database.isOpen());
312     ASSERT(m_database.tableExists("never_remember"));
313
314     if (!m_addNeverRememberStatement)
315         return false;
316
317     m_addNeverRememberStatement->bindText(1, url.string());
318     m_addNeverRememberStatement->bindText(2, protectionSpace.host());
319     m_addNeverRememberStatement->bindInt(3, protectionSpace.port());
320     m_addNeverRememberStatement->bindInt(4, static_cast<int>(protectionSpace.serverType()));
321     m_addNeverRememberStatement->bindText(5, protectionSpace.realm());
322     m_addNeverRememberStatement->bindInt(6, static_cast<int>(protectionSpace.authenticationScheme()));
323
324     int result = m_addNeverRememberStatement->step();
325     m_addNeverRememberStatement->reset();
326     HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false,
327         "Failed to add naver saved item info into table never_remember - %i", result);
328
329     return true;
330 }
331
332 bool CredentialBackingStore::hasNeverRemember(const ProtectionSpace& protectionSpace)
333 {
334     ASSERT(m_database.isOpen());
335     ASSERT(m_database.tableExists("never_remember"));
336
337     if (!m_hasNeverRememberStatement)
338         return false;
339
340     m_hasNeverRememberStatement->bindText(1, protectionSpace.host());
341     m_hasNeverRememberStatement->bindInt(2, protectionSpace.port());
342     m_hasNeverRememberStatement->bindInt(3, static_cast<int>(protectionSpace.serverType()));
343     m_hasNeverRememberStatement->bindText(4, protectionSpace.realm());
344     m_hasNeverRememberStatement->bindInt(5, static_cast<int>(protectionSpace.authenticationScheme()));
345
346     int result = m_hasNeverRememberStatement->step();
347     int numOfRow = m_hasNeverRememberStatement->getColumnInt(0);
348     m_hasNeverRememberStatement->reset();
349     HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, false,
350         "Failed to execute select to find naver saved site from table never_remember - %i", result);
351
352     if (numOfRow)
353         return true;
354     return false;
355 }
356
357 KURL CredentialBackingStore::getNeverRemember(const ProtectionSpace& protectionSpace)
358 {
359     ASSERT(m_database.isOpen());
360     ASSERT(m_database.tableExists("never_remember"));
361
362     if (!m_getNeverRememberStatement)
363         return KURL();
364
365     m_getNeverRememberStatement->bindText(1, protectionSpace.host());
366     m_getNeverRememberStatement->bindInt(2, protectionSpace.port());
367     m_getNeverRememberStatement->bindInt(3, static_cast<int>(protectionSpace.serverType()));
368     m_getNeverRememberStatement->bindText(4, protectionSpace.realm());
369     m_getNeverRememberStatement->bindInt(5, static_cast<int>(protectionSpace.authenticationScheme()));
370
371     int result = m_getNeverRememberStatement->step();
372     String url = m_getNeverRememberStatement->getColumnText(0);
373     m_getNeverRememberStatement->reset();
374     HANDLE_SQL_EXEC_FAILURE(result != SQLResultRow, KURL(),
375         "Failed to execute select never saved site info from table never_remember in getNeverRemember - %i", result);
376
377     return KURL(ParsedURLString, url);
378 }
379
380 bool CredentialBackingStore::removeNeverRemember(const ProtectionSpace& protectionSpace)
381 {
382     ASSERT(m_database.isOpen());
383     ASSERT(m_database.tableExists("never_remember"));
384
385     if (!m_removeNeverRememberStatement)
386         return false;
387
388     m_removeNeverRememberStatement->bindText(1, protectionSpace.host());
389     m_removeNeverRememberStatement->bindInt(2, protectionSpace.port());
390     m_removeNeverRememberStatement->bindInt(3, static_cast<int>(protectionSpace.serverType()));
391     m_removeNeverRememberStatement->bindText(4, protectionSpace.realm());
392     m_removeNeverRememberStatement->bindInt(5, static_cast<int>(protectionSpace.authenticationScheme()));
393
394     int result = m_removeNeverRememberStatement->step();
395     m_removeNeverRememberStatement->reset();
396     HANDLE_SQL_EXEC_FAILURE(result != SQLResultDone, false,
397         "Failed to remove never saved site from table never_remember - %i", result);
398
399     return true;
400 }
401
402 bool CredentialBackingStore::clearLogins()
403 {
404     ASSERT(m_database.isOpen());
405     ASSERT(m_database.tableExists("logins"));
406
407     HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("DELETE FROM logins"),
408         false, "Failed to clear table logins");
409
410     return true;
411 }
412
413 bool CredentialBackingStore::clearNeverRemember()
414 {
415     ASSERT(m_database.isOpen());
416     ASSERT(m_database.tableExists("never_remember"));
417
418     HANDLE_SQL_EXEC_FAILURE(!m_database.executeCommand("DELETE FROM never_remember"),
419         false, "Failed to clear table never_remember");
420
421     return true;
422 }
423
424 String CredentialBackingStore::encryptedString(const String& plainText) const
425 {
426     // FIXME: Need encrypt plainText here
427     notImplemented();
428     return plainText;
429 }
430
431 String CredentialBackingStore::decryptedString(const String& cipherText) const
432 {
433     // FIXME: Need decrypt cipherText here
434     notImplemented();
435     return cipherText;
436 }
437
438 } // namespace WebCore
439
440 #endif // ENABLE(BLACKBERRY_CREDENTIAL_PERSIST)