1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Pierre Phaneuf <pp@ludusdesign.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
40 #include "nsWalletService.h"
41 #include "nsIServiceManager.h"
44 #include "nsPassword.h"
45 #include "nsIObserverService.h"
46 #include "nsIDOMHTMLDocument.h"
47 #include "nsIDOMHTMLCollection.h"
48 #include "nsIDOMHTMLFormElement.h"
49 #include "nsIDocument.h"
50 #include "nsCURILoader.h"
51 #include "nsIDOMHTMLInputElement.h"
52 #include "nsIFormControl.h"
53 #include "nsIDocShell.h"
54 #include "nsPIDOMWindow.h"
55 #include "nsIPrompt.h"
56 #include "nsIChannel.h"
57 #include "nsIWindowWatcher.h"
58 #include "nsIWebProgress.h"
59 #include "nsXPIDLString.h"
60 #include "nsUnicharUtils.h"
61 #include "nsReadableUtils.h"
62 #include "nsICategoryManager.h"
63 #include "nsNetUtil.h"
64 #include "nsEmbedCID.h"
66 // for making the leap from nsIDOMWindowInternal -> nsIPresShell
68 static NS_DEFINE_IID(kDocLoaderServiceCID
, NS_DOCUMENTLOADER_SERVICE_CID
);
71 ////////////////////////////////////////////////////////////////////////////////
74 nsWalletlibService::nsWalletlibService()
78 nsWalletlibService::~nsWalletlibService()
81 printf("Wallet Service destroyed successfully.\n");
83 Wallet_ReleaseAllLists();
87 NS_IMPL_THREADSAFE_ISUPPORTS6(nsWalletlibService
,
90 nsIFormSubmitObserver
,
91 nsIWebProgressListener
,
93 nsISupportsWeakReference
)
95 NS_IMETHODIMP
nsWalletlibService::WALLET_PreEdit(nsAString
& walletList
) {
96 ::WLLT_PreEdit(walletList
);
100 NS_IMETHODIMP
nsWalletlibService::WALLET_PostEdit(const nsAString
& walletList
) {
101 ::WLLT_PostEdit(walletList
);
105 NS_IMETHODIMP
nsWalletlibService::WALLET_ChangePassword(PRBool
* status
) {
106 ::WLLT_ChangePassword(status
);
110 NS_IMETHODIMP
nsWalletlibService::WALLET_DeleteAll() {
116 nsWalletlibService::WALLET_RequestToCapture(nsIDOMWindowInternal
* aWin
,
120 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(aWin
));
121 nsIDocShell
*docShell
= window
->GetDocShell();
123 nsCOMPtr
<nsIPresShell
> presShell
;
125 docShell
->GetPresShell(getter_AddRefs(presShell
));
127 ::WLLT_RequestToCapture(presShell
, aWin
, status
);
132 nsWalletlibService::WALLET_PrefillOneElement
133 (nsIDOMWindowInternal
* aWin
, nsIDOMNode
* elementNode
, PRUnichar
**value
)
135 nsAutoString compositeValue
;
136 nsresult rv
= ::WLLT_PrefillOneElement(aWin
, elementNode
, compositeValue
);
137 *value
= ToNewUnicode(compositeValue
);
142 nsWalletlibService::WALLET_Prefill(PRBool quick
,
143 nsIDOMWindowInternal
* aWin
,
146 nsCOMPtr
<nsPIDOMWindow
> window(do_QueryInterface(aWin
));
147 nsIDocShell
*docShell
= window
->GetDocShell();
149 nsCOMPtr
<nsIPresShell
> presShell
;
151 docShell
->GetPresShell(getter_AddRefs(presShell
));
153 return ::WLLT_Prefill(presShell
, quick
, aWin
);
156 NS_IMETHODIMP
nsWalletlibService::WALLET_PrefillReturn(const nsAString
& results
){
157 ::WLLT_PrefillReturn(results
);
161 NS_IMETHODIMP
nsWalletlibService::WALLET_ExpirePassword(PRBool
* status
){
162 ::WLLT_ExpirePassword(status
);
166 NS_IMETHODIMP
nsWalletlibService::WALLET_InitReencryptCallback(nsIDOMWindowInternal
* window
){
167 /* register callback to be used when encryption pref changes */
168 ::WLLT_InitReencryptCallback(window
);
172 NS_IMETHODIMP
nsWalletlibService::WALLET_GetNopreviewListForViewer(nsAString
& aNopreviewList
){
173 ::WLLT_GetNopreviewListForViewer(aNopreviewList
);
177 NS_IMETHODIMP
nsWalletlibService::WALLET_GetNocaptureListForViewer(nsAString
& aNocaptureList
){
178 ::WLLT_GetNocaptureListForViewer(aNocaptureList
);
182 NS_IMETHODIMP
nsWalletlibService::WALLET_GetPrefillListForViewer(nsAString
& aPrefillList
){
183 ::WLLT_GetPrefillListForViewer(aPrefillList
);
187 NS_IMETHODIMP
nsWalletlibService::SI_SignonViewerReturn(const nsAString
& results
){
188 ::Wallet_SignonViewerReturn(results
);
192 NS_IMETHODIMP
nsWalletlibService::Observe(nsISupports
*aSubject
, const char *aTopic
, const PRUnichar
*someData
)
194 if (!nsCRT::strcmp(aTopic
, "profile-before-change")) {
196 WLLT_ExpirePassword(&status
);
197 WLLT_ClearUserData();
198 if (!nsCRT::strcmp(someData
, NS_LITERAL_STRING("shutdown-cleanse").get())) {
199 WLLT_DeletePersistentUserData();
202 else if (!nsCRT::strcmp(aTopic
, "login-succeeded")) {
203 // A login succeeded; store the password.
204 nsCOMPtr
<nsIURI
> uri
= do_QueryInterface(aSubject
);
207 if (NS_SUCCEEDED(uri
->GetSpec(spec
)))
208 SINGSIGN_StorePassword(spec
.get(), EmptyString().get(), someData
);
211 else if (!nsCRT::strcmp(aTopic
, "login-failed")) {
212 // A login failed; clean out any information we've stored about
213 // the URL where the failure occurred.
214 nsCOMPtr
<nsIURI
> uri
= do_QueryInterface(aSubject
);
217 if (NS_SUCCEEDED(uri
->GetSpec(spec
)))
218 SINGSIGN_RemoveUserAfterLoginFailure(spec
.get(), EmptyString().get(), PR_TRUE
);
224 #define CRLF "\015\012"
225 NS_IMETHODIMP
nsWalletlibService::Notify(nsIDOMHTMLFormElement
* formNode
, nsIDOMWindowInternal
* window
, nsIURI
* actionURL
, PRBool
* cancelSubmit
)
228 return NS_ERROR_FAILURE
;
231 NS_ENSURE_TRUE(window
, NS_OK
);
233 ::WLLT_OnSubmit(formNode
, window
);
238 nsWalletlibService::RegisterProc(nsIComponentManager
*aCompMgr
,
240 const char *registryLocation
,
241 const char *componentType
,
242 const nsModuleComponentInfo
*info
)
244 // Register ourselves into the NS_CATEGORY_HTTP_STARTUP
246 nsCOMPtr
<nsICategoryManager
> catman
= do_GetService(NS_CATEGORYMANAGER_CONTRACTID
, &rv
);
247 if (NS_FAILED(rv
)) return rv
;
249 nsXPIDLCString prevEntry
;
250 catman
->AddCategoryEntry(NS_FIRST_FORMSUBMIT_CATEGORY
, "Form Manager", NS_WALLETSERVICE_CONTRACTID
,
251 PR_TRUE
, PR_TRUE
, getter_Copies(prevEntry
));
253 catman
->AddCategoryEntry(NS_PASSWORDMANAGER_CATEGORY
, "Password Manager", NS_WALLETSERVICE_CONTRACTID
,
254 PR_TRUE
, PR_TRUE
, getter_Copies(prevEntry
));
259 nsWalletlibService::UnregisterProc(nsIComponentManager
*aCompMgr
,
261 const char *registryLocation
,
262 const nsModuleComponentInfo
*info
)
265 nsCOMPtr
<nsICategoryManager
> catman
= do_GetService(NS_CATEGORYMANAGER_CONTRACTID
, &rv
);
266 if (NS_FAILED(rv
)) return rv
;
268 catman
->DeleteCategoryEntry(NS_FIRST_FORMSUBMIT_CATEGORY
,
269 NS_WALLETSERVICE_CONTRACTID
, PR_TRUE
);
271 catman
->DeleteCategoryEntry(NS_PASSWORDMANAGER_CATEGORY
,
272 NS_WALLETSERVICE_CONTRACTID
, PR_TRUE
);
274 // Return value is not used from this function.
278 PRBool expireMasterPassword
= PR_FALSE
;
279 #define expireMasterPasswordPref "signon.expireMasterPassword"
282 ExpireMasterPasswordPrefChanged(const char * newpref
, void * data
) {
284 nsCOMPtr
<nsIPref
> prefs(do_GetService(NS_PREF_CONTRACTID
, &rv
));
285 if (NS_FAILED(prefs
->GetBoolPref(expireMasterPasswordPref
, &expireMasterPassword
))) {
286 expireMasterPassword
= PR_FALSE
;
288 if (expireMasterPassword
) {
290 WLLT_ExpirePasswordOnly(&status
);
295 nsresult
nsWalletlibService::Init()
299 nsCOMPtr
<nsIObserverService
> svc
=
300 do_GetService("@mozilla.org/observer-service;1", &rv
);
301 if (NS_SUCCEEDED(rv
) && svc
) {
302 // Register as an observer of form submission
303 svc
->AddObserver(this, NS_EARLYFORMSUBMIT_SUBJECT
, PR_TRUE
);
304 // Register as an observer of profile changes
305 svc
->AddObserver(this, "profile-before-change", PR_TRUE
);
306 // Register as an observer for login
307 svc
->AddObserver(this, "login-succeeded", PR_TRUE
);
308 svc
->AddObserver(this, "login-failed", PR_TRUE
);
311 NS_ERROR("Could not get nsIObserverService");
313 // Get the global document loader service...
314 nsCOMPtr
<nsIWebProgress
> progress
=
315 do_GetService(kDocLoaderServiceCID
, &rv
);
316 if (NS_SUCCEEDED(rv
)) {
317 (void) progress
->AddProgressListener((nsIWebProgressListener
*)this,
318 nsIWebProgress::NOTIFY_STATE_DOCUMENT
);
321 NS_ERROR("Could not get nsIWebProgress");
323 /* initialize the expire-master-password feature */
324 nsCOMPtr
<nsIPref
> prefs(do_GetService(NS_PREF_CONTRACTID
, &rv
));
325 if (NS_SUCCEEDED(rv
)) {
326 prefs
->RegisterCallback(expireMasterPasswordPref
, ExpireMasterPasswordPrefChanged
, NULL
);
327 prefs
->GetBoolPref(expireMasterPasswordPref
, &expireMasterPassword
);
333 // nsIWebProgressListener implementation
335 nsWalletlibService::OnStateChange(nsIWebProgress
* aWebProgress
,
336 nsIRequest
*aRequest
,
337 PRUint32 progressStateFlags
,
342 // If the load failed, do not try to prefill...
343 if (NS_FAILED(aStatus
)) {
347 if (progressStateFlags
& nsIWebProgressListener::STATE_IS_DOCUMENT
) {
348 if (progressStateFlags
& nsIWebProgressListener::STATE_STOP
) {
350 nsCOMPtr
<nsIDOMWindow
> domWin
;
351 rv
= aWebProgress
->GetDOMWindow(getter_AddRefs(domWin
));
352 if (NS_FAILED(rv
)) return rv
;
354 nsCOMPtr
<nsIDOMDocument
> domDoc
;
355 rv
= domWin
->GetDocument(getter_AddRefs(domDoc
));
356 if (NS_FAILED(rv
)) return rv
;
358 // we only want to handle HTML documents as they're the
359 // only one's that can have forms which we might want to
361 nsCOMPtr
<nsIDOMHTMLDocument
> htmldoc(do_QueryInterface(domDoc
, &rv
));
362 if (NS_FAILED(rv
)) return NS_OK
;
364 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(htmldoc
, &rv
));
366 NS_ASSERTION(0, "no document available");
370 nsIURI
*uri
= doc
->GetDocumentURI();
372 NS_ASSERTION(0, "no URI available");
376 nsCOMPtr
<nsIDOMHTMLCollection
> forms
;
377 rv
= htmldoc
->GetForms(getter_AddRefs(forms
));
378 if (NS_FAILED(rv
) || (forms
== nsnull
)) return rv
;
380 PRUint32 elementNumber
= 0;
382 forms
->GetLength(&numForms
);
383 for (PRUint32 formX
= 0; formX
< numForms
; formX
++) {
384 nsCOMPtr
<nsIDOMNode
> formNode
;
385 forms
->Item(formX
, getter_AddRefs(formNode
));
386 if (nsnull
!= formNode
) {
387 nsCOMPtr
<nsIDOMHTMLFormElement
> formElement(do_QueryInterface(formNode
));
388 if ((nsnull
!= formElement
)) {
389 nsCOMPtr
<nsIDOMHTMLCollection
> elements
;
390 rv
= formElement
->GetElements(getter_AddRefs(elements
));
391 if ((NS_SUCCEEDED(rv
)) && (nsnull
!= elements
)) {
392 /* got to the form elements at long last */
393 PRUint32 numElements
;
394 elements
->GetLength(&numElements
);
395 /* get number of passwords on form */
396 PRInt32 passwordCount
= 0;
397 for (PRUint32 elementXX
= 0; elementXX
< numElements
; elementXX
++) {
398 nsCOMPtr
<nsIDOMNode
> elementNode
;
399 elements
->Item(elementXX
, getter_AddRefs(elementNode
));
400 if (nsnull
!= elementNode
) {
401 nsCOMPtr
<nsIDOMHTMLInputElement
> inputElement(do_QueryInterface(elementNode
));
402 if ((NS_SUCCEEDED(rv
)) && (nsnull
!= inputElement
)) {
404 rv
= inputElement
->GetType(type
);
405 if (NS_SUCCEEDED(rv
)) {
406 if (type
.LowerCaseEqualsLiteral("password")) {
413 /* don't prefill if there were no passwords on the form */
414 if (passwordCount
== 0) {
417 for (PRUint32 elementX
= 0; elementX
< numElements
; elementX
++) {
418 nsCOMPtr
<nsIDOMNode
> elementNode
;
419 elements
->Item(elementX
, getter_AddRefs(elementNode
));
420 if (nsnull
!= elementNode
) {
421 nsCOMPtr
<nsIDOMHTMLInputElement
> inputElement(do_QueryInterface(elementNode
));
422 if ((NS_SUCCEEDED(rv
)) && (nsnull
!= inputElement
)) {
424 rv
= inputElement
->GetType(type
);
425 if (NS_SUCCEEDED(rv
)) {
426 if (type
.IsEmpty() ||
427 type
.LowerCaseEqualsLiteral("text") ||
428 type
.LowerCaseEqualsLiteral("password")) {
430 rv
= inputElement
->GetName(field
);
431 if (NS_SUCCEEDED(rv
)) {
432 PRUnichar
* nameString
= ToNewUnicode(field
);
435 PRUnichar
* valueString
= NULL
;
436 nsCOMPtr
<nsIPrompt
> prompter
;
438 nsCOMPtr
<nsIChannel
> channel
= do_QueryInterface(aRequest
);
440 NS_QueryNotificationCallbacks(channel
, prompter
);
442 nsCOMPtr
<nsIWindowWatcher
> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID
));
444 wwatch
->GetNewPrompter(0, getter_AddRefs(prompter
));
447 SINGSIGN_RestoreSignonData(prompter
, uri
, nameString
, &valueString
, formX
, elementNumber
++);
451 rv
= inputElement
->SetValue(value
);
452 // warning! don't delete valueString
466 if (expireMasterPassword
) {
468 WLLT_ExpirePasswordOnly(&status
);
476 nsWalletlibService::OnProgressChange(nsIWebProgress
*aWebProgress
,
477 nsIRequest
*aRequest
,
478 PRInt32 aCurSelfProgress
,
479 PRInt32 aMaxSelfProgress
,
480 PRInt32 aCurTotalProgress
,
481 PRInt32 aMaxTotalProgress
)
483 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
488 nsWalletlibService::OnLocationChange(nsIWebProgress
* aWebProgress
,
489 nsIRequest
* aRequest
,
492 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
497 nsWalletlibService::OnStatusChange(nsIWebProgress
* aWebProgress
,
498 nsIRequest
* aRequest
,
500 const PRUnichar
* aMessage
)
502 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
507 nsWalletlibService::OnSecurityChange(nsIWebProgress
*aWebProgress
,
508 nsIRequest
*aRequest
,
511 NS_NOTREACHED("notification excluded in AddProgressListener(...)");
516 nsWalletlibService::HaveData(nsIPrompt
* dialog
, const char *key
, const PRUnichar
*userName
, PRBool
*_retval
)
518 return ::SINGSIGN_HaveData(dialog
, key
, userName
, _retval
);
522 nsWalletlibService::WALLET_Encrypt (const PRUnichar
*text
, char **crypt
) {
523 nsAutoString
textAutoString( text
);
524 nsAutoString cryptAutoString
;
525 PRBool rv
= ::Wallet_Encrypt(textAutoString
, cryptAutoString
);
526 *crypt
= ToNewCString(cryptAutoString
);
531 nsWalletlibService::WALLET_Decrypt (const char *crypt
, PRUnichar
**text
) {
532 nsAutoString cryptAutoString
; cryptAutoString
.AssignASCII(crypt
);
533 nsAutoString textAutoString
;
534 PRBool rv
= ::Wallet_Decrypt(cryptAutoString
, textAutoString
);
535 *text
= ToNewUnicode(textAutoString
);
540 nsWalletlibService::GetPrompt(nsIDOMWindow
* aParent
,
543 if (!aIID
.Equals(NS_GET_IID(nsIAuthPrompt2
))) {
544 NS_WARNING("Wallet asked for unexpected interface");
545 return NS_NOINTERFACE
;
548 // NOTE: It is important to return the specific return value here. The
551 nsCOMPtr
<nsIPromptService2
> service
=
552 do_GetService(NS_PROMPTSERVICE_CONTRACTID
, &rv
);
556 nsWalletAuthPromptWrapper
* wrapper
=
557 new nsWalletAuthPromptWrapper(service
, aParent
);
559 return NS_ERROR_OUT_OF_MEMORY
;
562 *_retval
= static_cast<nsIAuthPrompt2
*>(wrapper
);
566 ////////////////////////////////////////////////////////////////////////////////
567 // nsWalletAuthPromptWrapper
569 NS_IMPL_ISUPPORTS1(nsWalletAuthPromptWrapper
, nsIAuthPrompt2
)
572 nsWalletAuthPromptWrapper::PromptAuth(nsIChannel
* aChannel
,
574 nsIAuthInformation
* aAuthInfo
,
577 return SINGSIGN_PromptAuth(mService
, mParent
, aChannel
,
578 aLevel
, aAuthInfo
, retval
);
582 nsWalletAuthPromptWrapper::AsyncPromptAuth(nsIChannel
*,
583 nsIAuthPromptCallback
*,
589 return NS_ERROR_NOT_IMPLEMENTED
;
594 ////////////////////////////////////////////////////////////////////////////////
595 // nsSingleSignOnPrompt
597 NS_IMPL_THREADSAFE_ISUPPORTS2(nsSingleSignOnPrompt
,
598 nsIAuthPromptWrapper
,
602 nsSingleSignOnPrompt::Init()
608 nsSingleSignOnPrompt::Prompt(const PRUnichar
*dialogTitle
, const PRUnichar
*text
,
609 const PRUnichar
*passwordRealm
, PRUint32 savePassword
,
610 const PRUnichar
*defaultText
, PRUnichar
**result
, PRBool
*_retval
)
613 rv
= SINGSIGN_Prompt(
614 dialogTitle
, text
, defaultText
, result
,
615 NS_ConvertUTF16toUTF8(passwordRealm
).get(), mPrompt
, _retval
, savePassword
);
620 nsSingleSignOnPrompt::PromptUsernameAndPassword(const PRUnichar
*dialogTitle
, const PRUnichar
*text
,
621 const PRUnichar
*passwordRealm
, PRUint32 savePassword
,
622 PRUnichar
**user
, PRUnichar
**pwd
, PRBool
*_retval
)
625 rv
= SINGSIGN_PromptUsernameAndPassword(
626 dialogTitle
, text
, user
, pwd
,
627 NS_ConvertUTF16toUTF8(passwordRealm
).get(), mPrompt
, _retval
, savePassword
);
632 nsSingleSignOnPrompt::PromptPassword(const PRUnichar
*dialogTitle
, const PRUnichar
*text
,
633 const PRUnichar
*passwordRealm
, PRUint32 savePassword
,
634 PRUnichar
**pwd
, PRBool
*_retval
)
637 rv
= SINGSIGN_PromptPassword(
638 dialogTitle
, text
, pwd
,
639 NS_ConvertUTF16toUTF8(passwordRealm
).get(), mPrompt
, _retval
, savePassword
);
643 // nsISingleSignOnPrompt methods:
646 nsSingleSignOnPrompt::SetPromptDialogs(nsIPrompt
* dialogs
)
652 ////////////////////////////////////////////////////////////////////////////////