OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "services/authentication/accounts_db_manager.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/strings/string_tokenizer.h" | |
11 #include "mojo/public/cpp/bindings/array.h" | |
12 #include "mojo/public/cpp/bindings/type_converter.h" | |
13 #include "mojo/services/files/interfaces/files.mojom.h" | |
14 #include "services/authentication/authentication_impl_db.mojom.h" | |
15 | |
16 namespace authentication { | |
17 | |
18 char kAccountsDbFileName[] = "creds_db"; | |
19 char kAuthDbFileName[] = "auth_db"; | |
20 const uint32 kAuthDbVersion = 1; | |
21 | |
22 AccountsDbManager::AccountsDbManager() | |
23 : creds_db_file_(nullptr), auth_db_file_(nullptr), contents_(nullptr) {} | |
24 | |
25 AccountsDbManager::AccountsDbManager( | |
26 const mojo::files::DirectoryPtr directory) { | |
27 // Initialize in-memory contents from existing DB file | |
28 directory->OpenFile( | |
29 kAccountsDbFileName, GetProxy(&creds_db_file_), | |
30 mojo::files::kOpenFlagCreate | mojo::files::kOpenFlagRead | | |
31 mojo::files::kOpenFlagWrite, | |
32 [this](mojo::files::Error error) { | |
33 if (mojo::files::Error::OK != error) { | |
34 LOG(ERROR) << "Open() error on credentials db:" << error; | |
35 delete this; | |
36 return; | |
37 } | |
38 }); | |
39 directory->OpenFile(kAuthDbFileName, GetProxy(&auth_db_file_), | |
40 mojo::files::kOpenFlagCreate | | |
41 mojo::files::kOpenFlagRead | | |
42 mojo::files::kOpenFlagWrite, | |
43 [this](mojo::files::Error error) { | |
44 if (mojo::files::Error::OK != error) { | |
45 LOG(ERROR) << "Open() error on auth db:" << error; | |
46 delete this; | |
47 return; | |
48 } | |
49 }); | |
50 Initialize(); | |
51 } | |
52 | |
53 AccountsDbManager::~AccountsDbManager() {} | |
54 | |
55 mojo::String AccountsDbManager::GetUpdatedDbContents( | |
56 const mojo::String& username, | |
57 const mojo::String& new_account_data, | |
58 bool user_exists) { | |
59 if (username.is_null() || new_account_data.is_null()) { | |
60 return nullptr; | |
61 } | |
62 std::string buffer; | |
63 if (user_exists) { | |
64 // Remove existing user record | |
65 base::StringTokenizer lines(contents_, "\n"); | |
66 std::string user_record; | |
67 while (lines.GetNext()) { | |
qsr
2016/02/16 14:17:06
Please comment that you are removing the entry for
ukode
2016/02/26 21:35:49
Had the same comment two lines above. Moved it dow
| |
68 user_record = lines.token(); | |
69 std::size_t pos = user_record.find(username.get() + ","); | |
70 if ((pos == std::string::npos) || (pos != 0)) { | |
qsr
2016/02/16 14:17:06
std::string::npos will not be 0, so pos != 0 is en
ukode
2016/02/26 21:35:49
Acknowledged.
| |
71 buffer += user_record; | |
72 buffer += "\n"; | |
73 } | |
74 } | |
75 } else { | |
76 if (!contents_.empty()) { // first account | |
77 buffer += "\n"; | |
78 } | |
79 } | |
80 buffer += new_account_data; | |
81 return mojo::String(buffer); | |
82 } | |
83 | |
84 void AccountsDbManager::UpdateAccount(const mojo::String& username, | |
85 const mojo::String& new_account_data) { | |
86 if (username.is_null() || new_account_data.is_null()) { | |
87 return; | |
88 } | |
89 bool user_exists = !GetAccountDataForUser(username).is_null(); | |
qsr
2016/02/16 14:17:06
This is parsing the string.
ukode
2016/02/26 21:35:49
Acknowledged.
| |
90 | |
91 mojo::String new_db_contents = | |
92 GetUpdatedDbContents(username, new_account_data, user_exists); | |
qsr
2016/02/16 14:17:06
And this is doing it again.
Any reason the in-mem
ukode
2016/02/26 21:35:49
Got rid of this extra parsing completely,and direc
| |
93 if (new_db_contents.is_null()) { | |
94 return; | |
95 } | |
96 | |
97 // Update contents cache with new data | |
98 if (user_exists) { | |
99 contents_.assign(new_db_contents.data(), new_db_contents.size()); | |
100 } else { | |
101 contents_ += new_db_contents; | |
102 } | |
103 | |
104 // Write updated contents to file | |
105 std::vector<uint8_t> bytes_to_write(new_db_contents.get().begin(), | |
106 new_db_contents.get().end()); | |
107 bytes_to_write.push_back('\0'); | |
108 mojo::files::Whence whence; | |
109 if (user_exists) { | |
110 whence = mojo::files::Whence::FROM_START; | |
111 } else { | |
112 whence = mojo::files::Whence::FROM_CURRENT; | |
113 } | |
114 creds_db_file_->Write( | |
115 mojo::Array<uint8_t>::From(bytes_to_write), 0, whence, | |
116 [this](mojo::files::Error error, uint32_t num_bytes_written) { | |
117 this->OnWriteResponse(error, num_bytes_written); | |
118 }); | |
119 } | |
120 | |
121 void AccountsDbManager::OnWriteResponse(const mojo::files::Error error, | |
122 const uint32_t num_bytes_written) { | |
123 if (mojo::files::Error::OK != error) { | |
124 LOG(ERROR) << "Write() error on accounts db:" << error; | |
125 delete this; | |
qsr
2016/02/16 14:17:06
Return after the delete. Doesn't matter that much
ukode
2016/02/26 21:35:49
Done.
| |
126 } | |
127 return; | |
128 } | |
129 | |
130 mojo::String AccountsDbManager::GetAccountDataForUser( | |
131 const mojo::String& username) { | |
132 if (username.is_null() || contents_.empty()) { | |
133 return nullptr; | |
134 } | |
135 | |
136 base::StringTokenizer lines(contents_, "\n"); | |
137 std::string entry; | |
138 while (lines.GetNext()) { | |
139 entry = lines.token(); | |
140 std::size_t pos = entry.find(username.get() + ","); | |
141 if ((pos != std::string::npos) && (pos == 0)) { | |
142 return mojo::String(entry); | |
143 } | |
144 } | |
145 return nullptr; | |
146 } | |
147 | |
148 mojo::String AccountsDbManager::GetAllUserAccounts() { | |
149 return mojo::String(contents_); | |
150 } | |
151 | |
152 void AccountsDbManager::Initialize() { | |
153 auth_grants.version = kAuthDbVersion; | |
154 | |
155 const size_t kMaxReadSize = 1 * 1024 * 1024; | |
156 mojo::Array<uint8_t> cred_bytes_read; | |
157 creds_db_file_->Read( | |
qsr
2016/02/16 14:17:06
Don't you have a race in this class? What happen i
ukode
2016/02/26 21:35:49
The async reads happen very quickly and have enoug
| |
158 kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, | |
159 [this](mojo::files::Error error, mojo::Array<uint8_t> cred_bytes_read) { | |
160 this->OnReadResponse(error, cred_bytes_read.Pass()); | |
161 }); | |
162 | |
163 mojo::Array<uint8_t> auth_bytes_read; | |
164 auth_db_file_->Read( | |
165 kMaxReadSize - 1, 0, mojo::files::Whence::FROM_START, | |
166 [this](mojo::files::Error error, mojo::Array<uint8_t> auth_bytes_read) { | |
167 this->OnAuthFileReadResponse(error, auth_bytes_read.Pass()); | |
168 }); | |
169 } | |
170 | |
171 void AccountsDbManager::OnReadResponse(const mojo::files::Error error, | |
qsr
2016/02/16 14:17:06
Maybe rename this. Response is not that clear when
ukode
2016/02/26 21:35:49
Acknowledged.
| |
172 const mojo::Array<uint8_t> bytes_read) { | |
173 if (error != mojo::files::Error::OK) { | |
174 LOG(ERROR) << "Read() error on accounts db: " << error; | |
175 delete this; | |
176 return; | |
177 } | |
178 | |
179 if (bytes_read.size() != 0) { | |
180 contents_.assign(reinterpret_cast<const char*>(&bytes_read[0]), | |
181 bytes_read.size()); | |
182 } | |
183 } | |
184 | |
185 void AccountsDbManager::OnAuthFileReadResponse( | |
186 const mojo::files::Error error, | |
187 const mojo::Array<uint8_t> bytes_read) { | |
188 if (error != mojo::files::Error::OK) { | |
189 LOG(ERROR) << "Read() error on auth db: " << error; | |
190 delete this; | |
191 return; | |
192 } | |
193 | |
194 if (bytes_read.size() != 0) { | |
195 // Deserialize data from file | |
196 const char* p = reinterpret_cast<const char*>(&bytes_read[0]); | |
qsr
2016/02/16 14:17:06
s/p/data/g?
ukode
2016/02/26 21:35:49
Done.
| |
197 auth_grants.Deserialize((void*)p); | |
198 CHECK_EQ(auth_grants.version, kAuthDbVersion); | |
199 CHECK(!auth_grants.last_selected_accounts.is_null()); | |
200 } | |
201 } | |
202 | |
203 mojo::String AccountsDbManager::GetAuthorizedUserForApp(mojo::String app_url) { | |
204 if (app_url.is_null()) { | |
205 return nullptr; | |
206 } | |
207 auto it = auth_grants.last_selected_accounts.find(app_url); | |
208 if (it == auth_grants.last_selected_accounts.end()) { | |
209 return nullptr; | |
210 } | |
211 return mojo::String(it.GetValue()); | |
212 } | |
213 | |
214 void AccountsDbManager::UpdateAuthorization(mojo::String app_url, | |
215 mojo::String username) { | |
216 if (app_url.is_null() || username.is_null()) { | |
217 return; | |
218 } | |
219 auth_grants.last_selected_accounts[app_url] = username; | |
220 | |
221 size_t buf_size = auth_grants.GetSerializedSize(); | |
222 char buf[buf_size]; | |
223 MOJO_CHECK(auth_grants.Serialize(buf, buf_size)); | |
224 | |
225 std::vector<uint8_t> bytes_to_write(buf, buf + buf_size); | |
226 bytes_to_write.push_back('\0'); | |
qsr
2016/02/16 14:17:06
Why this?
ukode
2016/02/26 21:35:49
The very first version of files service needed thi
| |
227 mojo::files::Whence whence; | |
228 whence = mojo::files::Whence::FROM_START; | |
229 | |
230 auth_db_file_->Write( | |
231 mojo::Array<uint8_t>::From(bytes_to_write), 0, whence, | |
232 [this](mojo::files::Error error, uint32_t num_bytes_written) { | |
233 this->OnAuthFileWriteResponse(error, num_bytes_written); | |
234 }); | |
235 } | |
236 | |
237 void AccountsDbManager::OnAuthFileWriteResponse( | |
238 const mojo::files::Error error, | |
239 const uint32_t num_bytes_written) { | |
240 if (mojo::files::Error::OK != error) { | |
241 LOG(ERROR) << "Write() error on auth db:" << error; | |
242 delete this; | |
243 } | |
244 return; | |
245 } | |
246 | |
247 } // namespace authentication | |
OLD | NEW |