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