1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This class isn't pretty. It's just a step better than globals, which is what
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// these were previously.
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/util/user_settings.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "build/build_config.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <windows.h>
14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <limits>
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <vector>
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/file_util.h"
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/syncable/directory_manager.h"  // For migration.
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/util/crypto_helpers.h"
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/sync/util/data_encryption.h"
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/sqlite_utils.h"
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::numeric_limits;
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::string;
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing std::vector;
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing syncable::DirectoryManager;
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace browser_sync {
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExecOrDie(sqlite3* dbhandle, const char *query) {
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLStatement statement;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.prepare(dbhandle, query);
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (SQLITE_DONE != statement.step()) {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    LOG(FATAL) << query << "\n" << sqlite3_errmsg(dbhandle);
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Useful for encoding any sequence of bytes into a string that can be used in
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// a table name. Kind of like hex encoding, except that A is zero and P is 15.
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring APEncode(const string& in) {
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string result;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result.reserve(in.size() * 2);
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (string::const_iterator i = in.begin(); i != in.end(); ++i) {
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    unsigned int c = static_cast<unsigned char>(*i);
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result.push_back((c & 0x0F) + 'A');
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result.push_back(((c >> 4) & 0x0F) + 'A');
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring APDecode(const string& in) {
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string result;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  result.reserve(in.size() / 2);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (string::const_iterator i = in.begin(); i != in.end(); ++i) {
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    unsigned int c = *i - 'A';
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (++i != in.end())
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      c = c | (static_cast<unsigned char>(*i - 'A') << 4);
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result.push_back(c);
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const char PASSWORD_HASH[] = "password_hash2";
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const char SALT[] = "salt2";
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kSaltSize = 20;
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kCurrentDBVersion = 12;
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochUserSettings::ScopedDBHandle::ScopedDBHandle(UserSettings* settings)
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : mutex_lock_(settings->dbhandle_mutex_), handle_(&settings->dbhandle_) {
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochUserSettings::UserSettings() : dbhandle_(NULL) {
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring UserSettings::email() const {
8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::AutoLock lock(mutex_);
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return email_;
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void MakeSigninsTable(sqlite3* const dbhandle) {
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Multiple email addresses can map to the same Google Account. This table
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // keeps a map of sign-in email addresses to primary Google Account email
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // addresses.
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExecOrDie(dbhandle,
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            "CREATE TABLE signins"
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            " (signin, primary_email, "
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            " PRIMARY KEY(signin, primary_email) ON CONFLICT REPLACE)");
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UserSettings::MigrateOldVersionsAsNeeded(sqlite3* const handle,
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int current_version) {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  switch (current_version) {
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Versions 1-9 are unhandled.  Version numbers greater than
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // kCurrentDBVersion should have already been weeded out by the caller.
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default:
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // When the version is too old, we just try to continue anyway.  There
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // should not be a released product that makes a database too old for us
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // to handle.
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(WARNING) << "UserSettings database version " << current_version <<
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          " is too old to handle.";
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 10:
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // Scrape the 'shares' table to find the syncable DB.  'shares' had a
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // pair of string columns that mapped the username to the filename of
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // the sync data sqlite3 file.  Version 11 switched to a constant
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // filename, so here we read the string, copy the file to the new name,
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        // delete the old one, and then drop the unused shares table.
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SQLStatement share_query;
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        share_query.prepare(handle, "SELECT share_name, file_name FROM shares");
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        int query_result = share_query.step();
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        CHECK(SQLITE_ROW == query_result);
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        FilePath::StringType share_name, file_name;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_POSIX)
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        share_name = share_query.column_string(0);
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        file_name = share_query.column_string(1);
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#else
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        share_name = share_query.column_wstring(0);
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        file_name = share_query.column_wstring(1);
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        const FilePath& src_syncdata_path = FilePath(file_name);
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        FilePath dst_syncdata_path(src_syncdata_path.DirName());
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        file_util::AbsolutePath(&dst_syncdata_path);
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        dst_syncdata_path = dst_syncdata_path.Append(
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            DirectoryManager::GetSyncDataDatabaseFilename());
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!file_util::Move(src_syncdata_path, dst_syncdata_path)) {
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          LOG(WARNING) << "Unable to upgrade UserSettings from v10";
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ExecOrDie(handle, "DROP TABLE shares");
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ExecOrDie(handle, "UPDATE db_version SET version = 11");
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // FALL THROUGH
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case 11:
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ExecOrDie(handle, "DROP TABLE signin_types");
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ExecOrDie(handle, "UPDATE db_version SET version = 12");
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // FALL THROUGH
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    case kCurrentDBVersion:
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Nothing to migrate.
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void MakeCookiesTable(sqlite3* const dbhandle) {
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This table keeps a list of auth tokens for each signed in account. There
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // will be as many rows as there are auth tokens per sign in.
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The service_token column will store encrypted values.
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExecOrDie(dbhandle,
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            "CREATE TABLE cookies"
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            " (email, service_name, service_token, "
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            " PRIMARY KEY(email, service_name) ON CONFLICT REPLACE)");
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void MakeClientIDTable(sqlite3* const dbhandle) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Stores a single client ID value that can be used as the client id, if
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // there's not another such ID provided on the install.
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExecOrDie(dbhandle, "CREATE TABLE client_id (id) ");
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SQLStatement statement;
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.prepare(dbhandle,
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      "INSERT INTO client_id values ( ? )");
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.bind_string(0, Generate128BitRandomHexString());
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (SQLITE_DONE != statement.step()) {
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(FATAL) << "INSERT INTO client_id\n" << sqlite3_errmsg(dbhandle);
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UserSettings::Init(const FilePath& settings_path) {
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {  // Scope the handle.
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ScopedDBHandle dbhandle(this);
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (dbhandle_)
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      sqlite3_close(dbhandle_);
1813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (SQLITE_OK != sqlite_utils::OpenSqliteDb(settings_path, &dbhandle_))
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return false;
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // In the worst case scenario, the user may hibernate his computer during
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // one of our transactions.
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sqlite3_busy_timeout(dbhandle_, numeric_limits<int>::max());
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExecOrDie(dbhandle.get(), "PRAGMA fullfsync = 1");
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ExecOrDie(dbhandle.get(), "PRAGMA synchronous = 2");
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SQLTransaction transaction(dbhandle.get());
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    transaction.BeginExclusive();
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SQLStatement table_query;
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    table_query.prepare(dbhandle.get(),
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        "select count(*) from sqlite_master"
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        " where type = 'table' and name = 'db_version'");
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int query_result = table_query.step();
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    CHECK(SQLITE_ROW == query_result);
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int table_count = table_query.column_int(0);
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    table_query.reset();
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (table_count > 0) {
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQLStatement version_query;
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      version_query.prepare(dbhandle.get(),
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                            "SELECT version FROM db_version");
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      query_result = version_query.step();
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      CHECK(SQLITE_ROW == query_result);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      const int version = version_query.column_int(0);
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      version_query.reset();
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (version > kCurrentDBVersion) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(WARNING) << "UserSettings database is too new.";
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        return false;
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MigrateOldVersionsAsNeeded(dbhandle.get(), version);
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Create settings table.
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      {
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SQLStatement statement;
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        statement.prepare(dbhandle.get(),
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          "CREATE TABLE settings"
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          " (email, key, value, "
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          "  PRIMARY KEY(email, key) ON CONFLICT REPLACE)");
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (SQLITE_DONE != statement.step()) {
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Create and populate version table.
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      {
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SQLStatement statement;
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        statement.prepare(dbhandle.get(),
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          "CREATE TABLE db_version ( version )");
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (SQLITE_DONE != statement.step()) {
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      {
237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        SQLStatement statement;
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        statement.prepare(dbhandle.get(),
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          "INSERT INTO db_version values ( ? )");
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        statement.bind_int(0, kCurrentDBVersion);
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (SQLITE_DONE != statement.step()) {
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          return false;
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MakeSigninsTable(dbhandle.get());
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MakeCookiesTable(dbhandle.get());
248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      MakeClientIDTable(dbhandle.get());
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    transaction.Commit();
251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN)
253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Do not index this file. Scanning can occur every time we close the file,
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // which causes long delays in SQLite's file locking.
255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const DWORD attrs = GetFileAttributes(settings_path.value().c_str());
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const BOOL attrs_set =
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SetFileAttributes(settings_path.value().c_str(),
258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      attrs | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif
260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochUserSettings::~UserSettings() {
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (dbhandle_)
265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    sqlite3_close(dbhandle_);
266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int32 kInvalidHash = 0xFFFFFFFF;
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// We use 10 bits of data from the MD5 digest as the hash.
271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int32 kHashMask = 0x3FF;
272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochint32 GetHashFromDigest(const vector<uint8>& digest) {
274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 hash = 0;
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 mask = kHashMask;
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (vector<uint8>::const_iterator i = digest.begin(); i != digest.end();
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++i) {
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hash = hash << 8;
279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    hash = hash | (*i & kHashMask);
280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    mask = mask >> 8;
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (0 == mask)
282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      break;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return hash;
285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UserSettings::StoreEmailForSignin(const string& signin,
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const string& primary_email) {
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDBHandle dbhandle(this);
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLTransaction transaction(dbhandle.get());
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int sqlite_result = transaction.BeginExclusive();
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(SQLITE_OK == sqlite_result);
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLStatement query;
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.prepare(dbhandle.get(),
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                "SELECT COUNT(*) FROM signins"
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                " WHERE signin = ? AND primary_email = ?");
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.bind_string(0, signin);
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.bind_string(1, primary_email);
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int query_result = query.step();
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(SQLITE_ROW == query_result);
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 count = query.column_int(0);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.reset();
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (0 == count) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Migrate any settings the user might have from earlier versions.
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    {
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQLStatement statement;
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      statement.prepare(dbhandle.get(),
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        "UPDATE settings SET email = ? WHERE email = ?");
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      statement.bind_string(0, signin);
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      statement.bind_string(1, primary_email);
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (SQLITE_DONE != statement.step()) {
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(FATAL) << sqlite3_errmsg(dbhandle.get());
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Store this signin:email mapping.
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    {
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SQLStatement statement;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      statement.prepare(dbhandle.get(),
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        "INSERT INTO signins(signin, primary_email)"
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                        " values ( ?, ? )");
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      statement.bind_string(0, signin);
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      statement.bind_string(1, primary_email);
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (SQLITE_DONE != statement.step()) {
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        LOG(FATAL) << sqlite3_errmsg(dbhandle.get());
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.Commit();
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// string* signin is both the input and the output of this function.
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UserSettings::GetEmailForSignin(string* signin) {
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDBHandle dbhandle(this);
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string result;
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLStatement query;
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.prepare(dbhandle.get(),
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                "SELECT primary_email FROM signins WHERE signin = ?");
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.bind_string(0, *signin);
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int query_result = query.step();
340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (SQLITE_ROW == query_result) {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    query.column_string(0, &result);
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!result.empty()) {
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      swap(result, *signin);
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return true;
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return false;
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UserSettings::StoreHashedPassword(const string& email,
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                       const string& password) {
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Save one-way hashed password:
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  char binary_salt[kSaltSize];
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetRandomBytes(binary_salt, sizeof(binary_salt));
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const string salt = APEncode(string(binary_salt, sizeof(binary_salt)));
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Calculator md5;
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  md5.AddData(salt.data(), salt.size());
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  md5.AddData(password.data(), password.size());
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDBHandle dbhandle(this);
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLTransaction transaction(dbhandle.get());
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.BeginExclusive();
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SQLStatement statement;
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.prepare(dbhandle.get(),
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      "INSERT INTO settings(email, key, value)"
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      " values ( ?, ?, ? )");
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.bind_string(0, email);
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.bind_string(1, PASSWORD_HASH);
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.bind_int(2, GetHashFromDigest(md5.GetDigest()));
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (SQLITE_DONE != statement.step()) {
372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(FATAL) << sqlite3_errmsg(dbhandle.get());
373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SQLStatement statement;
377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.prepare(dbhandle.get(),
378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      "INSERT INTO settings(email, key, value)"
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                      " values ( ?, ?, ? )");
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.bind_string(0, email);
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.bind_string(1, SALT);
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    statement.bind_string(2, salt);
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (SQLITE_DONE != statement.step()) {
384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      LOG(FATAL) << sqlite3_errmsg(dbhandle.get());
385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  transaction.Commit();
388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UserSettings::VerifyAgainstStoredHash(const string& email,
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                           const string& password) {
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDBHandle dbhandle(this);
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string salt_and_digest;
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLStatement query;
396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.prepare(dbhandle.get(),
397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                "SELECT key, value FROM settings"
398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                " WHERE email = ? AND (key = ? OR key = ?)");
399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.bind_string(0, email);
400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.bind_string(1, PASSWORD_HASH);
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.bind_string(2, SALT);
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int query_result = query.step();
403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string salt;
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int32 hash = kInvalidHash;
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  while (SQLITE_ROW == query_result) {
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    string key(query.column_string(0));
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (key == SALT)
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      salt = query.column_string(1);
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      hash = query.column_int(1);
411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    query_result = query.step();
412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  CHECK(SQLITE_DONE == query_result);
414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (salt.empty() || hash == kInvalidHash)
415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  MD5Calculator md5;
417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  md5.AddData(salt.data(), salt.size());
418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  md5.AddData(password.data(), password.size());
419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return hash == GetHashFromDigest(md5.GetDigest());
420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UserSettings::SwitchUser(const string& username) {
423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    base::AutoLock lock(mutex_);
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    email_ = username;
426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstring UserSettings::GetClientId() {
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDBHandle dbhandle(this);
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLStatement statement;
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  statement.prepare(dbhandle.get(), "SELECT id FROM client_id");
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int query_result = statement.step();
434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  string client_id;
435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (query_result == SQLITE_ROW)
436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    client_id = statement.column_string(0);
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return client_id;
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid UserSettings::ClearAllServiceTokens() {
441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDBHandle dbhandle(this);
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ExecOrDie(dbhandle.get(), "DELETE FROM cookies");
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool UserSettings::GetLastUser(string* username) {
446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ScopedDBHandle dbhandle(this);
447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SQLStatement query;
448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  query.prepare(dbhandle.get(), "SELECT email FROM cookies");
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (SQLITE_ROW == query.step()) {
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    *username = query.column_string(0);
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return true;
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return false;
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace browser_sync
458