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 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 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 104 bool LoginsTable::IsSyncable() { 105 return true; 106 } 107 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 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 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 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 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 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