1// Copyright 2014 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 "components/signin/core/browser/webdata/token_service_table.h"
6
7#include <map>
8#include <string>
9
10#include "base/logging.h"
11#include "components/os_crypt/os_crypt.h"
12#include "components/webdata/common/web_database.h"
13#include "sql/statement.h"
14
15namespace {
16
17WebDatabaseTable::TypeKey GetKey() {
18  // We just need a unique constant. Use the address of a static that
19  // COMDAT folding won't touch in an optimizing linker.
20  static int table_key = 0;
21  return reinterpret_cast<void*>(&table_key);
22}
23
24}  // namespace
25
26TokenServiceTable* TokenServiceTable::FromWebDatabase(WebDatabase* db) {
27  return static_cast<TokenServiceTable*>(db->GetTable(GetKey()));
28
29}
30
31WebDatabaseTable::TypeKey TokenServiceTable::GetTypeKey() const {
32  return GetKey();
33}
34
35bool TokenServiceTable::CreateTablesIfNecessary() {
36  if (!db_->DoesTableExist("token_service")) {
37    if (!db_->Execute("CREATE TABLE token_service ("
38                      "service VARCHAR PRIMARY KEY NOT NULL,"
39                      "encrypted_token BLOB)")) {
40      NOTREACHED();
41      return false;
42    }
43  }
44  return true;
45}
46
47bool TokenServiceTable::IsSyncable() {
48  return true;
49}
50
51bool TokenServiceTable::MigrateToVersion(int version,
52                                         bool* update_compatible_version) {
53  return true;
54}
55
56bool TokenServiceTable::RemoveAllTokens() {
57  sql::Statement s(db_->GetUniqueStatement(
58      "DELETE FROM token_service"));
59
60  return s.Run();
61}
62
63bool TokenServiceTable::RemoveTokenForService(const std::string& service) {
64  sql::Statement s(db_->GetUniqueStatement(
65      "DELETE FROM token_service WHERE service = ?"));
66  s.BindString(0, service);
67
68  return s.Run();
69}
70
71bool TokenServiceTable::SetTokenForService(const std::string& service,
72                                           const std::string& token) {
73  std::string encrypted_token;
74  bool encrypted = OSCrypt::EncryptString(token, &encrypted_token);
75  if (!encrypted) {
76    return false;
77  }
78
79  // Don't bother with a cached statement since this will be a relatively
80  // infrequent operation.
81  sql::Statement s(db_->GetUniqueStatement(
82      "INSERT OR REPLACE INTO token_service "
83      "(service, encrypted_token) VALUES (?, ?)"));
84  s.BindString(0, service);
85  s.BindBlob(1, encrypted_token.data(),
86             static_cast<int>(encrypted_token.length()));
87
88  return s.Run();
89}
90
91bool TokenServiceTable::GetAllTokens(
92    std::map<std::string, std::string>* tokens) {
93  sql::Statement s(db_->GetUniqueStatement(
94      "SELECT service, encrypted_token FROM token_service"));
95
96  if (!s.is_valid())
97    return false;
98
99  while (s.Step()) {
100    std::string encrypted_token;
101    std::string decrypted_token;
102    std::string service;
103    service = s.ColumnString(0);
104    bool entry_ok = !service.empty() &&
105                    s.ColumnBlobAsString(1, &encrypted_token);
106    if (entry_ok) {
107      OSCrypt::DecryptString(encrypted_token, &decrypted_token);
108      (*tokens)[service] = decrypted_token;
109    } else {
110      NOTREACHED();
111      return false;
112    }
113  }
114  return true;
115}
116