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 "chrome/browser/extensions/api/passwords_private/passwords_private_api.h"
6
7 #include <memory>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/location.h"
12 #include "base/metrics/histogram_macros.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "base/values.h"
17 #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/sync/profile_sync_service_factory.h"
20 #include "chrome/common/extensions/api/passwords_private.h"
21 #include "components/password_manager/core/browser/manage_passwords_referrer.h"
22 #include "components/password_manager/core/browser/password_manager_util.h"
23 #include "components/sync/driver/sync_service.h"
24 #include "content/public/browser/web_contents.h"
25 #include "extensions/browser/extension_function_registry.h"
26
27 namespace extensions {
28
29 namespace {
30
31 using ResponseAction = ExtensionFunction::ResponseAction;
32
GetDelegate(content::BrowserContext * browser_context)33 PasswordsPrivateDelegate* GetDelegate(
34 content::BrowserContext* browser_context) {
35 return PasswordsPrivateDelegateFactory::GetForBrowserContext(browser_context,
36 /*create=*/true);
37 }
38
39 } // namespace
40
41 // PasswordsPrivateRecordPasswordsPageAccessInSettingsFunction
42 ResponseAction
Run()43 PasswordsPrivateRecordPasswordsPageAccessInSettingsFunction::Run() {
44 UMA_HISTOGRAM_ENUMERATION(
45 "PasswordManager.ManagePasswordsReferrer",
46 password_manager::ManagePasswordsReferrer::kChromeSettings);
47 return RespondNow(NoArguments());
48 }
49
50 // PasswordsPrivateChangeSavedPasswordFunction
Run()51 ResponseAction PasswordsPrivateChangeSavedPasswordFunction::Run() {
52 auto parameters =
53 api::passwords_private::ChangeSavedPassword::Params::Create(*args_);
54 EXTENSION_FUNCTION_VALIDATE(parameters);
55
56 if (!GetDelegate(browser_context())
57 ->ChangeSavedPassword(parameters->ids,
58 base::UTF8ToUTF16(parameters->new_username),
59 base::UTF8ToUTF16(parameters->new_password))) {
60 return RespondNow(Error(
61 "Could not change the password. Either the password is empty, the user "
62 "is not authenticated, vector of ids is empty or no matching password "
63 "could be found at least for one of the ids."));
64 }
65
66 return RespondNow(NoArguments());
67 }
68
69 // PasswordsPrivateRemoveSavedPasswordFunction
Run()70 ResponseAction PasswordsPrivateRemoveSavedPasswordFunction::Run() {
71 auto parameters =
72 api::passwords_private::RemoveSavedPassword::Params::Create(*args_);
73 EXTENSION_FUNCTION_VALIDATE(parameters);
74 GetDelegate(browser_context())->RemoveSavedPasswords({parameters->id});
75 return RespondNow(NoArguments());
76 }
77
78 // PasswordsPrivateRemoveSavedPasswordsFunction
Run()79 ResponseAction PasswordsPrivateRemoveSavedPasswordsFunction::Run() {
80 auto parameters =
81 api::passwords_private::RemoveSavedPasswords::Params::Create(*args_);
82 EXTENSION_FUNCTION_VALIDATE(parameters);
83 GetDelegate(browser_context())->RemoveSavedPasswords(parameters->ids);
84 return RespondNow(NoArguments());
85 }
86
87 // PasswordsPrivateRemovePasswordExceptionFunction
Run()88 ResponseAction PasswordsPrivateRemovePasswordExceptionFunction::Run() {
89 auto parameters =
90 api::passwords_private::RemovePasswordException::Params::Create(*args_);
91 EXTENSION_FUNCTION_VALIDATE(parameters);
92 GetDelegate(browser_context())->RemovePasswordExceptions({parameters->id});
93 return RespondNow(NoArguments());
94 }
95
96 // PasswordsPrivateRemovePasswordExceptionsFunction
Run()97 ResponseAction PasswordsPrivateRemovePasswordExceptionsFunction::Run() {
98 auto parameters =
99 api::passwords_private::RemovePasswordExceptions::Params::Create(*args_);
100 EXTENSION_FUNCTION_VALIDATE(parameters);
101 GetDelegate(browser_context())->RemovePasswordExceptions(parameters->ids);
102 return RespondNow(NoArguments());
103 }
104
105 // PasswordsPrivateUndoRemoveSavedPasswordOrExceptionFunction
106 ResponseAction
Run()107 PasswordsPrivateUndoRemoveSavedPasswordOrExceptionFunction::Run() {
108 GetDelegate(browser_context())->UndoRemoveSavedPasswordOrException();
109 return RespondNow(NoArguments());
110 }
111
112 // PasswordsPrivateRequestPlaintextPasswordFunction
Run()113 ResponseAction PasswordsPrivateRequestPlaintextPasswordFunction::Run() {
114 auto parameters =
115 api::passwords_private::RequestPlaintextPassword::Params::Create(*args_);
116 EXTENSION_FUNCTION_VALIDATE(parameters);
117
118 GetDelegate(browser_context())
119 ->RequestPlaintextPassword(
120 parameters->id, parameters->reason,
121 base::BindOnce(
122 &PasswordsPrivateRequestPlaintextPasswordFunction::GotPassword,
123 this),
124 GetSenderWebContents());
125
126 // GotPassword() might respond before we reach this point.
127 return did_respond() ? AlreadyResponded() : RespondLater();
128 }
129
GotPassword(base::Optional<base::string16> password)130 void PasswordsPrivateRequestPlaintextPasswordFunction::GotPassword(
131 base::Optional<base::string16> password) {
132 if (password) {
133 Respond(OneArgument(base::Value(std::move(*password))));
134 return;
135 }
136
137 Respond(Error(base::StringPrintf(
138 "Could not obtain plaintext password. Either the user is not "
139 "authenticated or no password with id = %d could be found.",
140 api::passwords_private::RequestPlaintextPassword::Params::Create(*args_)
141 ->id)));
142 }
143
144 // PasswordsPrivateGetSavedPasswordListFunction
Run()145 ResponseAction PasswordsPrivateGetSavedPasswordListFunction::Run() {
146 // GetList() can immediately call GotList() (which would Respond() before
147 // RespondLater()). So we post a task to preserve order.
148 base::ThreadTaskRunnerHandle::Get()->PostTask(
149 FROM_HERE,
150 base::BindOnce(&PasswordsPrivateGetSavedPasswordListFunction::GetList,
151 this));
152 return RespondLater();
153 }
154
GetList()155 void PasswordsPrivateGetSavedPasswordListFunction::GetList() {
156 GetDelegate(browser_context())
157 ->GetSavedPasswordsList(base::BindOnce(
158 &PasswordsPrivateGetSavedPasswordListFunction::GotList, this));
159 }
160
GotList(const PasswordsPrivateDelegate::UiEntries & list)161 void PasswordsPrivateGetSavedPasswordListFunction::GotList(
162 const PasswordsPrivateDelegate::UiEntries& list) {
163 Respond(ArgumentList(
164 api::passwords_private::GetSavedPasswordList::Results::Create(list)));
165 }
166
167 // PasswordsPrivateGetPasswordExceptionListFunction
Run()168 ResponseAction PasswordsPrivateGetPasswordExceptionListFunction::Run() {
169 // GetList() can immediately call GotList() (which would Respond() before
170 // RespondLater()). So we post a task to preserve order.
171 base::ThreadTaskRunnerHandle::Get()->PostTask(
172 FROM_HERE,
173 base::BindOnce(&PasswordsPrivateGetPasswordExceptionListFunction::GetList,
174 this));
175 return RespondLater();
176 }
177
GetList()178 void PasswordsPrivateGetPasswordExceptionListFunction::GetList() {
179 GetDelegate(browser_context())
180 ->GetPasswordExceptionsList(base::BindOnce(
181 &PasswordsPrivateGetPasswordExceptionListFunction::GotList, this));
182 }
183
GotList(const PasswordsPrivateDelegate::ExceptionEntries & entries)184 void PasswordsPrivateGetPasswordExceptionListFunction::GotList(
185 const PasswordsPrivateDelegate::ExceptionEntries& entries) {
186 Respond(ArgumentList(
187 api::passwords_private::GetPasswordExceptionList::Results::Create(
188 entries)));
189 }
190
191 // PasswordsPrivateMovePasswordToAccountFunction
Run()192 ResponseAction PasswordsPrivateMovePasswordsToAccountFunction::Run() {
193 auto parameters =
194 api::passwords_private::MovePasswordsToAccount::Params::Create(*args_);
195 EXTENSION_FUNCTION_VALIDATE(parameters);
196 GetDelegate(browser_context())
197 ->MovePasswordsToAccount(parameters->ids, GetSenderWebContents());
198 return RespondNow(NoArguments());
199 }
200
201 // PasswordsPrivateImportPasswordsFunction
Run()202 ResponseAction PasswordsPrivateImportPasswordsFunction::Run() {
203 GetDelegate(browser_context())->ImportPasswords(GetSenderWebContents());
204 return RespondNow(NoArguments());
205 }
206
207 // PasswordsPrivateExportPasswordsFunction
Run()208 ResponseAction PasswordsPrivateExportPasswordsFunction::Run() {
209 GetDelegate(browser_context())
210 ->ExportPasswords(
211 base::BindOnce(
212 &PasswordsPrivateExportPasswordsFunction::ExportRequestCompleted,
213 this),
214 GetSenderWebContents());
215 return RespondLater();
216 }
217
ExportRequestCompleted(const std::string & error)218 void PasswordsPrivateExportPasswordsFunction::ExportRequestCompleted(
219 const std::string& error) {
220 if (error.empty())
221 Respond(NoArguments());
222 else
223 Error(error);
224 }
225
226 // PasswordsPrivateCancelExportPasswordsFunction
Run()227 ResponseAction PasswordsPrivateCancelExportPasswordsFunction::Run() {
228 GetDelegate(browser_context())->CancelExportPasswords();
229 return RespondNow(NoArguments());
230 }
231
232 // PasswordsPrivateRequestExportProgressStatusFunction
Run()233 ResponseAction PasswordsPrivateRequestExportProgressStatusFunction::Run() {
234 return RespondNow(ArgumentList(
235 api::passwords_private::RequestExportProgressStatus::Results::Create(
236 GetDelegate(browser_context())->GetExportProgressStatus())));
237 }
238
239 // PasswordsPrivateIsOptedInForAccountStorageFunction
Run()240 ResponseAction PasswordsPrivateIsOptedInForAccountStorageFunction::Run() {
241 return RespondNow(OneArgument(base::Value(
242 GetDelegate(browser_context())->IsOptedInForAccountStorage())));
243 }
244
245 // PasswordsPrivateOptInForAccountStorageFunction
Run()246 ResponseAction PasswordsPrivateOptInForAccountStorageFunction::Run() {
247 auto parameters =
248 api::passwords_private::OptInForAccountStorage::Params::Create(*args_);
249 EXTENSION_FUNCTION_VALIDATE(parameters.get());
250
251 GetDelegate(browser_context())
252 ->SetAccountStorageOptIn(parameters->opt_in, GetSenderWebContents());
253 return RespondNow(NoArguments());
254 }
255
256 // PasswordsPrivateGetCompromisedCredentialsFunction:
257 PasswordsPrivateGetCompromisedCredentialsFunction::
258 ~PasswordsPrivateGetCompromisedCredentialsFunction() = default;
259
Run()260 ResponseAction PasswordsPrivateGetCompromisedCredentialsFunction::Run() {
261 return RespondNow(ArgumentList(
262 api::passwords_private::GetCompromisedCredentials::Results::Create(
263 GetDelegate(browser_context())->GetCompromisedCredentials())));
264 }
265
266 // PasswordsPrivateGetWeakCredentialsFunction:
267 PasswordsPrivateGetWeakCredentialsFunction::
268 ~PasswordsPrivateGetWeakCredentialsFunction() = default;
269
Run()270 ResponseAction PasswordsPrivateGetWeakCredentialsFunction::Run() {
271 return RespondNow(
272 ArgumentList(api::passwords_private::GetWeakCredentials::Results::Create(
273 GetDelegate(browser_context())->GetWeakCredentials())));
274 }
275
276 // PasswordsPrivateGetPlaintextInsecurePasswordFunction:
277 PasswordsPrivateGetPlaintextInsecurePasswordFunction::
278 ~PasswordsPrivateGetPlaintextInsecurePasswordFunction() = default;
279
Run()280 ResponseAction PasswordsPrivateGetPlaintextInsecurePasswordFunction::Run() {
281 auto parameters =
282 api::passwords_private::GetPlaintextInsecurePassword::Params::Create(
283 *args_);
284 EXTENSION_FUNCTION_VALIDATE(parameters);
285
286 GetDelegate(browser_context())
287 ->GetPlaintextInsecurePassword(
288 std::move(parameters->credential), parameters->reason,
289 GetSenderWebContents(),
290 base::BindOnce(&PasswordsPrivateGetPlaintextInsecurePasswordFunction::
291 GotCredential,
292 this));
293
294 // GotCredential() might respond before we reach this point.
295 return did_respond() ? AlreadyResponded() : RespondLater();
296 }
297
GotCredential(base::Optional<api::passwords_private::InsecureCredential> credential)298 void PasswordsPrivateGetPlaintextInsecurePasswordFunction::GotCredential(
299 base::Optional<api::passwords_private::InsecureCredential> credential) {
300 if (!credential) {
301 Respond(
302 Error("Could not obtain plaintext insecure password. Either the user "
303 "is not authenticated or no matching password could be found."));
304 return;
305 }
306
307 Respond(ArgumentList(
308 api::passwords_private::GetPlaintextInsecurePassword::Results::Create(
309 *credential)));
310 }
311
312 // PasswordsPrivateChangeInsecureCredentialFunction:
313 PasswordsPrivateChangeInsecureCredentialFunction::
314 ~PasswordsPrivateChangeInsecureCredentialFunction() = default;
315
Run()316 ResponseAction PasswordsPrivateChangeInsecureCredentialFunction::Run() {
317 auto parameters =
318 api::passwords_private::ChangeInsecureCredential::Params::Create(*args_);
319 EXTENSION_FUNCTION_VALIDATE(parameters);
320
321 if (parameters->new_password.empty()) {
322 return RespondNow(
323 Error("Could not change the insecure credential. The new password "
324 "can't be empty."));
325 }
326
327 if (!GetDelegate(browser_context())
328 ->ChangeInsecureCredential(parameters->credential,
329 parameters->new_password)) {
330 return RespondNow(Error(
331 "Could not change the insecure credential. Either the user is not "
332 "authenticated or no matching password could be found."));
333 }
334
335 return RespondNow(NoArguments());
336 }
337
338 // PasswordsPrivateRemoveInsecureCredentialFunction:
339 PasswordsPrivateRemoveInsecureCredentialFunction::
340 ~PasswordsPrivateRemoveInsecureCredentialFunction() = default;
341
Run()342 ResponseAction PasswordsPrivateRemoveInsecureCredentialFunction::Run() {
343 auto parameters =
344 api::passwords_private::RemoveInsecureCredential::Params::Create(*args_);
345 EXTENSION_FUNCTION_VALIDATE(parameters);
346
347 if (!GetDelegate(browser_context())
348 ->RemoveInsecureCredential(parameters->credential)) {
349 return RespondNow(
350 Error("Could not remove the insecure credential. Probably no matching "
351 "password could be found."));
352 }
353
354 return RespondNow(NoArguments());
355 }
356
357 // PasswordsPrivateStartPasswordCheckFunction:
358 PasswordsPrivateStartPasswordCheckFunction::
359 ~PasswordsPrivateStartPasswordCheckFunction() = default;
360
Run()361 ResponseAction PasswordsPrivateStartPasswordCheckFunction::Run() {
362 GetDelegate(browser_context())
363 ->StartPasswordCheck(base::BindOnce(
364 &PasswordsPrivateStartPasswordCheckFunction::OnStarted, this));
365
366 // OnStarted() might respond before we reach this point.
367 return did_respond() ? AlreadyResponded() : RespondLater();
368 }
369
OnStarted(password_manager::BulkLeakCheckService::State state)370 void PasswordsPrivateStartPasswordCheckFunction::OnStarted(
371 password_manager::BulkLeakCheckService::State state) {
372 const bool is_running =
373 state == password_manager::BulkLeakCheckService::State::kRunning;
374 Respond(is_running ? NoArguments()
375 : Error("Starting password check failed."));
376 }
377
378 // PasswordsPrivateStopPasswordCheckFunction:
379 PasswordsPrivateStopPasswordCheckFunction::
380 ~PasswordsPrivateStopPasswordCheckFunction() = default;
381
Run()382 ResponseAction PasswordsPrivateStopPasswordCheckFunction::Run() {
383 GetDelegate(browser_context())->StopPasswordCheck();
384 return RespondNow(NoArguments());
385 }
386
387 // PasswordsPrivateGetPasswordCheckStatusFunction:
388 PasswordsPrivateGetPasswordCheckStatusFunction::
389 ~PasswordsPrivateGetPasswordCheckStatusFunction() = default;
390
Run()391 ResponseAction PasswordsPrivateGetPasswordCheckStatusFunction::Run() {
392 return RespondNow(ArgumentList(
393 api::passwords_private::GetPasswordCheckStatus::Results::Create(
394 GetDelegate(browser_context())->GetPasswordCheckStatus())));
395 }
396
397 } // namespace extensions
398