• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. 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 "chrome/browser/webdata/logins_table.h"
6 
7 #include <limits>
8 #include <string>
9 
10 #include "app/sql/statement.h"
11 #include "base/logging.h"
12 #include "chrome/browser/password_manager/encryptor.h"
13 #include "webkit/glue/password_form.h"
14 
15 using webkit_glue::PasswordForm;
16 
17 namespace {
18 
InitPasswordFormFromStatement(PasswordForm * form,sql::Statement * s)19 void InitPasswordFormFromStatement(PasswordForm* form, sql::Statement* s) {
20   std::string tmp;
21   string16 decrypted_password;
22   tmp = s->ColumnString(0);
23   form->origin = GURL(tmp);
24   tmp = s->ColumnString(1);
25   form->action = GURL(tmp);
26   form->username_element = s->ColumnString16(2);
27   form->username_value = s->ColumnString16(3);
28   form->password_element = s->ColumnString16(4);
29 
30   int encrypted_password_len = s->ColumnByteLength(5);
31   std::string encrypted_password;
32   if (encrypted_password_len) {
33     encrypted_password.resize(encrypted_password_len);
34     memcpy(&encrypted_password[0], s->ColumnBlob(5), encrypted_password_len);
35     Encryptor::DecryptString16(encrypted_password, &decrypted_password);
36   }
37 
38   form->password_value = decrypted_password;
39   form->submit_element = s->ColumnString16(6);
40   tmp = s->ColumnString(7);
41   form->signon_realm = tmp;
42   form->ssl_valid = (s->ColumnInt(8) > 0);
43   form->preferred = (s->ColumnInt(9) > 0);
44   form->date_created = base::Time::FromTimeT(s->ColumnInt64(10));
45   form->blacklisted_by_user = (s->ColumnInt(11) > 0);
46   int scheme_int = s->ColumnInt(12);
47   DCHECK((scheme_int >= 0) && (scheme_int <= PasswordForm::SCHEME_OTHER));
48   form->scheme = static_cast<PasswordForm::Scheme>(scheme_int);
49 }
50 
51 }  // anonymous namespace
52 
Init()53 bool LoginsTable::Init() {
54   if (!db_->DoesTableExist("logins")) {
55     if (!db_->Execute("CREATE TABLE logins ("
56                       "origin_url VARCHAR NOT NULL, "
57                       "action_url VARCHAR, "
58                       "username_element VARCHAR, "
59                       "username_value VARCHAR, "
60                       "password_element VARCHAR, "
61                       "password_value BLOB, "
62                       "submit_element VARCHAR, "
63                       "signon_realm VARCHAR NOT NULL,"
64                       "ssl_valid INTEGER NOT NULL,"
65                       "preferred INTEGER NOT NULL,"
66                       "date_created INTEGER NOT NULL,"
67                       "blacklisted_by_user INTEGER NOT NULL,"
68                       "scheme INTEGER NOT NULL,"
69                       "UNIQUE "
70                       "(origin_url, username_element, "
71                       "username_value, password_element, "
72                       "submit_element, signon_realm))")) {
73       NOTREACHED();
74       return false;
75     }
76     if (!db_->Execute("CREATE INDEX logins_signon ON logins (signon_realm)")) {
77       NOTREACHED();
78       return false;
79     }
80   }
81 
82 #if defined(OS_WIN)
83   if (!db_->DoesTableExist("ie7_logins")) {
84     if (!db_->Execute("CREATE TABLE ie7_logins ("
85                       "url_hash VARCHAR NOT NULL, "
86                       "password_value BLOB, "
87                       "date_created INTEGER NOT NULL,"
88                       "UNIQUE "
89                       "(url_hash))")) {
90       NOTREACHED();
91       return false;
92     }
93     if (!db_->Execute("CREATE INDEX ie7_logins_hash ON "
94                       "ie7_logins (url_hash)")) {
95       NOTREACHED();
96       return false;
97     }
98   }
99 #endif
100 
101   return true;
102 }
103 
IsSyncable()104 bool LoginsTable::IsSyncable() {
105   return true;
106 }
107 
AddLogin(const PasswordForm & form)108 bool LoginsTable::AddLogin(const PasswordForm& form) {
109   sql::Statement s(db_->GetUniqueStatement(
110       "INSERT OR REPLACE INTO logins "
111       "(origin_url, action_url, username_element, username_value, "
112       " password_element, password_value, submit_element, "
113       " signon_realm, ssl_valid, preferred, date_created, "
114       " blacklisted_by_user, scheme) "
115       "VALUES "
116       "(?,?,?,?,?,?,?,?,?,?,?,?,?)"));
117   if (!s) {
118     NOTREACHED() << "Statement prepare failed";
119     return false;
120   }
121 
122   std::string encrypted_password;
123   s.BindString(0, form.origin.spec());
124   s.BindString(1, form.action.spec());
125   s.BindString16(2, form.username_element);
126   s.BindString16(3, form.username_value);
127   s.BindString16(4, form.password_element);
128   Encryptor::EncryptString16(form.password_value, &encrypted_password);
129   s.BindBlob(5, encrypted_password.data(),
130              static_cast<int>(encrypted_password.length()));
131   s.BindString16(6, form.submit_element);
132   s.BindString(7, form.signon_realm);
133   s.BindInt(8, form.ssl_valid);
134   s.BindInt(9, form.preferred);
135   s.BindInt64(10, form.date_created.ToTimeT());
136   s.BindInt(11, form.blacklisted_by_user);
137   s.BindInt(12, form.scheme);
138   if (!s.Run()) {
139     NOTREACHED();
140     return false;
141   }
142   return true;
143 }
144 
UpdateLogin(const PasswordForm & form)145 bool LoginsTable::UpdateLogin(const PasswordForm& form) {
146   sql::Statement s(db_->GetUniqueStatement(
147       "UPDATE logins SET "
148       "action_url = ?, "
149       "password_value = ?, "
150       "ssl_valid = ?, "
151       "preferred = ? "
152       "WHERE origin_url = ? AND "
153       "username_element = ? AND "
154       "username_value = ? AND "
155       "password_element = ? AND "
156       "signon_realm = ?"));
157   if (!s) {
158     NOTREACHED() << "Statement prepare failed";
159     return false;
160   }
161 
162   s.BindString(0, form.action.spec());
163   std::string encrypted_password;
164   Encryptor::EncryptString16(form.password_value, &encrypted_password);
165   s.BindBlob(1, encrypted_password.data(),
166              static_cast<int>(encrypted_password.length()));
167   s.BindInt(2, form.ssl_valid);
168   s.BindInt(3, form.preferred);
169   s.BindString(4, form.origin.spec());
170   s.BindString16(5, form.username_element);
171   s.BindString16(6, form.username_value);
172   s.BindString16(7, form.password_element);
173   s.BindString(8, form.signon_realm);
174 
175   if (!s.Run()) {
176     NOTREACHED();
177     return false;
178   }
179   return true;
180 }
181 
RemoveLogin(const PasswordForm & form)182 bool LoginsTable::RemoveLogin(const PasswordForm& form) {
183   // Remove a login by UNIQUE-constrained fields.
184   sql::Statement s(db_->GetUniqueStatement(
185       "DELETE FROM logins WHERE "
186       "origin_url = ? AND "
187       "username_element = ? AND "
188       "username_value = ? AND "
189       "password_element = ? AND "
190       "submit_element = ? AND "
191       "signon_realm = ?"));
192   if (!s) {
193     NOTREACHED() << "Statement prepare failed";
194     return false;
195   }
196   s.BindString(0, form.origin.spec());
197   s.BindString16(1, form.username_element);
198   s.BindString16(2, form.username_value);
199   s.BindString16(3, form.password_element);
200   s.BindString16(4, form.submit_element);
201   s.BindString(5, form.signon_realm);
202 
203   if (!s.Run()) {
204     NOTREACHED();
205     return false;
206   }
207   return true;
208 }
209 
RemoveLoginsCreatedBetween(base::Time delete_begin,base::Time delete_end)210 bool LoginsTable::RemoveLoginsCreatedBetween(base::Time delete_begin,
211                                              base::Time delete_end) {
212   sql::Statement s1(db_->GetUniqueStatement(
213       "DELETE FROM logins WHERE "
214       "date_created >= ? AND date_created < ?"));
215   if (!s1) {
216     NOTREACHED() << "Statement 1 prepare failed";
217     return false;
218   }
219   s1.BindInt64(0, delete_begin.ToTimeT());
220   s1.BindInt64(1,
221                delete_end.is_null() ?
222                    std::numeric_limits<int64>::max() :
223                    delete_end.ToTimeT());
224   bool success = s1.Run();
225 
226 #if defined(OS_WIN)
227   sql::Statement s2(db_->GetUniqueStatement(
228       "DELETE FROM ie7_logins WHERE date_created >= ? AND date_created < ?"));
229   if (!s2) {
230     NOTREACHED() << "Statement 2 prepare failed";
231     return false;
232   }
233   s2.BindInt64(0, delete_begin.ToTimeT());
234   s2.BindInt64(1,
235                delete_end.is_null() ?
236                    std::numeric_limits<int64>::max() :
237                    delete_end.ToTimeT());
238   success = success && s2.Run();
239 #endif
240 
241   return success;
242 }
243 
GetLogins(const PasswordForm & form,std::vector<PasswordForm * > * forms)244 bool LoginsTable::GetLogins(const PasswordForm& form,
245                             std::vector<PasswordForm*>* forms) {
246   DCHECK(forms);
247   sql::Statement s(db_->GetUniqueStatement(
248                 "SELECT origin_url, action_url, "
249                 "username_element, username_value, "
250                 "password_element, password_value, "
251                 "submit_element, signon_realm, "
252                 "ssl_valid, preferred, "
253                 "date_created, blacklisted_by_user, scheme FROM logins "
254                 "WHERE signon_realm == ?"));
255   if (!s) {
256     NOTREACHED() << "Statement prepare failed";
257     return false;
258   }
259 
260   s.BindString(0, form.signon_realm);
261 
262   while (s.Step()) {
263     PasswordForm* new_form = new PasswordForm();
264     InitPasswordFormFromStatement(new_form, &s);
265 
266     forms->push_back(new_form);
267   }
268   return s.Succeeded();
269 }
270 
GetAllLogins(std::vector<PasswordForm * > * forms,bool include_blacklisted)271 bool LoginsTable::GetAllLogins(std::vector<PasswordForm*>* forms,
272                                bool include_blacklisted) {
273   DCHECK(forms);
274   std::string stmt = "SELECT origin_url, action_url, "
275                      "username_element, username_value, "
276                      "password_element, password_value, "
277                      "submit_element, signon_realm, ssl_valid, preferred, "
278                      "date_created, blacklisted_by_user, scheme FROM logins ";
279   if (!include_blacklisted)
280     stmt.append("WHERE blacklisted_by_user == 0 ");
281   stmt.append("ORDER BY origin_url");
282 
283   sql::Statement s(db_->GetUniqueStatement(stmt.c_str()));
284   if (!s) {
285     NOTREACHED() << "Statement prepare failed";
286     return false;
287   }
288 
289   while (s.Step()) {
290     PasswordForm* new_form = new PasswordForm();
291     InitPasswordFormFromStatement(new_form, &s);
292 
293     forms->push_back(new_form);
294   }
295   return s.Succeeded();
296 }
297