/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Pierre Phaneuf */ #include "nsCOMPtr.h" #include "nsWalletService.h" #include "nsIServiceManager.h" #include "wallet.h" #include "singsign.h" #include "nsIObserverService.h" #include "nsIDOMHTMLDocument.h" #include "nsIDOMHTMLCollection.h" #include "nsIDOMHTMLFormElement.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDocumentLoader.h" #include "nsCURILoader.h" #include "nsIWebShell.h" #include "nsIDocumentViewer.h" #include "nsIDOMHTMLInputElement.h" #include "nsIFormControl.h" #include "nsIDocShell.h" #include "nsIDOMWindowInternal.h" #include "nsINetSupportDialogService.h" #include "nsIInterfaceRequestor.h" #include "nsIPrompt.h" #include "nsIChannel.h" // for making the leap from nsIDOMWindowInternal -> nsIPresShell #include "nsIScriptGlobalObject.h" static NS_DEFINE_IID(kDocLoaderServiceCID, NS_DOCUMENTLOADER_SERVICE_CID); static NS_DEFINE_CID(kNetSupportDialogCID, NS_NETSUPPORTDIALOG_CID); nsWalletlibService::nsWalletlibService() { NS_INIT_REFCNT(); } nsWalletlibService::~nsWalletlibService() { #ifdef DEBUG_dp printf("Wallet Service destroyed successfully.\n"); #endif /* DEBUG_dp */ Wallet_ReleaseAllLists(); SI_ClearUserData(); } NS_IMPL_THREADSAFE_ISUPPORTS5(nsWalletlibService, nsIWalletService, nsIObserver, nsIFormSubmitObserver, nsIDocumentLoaderObserver, nsISupportsWeakReference) NS_IMETHODIMP nsWalletlibService::WALLET_PreEdit(nsAutoString& walletList) { ::WLLT_PreEdit(walletList); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_PostEdit(nsAutoString walletList) { ::WLLT_PostEdit(walletList); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_ChangePassword(PRBool* status) { ::WLLT_ChangePassword(status); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_DeleteAll() { ::WLLT_DeleteAll(); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_RequestToCapture(nsIDOMWindowInternal* aWin, PRUint32* status) { nsCOMPtr scriptGlobalObject; scriptGlobalObject = do_QueryInterface(aWin); nsCOMPtr docShell; scriptGlobalObject->GetDocShell(getter_AddRefs(docShell)); nsCOMPtr presShell; if(docShell) docShell->GetPresShell(getter_AddRefs(presShell)); ::WLLT_RequestToCapture(presShell, aWin, status); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_PrefillOneElement (nsIDOMWindowInternal* aWin, nsIDOMNode* elementNode, PRUnichar **value) { nsAutoString compositeValue; nsresult rv = ::WLLT_PrefillOneElement(aWin, elementNode, compositeValue); *value = compositeValue.ToNewUnicode(); return rv; } NS_IMETHODIMP nsWalletlibService::WALLET_Prefill(PRBool quick, nsIDOMWindowInternal* aWin, PRBool* status) { nsCOMPtr scriptGlobalObject; scriptGlobalObject = do_QueryInterface(aWin); nsCOMPtr docShell; scriptGlobalObject->GetDocShell(getter_AddRefs(docShell)); nsCOMPtr presShell; if(docShell) docShell->GetPresShell(getter_AddRefs(presShell)); return ::WLLT_Prefill(presShell, quick, aWin); } NS_IMETHODIMP nsWalletlibService::WALLET_PrefillReturn(nsAutoString results){ ::WLLT_PrefillReturn(results); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_FetchFromNetCenter(){ ::WLLT_FetchFromNetCenter(); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_ExpirePassword(PRBool* status){ ::WLLT_ExpirePassword(status); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_InitReencryptCallback(nsIDOMWindowInternal* window){ /* register callback to be used when encryption pref changes */ ::WLLT_InitReencryptCallback(window); return NS_OK; } NS_IMETHODIMP nsWalletlibService::SI_RemoveUser(const char *key, const PRUnichar *userName) { ::SINGSIGN_RemoveUser(key, userName); return NS_OK; } NS_IMETHODIMP nsWalletlibService::SI_StorePassword(const char *key, const PRUnichar *userName, const PRUnichar *password) { ::SINGSIGN_StorePassword(key, userName, password); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_GetNopreviewListForViewer(nsAutoString& aNopreviewList){ ::WLLT_GetNopreviewListForViewer(aNopreviewList); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_GetNocaptureListForViewer(nsAutoString& aNocaptureList){ ::WLLT_GetNocaptureListForViewer(aNocaptureList); return NS_OK; } NS_IMETHODIMP nsWalletlibService::WALLET_GetPrefillListForViewer(nsAutoString& aPrefillList){ ::WLLT_GetPrefillListForViewer(aPrefillList); return NS_OK; } NS_IMETHODIMP nsWalletlibService::SI_GetSignonListForViewer(nsAutoString& aSignonList){ ::SINGSIGN_GetSignonListForViewer(aSignonList); return NS_OK; } NS_IMETHODIMP nsWalletlibService::SI_GetRejectListForViewer(nsAutoString& aRejectList){ ::SINGSIGN_GetRejectListForViewer(aRejectList); return NS_OK; } NS_IMETHODIMP nsWalletlibService::SI_SignonViewerReturn(nsAutoString results){ ::SINGSIGN_SignonViewerReturn(results); return NS_OK; } NS_IMETHODIMP nsWalletlibService::Observe(nsISupports*, const PRUnichar *aTopic, const PRUnichar *someData) { if (!nsCRT::strcmp(aTopic, NS_LITERAL_STRING("profile-before-change").get())) { WLLT_ClearUserData(); if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) { WLLT_DeletePersistentUserData(); } } return NS_OK; } #define CRLF "\015\012" NS_IMETHODIMP nsWalletlibService::Notify(nsIContent* formNode, nsIDOMWindowInternal* window, nsIURI* actionURL, PRBool* cancelSubmit) { if (!formNode) { return NS_ERROR_FAILURE; } ::WLLT_OnSubmit(formNode, window); return NS_OK; } nsresult nsWalletlibService::Init() { nsresult rv; NS_WITH_SERVICE(nsIObserverService, svc, NS_OBSERVERSERVICE_CONTRACTID, &rv); if (NS_SUCCEEDED(rv) && svc) { // Register as an observer of form submission nsAutoString topic; topic.AssignWithConversion(NS_FORMSUBMIT_SUBJECT); svc->AddObserver(this, topic.GetUnicode()); // Register as an observer of profile changes svc->AddObserver(this, NS_LITERAL_STRING("profile-before-change").get()); } else NS_ASSERTION(PR_FALSE, "Could not get nsIObserverService"); // Get the global document loader service... NS_WITH_SERVICE(nsIDocumentLoader, docLoaderService, kDocLoaderServiceCID, &rv) if (NS_SUCCEEDED(rv) && docLoaderService) { //Register ourselves as an observer for the new doc loader docLoaderService->AddObserver((nsIDocumentLoaderObserver*)this); } else NS_ASSERTION(PR_FALSE, "Could not get nsIDocumentLoader"); return NS_OK; } NS_IMETHODIMP nsWalletlibService::OnStartDocumentLoad(nsIDocumentLoader* aLoader, nsIURI* aURL, const char* aCommand) { return NS_OK; } #include "prmem.h" NS_IMETHODIMP nsWalletlibService::OnEndDocumentLoad(nsIDocumentLoader* aLoader, nsIRequest *request, nsresult aStatus) { nsresult rv = NS_OK; if (aLoader == nsnull) { return rv; } nsCOMPtr cont; rv = aLoader->GetContainer(getter_AddRefs(cont)); if (NS_FAILED(rv) || (cont == nsnull)) { return rv; } nsCOMPtr docShell(do_QueryInterface(cont)); NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); nsCOMPtr cv; rv = docShell->GetContentViewer(getter_AddRefs(cv)); if (NS_FAILED(rv) || (cv == nsnull)) { return rv; } nsCOMPtr docViewer(do_QueryInterface(cv)); NS_ENSURE_TRUE(docViewer, NS_ERROR_FAILURE); nsCOMPtr doc; rv = docViewer->GetDocument(*getter_AddRefs(doc)); if (NS_FAILED(rv) || (doc == nsnull)) { return rv; } /* get url name as ascii string */ char *URLName = nsnull; nsIURI* docURL = nsnull; char* spec; if (!doc) { return NS_OK; } docURL = doc->GetDocumentURL(); if (!docURL) { return NS_OK; } (void)docURL->GetSpec(&spec); URLName = (char*)PR_Malloc(PL_strlen(spec)+1); PL_strcpy(URLName, spec); NS_IF_RELEASE(docURL); nsCRT::free(spec); nsCOMPtr htmldoc(do_QueryInterface(doc)); if (htmldoc == nsnull) { PR_Free(URLName); return NS_ERROR_FAILURE; } nsCOMPtr forms; rv = htmldoc->GetForms(getter_AddRefs(forms)); if (NS_FAILED(rv) || (forms == nsnull)) { PR_Free(URLName); return rv; } PRUint32 elementNumber = 0; PRUint32 numForms; forms->GetLength(&numForms); for (PRUint32 formX = 0; formX < numForms; formX++) { nsCOMPtr formNode; forms->Item(formX, getter_AddRefs(formNode)); if (nsnull != formNode) { nsCOMPtr formElement(do_QueryInterface(formNode)); if ((nsnull != formElement)) { nsCOMPtr elements; rv = formElement->GetElements(getter_AddRefs(elements)); if ((NS_SUCCEEDED(rv)) && (nsnull != elements)) { /* got to the form elements at long last */ PRUint32 numElements; elements->GetLength(&numElements); /* get number of passwords on form */ PRInt32 passwordCount = 0; for (PRUint32 elementXX = 0; elementXX < numElements; elementXX++) { nsCOMPtr elementNode; elements->Item(elementXX, getter_AddRefs(elementNode)); if (nsnull != elementNode) { nsCOMPtr inputElement(do_QueryInterface(elementNode)); if ((NS_SUCCEEDED(rv)) && (nsnull != inputElement)) { nsAutoString type; rv = inputElement->GetType(type); if (NS_SUCCEEDED(rv)) { if (type.CompareWithConversion("password", PR_TRUE) == 0) { passwordCount++; } } } } } /* don't prefill if there were no passwords on the form */ if (passwordCount == 0) { continue; } for (PRUint32 elementX = 0; elementX < numElements; elementX++) { nsCOMPtr elementNode; elements->Item(elementX, getter_AddRefs(elementNode)); if (nsnull != elementNode) { nsCOMPtr inputElement(do_QueryInterface(elementNode)); if ((NS_SUCCEEDED(rv)) && (nsnull != inputElement)) { nsAutoString type; rv = inputElement->GetType(type); if (NS_SUCCEEDED(rv)) { if ((type.IsEmpty()) || (type.CompareWithConversion("text", PR_TRUE) == 0) || (type.CompareWithConversion("password", PR_TRUE) == 0)) { nsAutoString field; rv = inputElement->GetName(field); if (NS_SUCCEEDED(rv)) { PRUnichar* nameString = field.ToNewUnicode(); if (nameString) { /* note: we do not want to prefill if there is a default value */ nsAutoString value; rv = inputElement->GetValue(value); if (NS_FAILED(rv) || value.Length() == 0) { PRUnichar* valueString = NULL; nsCOMPtr interfaces; nsCOMPtr prompter; nsCOMPtr channel = do_QueryInterface(request); if (channel) channel->GetNotificationCallbacks(getter_AddRefs(interfaces)); if (interfaces) interfaces->GetInterface(NS_GET_IID(nsIPrompt), getter_AddRefs(prompter)); if (!prompter) prompter = do_GetService(kNetSupportDialogCID); if (prompter) { SINGSIGN_RestoreSignonData(prompter, URLName, nameString, &valueString, elementNumber++); } if (valueString) { value = valueString; rv = inputElement->SetValue(value); // warning! don't delete valueString } } Recycle(nameString); } } } } } } } } } } } PR_Free(URLName); return rv; } NS_IMETHODIMP nsWalletlibService::OnStartURLLoad (nsIDocumentLoader* loader, nsIRequest *request) { return NS_OK; } NS_IMETHODIMP nsWalletlibService::OnProgressURLLoad (nsIDocumentLoader* loader, nsIRequest *request, PRUint32 aProgress, PRUint32 aProgressMax) { return NS_OK; } NS_IMETHODIMP nsWalletlibService::OnStatusURLLoad (nsIDocumentLoader* loader, nsIRequest *request, nsString& aMsg) { return NS_OK; } NS_IMETHODIMP nsWalletlibService::OnEndURLLoad (nsIDocumentLoader* loader, nsIRequest *request, nsresult aStatus) { return NS_OK; } NS_IMETHODIMP nsWalletlibService::GetPassword(PRUnichar **password) { return NS_ERROR_FAILURE; } NS_IMETHODIMP nsWalletlibService::HaveData(nsIPrompt* dialog, const char *key, const PRUnichar *userName, PRBool *_retval) { return ::SINGSIGN_HaveData(dialog, key, userName, _retval); } NS_IMETHODIMP nsWalletlibService::WALLET_Encrypt (const PRUnichar *text, char **crypt) { nsAutoString textAutoString( text ); nsAutoString cryptAutoString; PRBool rv = ::Wallet_Encrypt(textAutoString, cryptAutoString); *crypt = cryptAutoString.ToNewCString(); return rv; } NS_IMETHODIMP nsWalletlibService::WALLET_Decrypt (const char *crypt, PRUnichar **text) { nsAutoString cryptAutoString; cryptAutoString.AssignWithConversion(crypt); nsAutoString textAutoString; PRBool rv = ::Wallet_Decrypt(cryptAutoString, textAutoString); *text = textAutoString.ToNewUnicode(); return rv; } //////////////////////////////////////////////////////////////////////////////// // nsSingleSignOnPrompt NS_IMPL_THREADSAFE_ISUPPORTS4(nsSingleSignOnPrompt, nsISingleSignOnPrompt, nsIPrompt, nsIObserver, nsISupportsWeakReference) nsresult nsSingleSignOnPrompt::Init() { nsresult rv; NS_WITH_SERVICE(nsIObserverService, svc, NS_OBSERVERSERVICE_CONTRACTID, &rv); if (NS_SUCCEEDED(rv) && svc) { // Register as an observer of profile changes svc->AddObserver(this, NS_LITERAL_STRING("profile-before-change").get()); } else NS_ASSERTION(PR_FALSE, "Could not get nsIObserverService"); return NS_OK; } NS_IMETHODIMP nsSingleSignOnPrompt::Alert(const PRUnichar *dialogTitle, const PRUnichar *text) { return mPrompt->Alert(dialogTitle, text); } NS_IMETHODIMP nsSingleSignOnPrompt::AlertCheck(const PRUnichar *dialogTitle, const PRUnichar *text, const PRUnichar *checkMsg, PRBool *checkValue) { return mPrompt->AlertCheck(dialogTitle, text, checkMsg, checkValue); } NS_IMETHODIMP nsSingleSignOnPrompt::Confirm(const PRUnichar *dialogTitle, const PRUnichar *text, PRBool *_retval) { return mPrompt->Confirm(dialogTitle, text, _retval); } NS_IMETHODIMP nsSingleSignOnPrompt::ConfirmCheck(const PRUnichar *dialogTitle, const PRUnichar *text, const PRUnichar *checkMsg, PRBool *checkValue, PRBool *_retval) { return mPrompt->ConfirmCheck(dialogTitle, text, checkMsg, checkValue, _retval); } NS_IMETHODIMP nsSingleSignOnPrompt::Prompt(const PRUnichar *dialogTitle, const PRUnichar *text, const PRUnichar *passwordRealm, PRUint32 savePassword, const PRUnichar *defaultText, PRUnichar **result, PRBool *_retval) { nsresult rv; nsCAutoString realm; realm.AssignWithConversion(passwordRealm); // XXX should be PRUnichar* rv = SINGSIGN_Prompt(dialogTitle, text, defaultText, result, realm.get(), mPrompt, _retval, savePassword); return rv; } NS_IMETHODIMP nsSingleSignOnPrompt::PromptUsernameAndPassword(const PRUnichar *dialogTitle, const PRUnichar *text, const PRUnichar *passwordRealm, PRUint32 savePassword, PRUnichar **user, PRUnichar **pwd, PRBool *_retval) { nsresult rv; nsCAutoString realm; realm.AssignWithConversion(passwordRealm); // XXX should be PRUnichar* rv = SINGSIGN_PromptUsernameAndPassword(dialogTitle, text, user, pwd, realm.get(), mPrompt, _retval, savePassword); return rv; } NS_IMETHODIMP nsSingleSignOnPrompt::PromptPassword(const PRUnichar *dialogTitle, const PRUnichar *text, const PRUnichar *passwordRealm, PRUint32 savePassword, PRUnichar **pwd, PRBool *_retval) { nsresult rv; nsCAutoString realm; realm.AssignWithConversion(passwordRealm); // XXX should be PRUnichar* rv = SINGSIGN_PromptPassword(dialogTitle, text, pwd, realm.get(), mPrompt, _retval, savePassword); return rv; } NS_IMETHODIMP nsSingleSignOnPrompt::Select(const PRUnichar *dialogTitle, const PRUnichar *text, PRUint32 count, const PRUnichar **selectList, PRInt32 *outSelection, PRBool *_retval) { return mPrompt->Select(dialogTitle, text, count, selectList, outSelection, _retval); } NS_IMETHODIMP nsSingleSignOnPrompt::UniversalDialog(const PRUnichar *titleMessage, const PRUnichar *dialogTitle, const PRUnichar *text, const PRUnichar *checkboxMsg, const PRUnichar *button0Text, const PRUnichar *button1Text, const PRUnichar *button2Text, const PRUnichar *button3Text, const PRUnichar *editfield1Msg, const PRUnichar *editfield2Msg, PRUnichar **editfield1Value, PRUnichar **editfield2Value, const PRUnichar *iconURL, PRBool *checkboxState, PRInt32 numberButtons, PRInt32 numberEditfields, PRInt32 editField1Password, PRInt32 *buttonPressed) { return mPrompt->UniversalDialog(titleMessage, dialogTitle, text, checkboxMsg, button0Text, button1Text, button2Text, button3Text, editfield1Msg, editfield2Msg, editfield1Value, editfield2Value, iconURL, checkboxState, numberButtons, numberEditfields, editField1Password, buttonPressed); } // nsISingleSignOnPrompt methods: NS_IMETHODIMP nsSingleSignOnPrompt::SetPromptDialogs(nsIPrompt* dialogs) { mPrompt = dialogs; return NS_OK; } // nsIObserver methods: NS_IMETHODIMP nsSingleSignOnPrompt::Observe(nsISupports*, const PRUnichar *aTopic, const PRUnichar *someData) { if (!nsCRT::strcmp(aTopic, NS_LITERAL_STRING("profile-before-change").get())) { SI_ClearUserData(); if (!nsCRT::strcmp(someData, NS_LITERAL_STRING("shutdown-cleanse").get())) { SI_DeletePersistentUserData(); } } return NS_OK; } ////////////////////////////////////////////////////////////////////////////////