From a91716eeaecf7f21a01159f1cb3c8747a38ea880 Mon Sep 17 00:00:00 2001 From: "joshmoz@gmail.com" Date: Thu, 27 Sep 2007 09:01:32 -0700 Subject: [PATCH] extra measure of security for password textfields on Mac OS X. b=394107 r=smorgan sr=roc --- layout/forms/nsTextControlFrame.cpp | 36 ++++++++++++++++++++++++++- layout/forms/nsTextControlFrame.h | 7 +++++- widget/public/nsIWidget.h | 24 +++++++++++++++--- widget/src/cocoa/nsChildView.h | 3 +++ widget/src/cocoa/nsChildView.mm | 20 +++++++++++++++ widget/src/cocoa/nsCocoaWindow.h | 3 +++ widget/src/cocoa/nsCocoaWindow.mm | 18 ++++++++++++++ widget/src/xpwidgets/nsBaseWidget.cpp | 21 ++++++++++++++++ widget/src/xpwidgets/nsBaseWidget.h | 4 ++- 9 files changed, 130 insertions(+), 6 deletions(-) diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index bcc798fc57f6..94669bf8ab09 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -359,7 +359,12 @@ nsTextInputListener::Focus(nsIDOMEvent* aEvent) editor->AddEditorObserver(this); } - return mFrame->InitFocusedValue(); + nsresult rv = mFrame->InitFocusedValue(); + + if (NS_SUCCEEDED(rv)) + rv = mFrame->MaybeBeginSecureKeyboardInput(); + + return rv; } NS_IMETHODIMP @@ -374,6 +379,8 @@ nsTextInputListener::Blur(nsIDOMEvent* aEvent) editor->RemoveEditorObserver(this); } + mFrame->MaybeEndSecureKeyboardInput(); + return NS_OK; } @@ -1040,6 +1047,7 @@ nsTextControlFrame::nsTextControlFrame(nsIPresShell* aShell, nsStyleContext* aCo , mNotifyOnInput(PR_TRUE) , mDidPreDestroy(PR_FALSE) , mFireChangeEventState(PR_FALSE) + , mInSecureKeyboardInputMode(PR_FALSE) , mTextListener(nsnull) #ifdef DEBUG , mCreateFrameForCalled(PR_FALSE) @@ -1172,6 +1180,9 @@ nsTextControlFrame::PreDestroy() void nsTextControlFrame::Destroy() { + if (mInSecureKeyboardInputMode) { + MaybeEndSecureKeyboardInput(); + } if (!mDidPreDestroy) { PreDestroy(); } @@ -1220,6 +1231,29 @@ PRBool nsTextControlFrame::IsPlainTextControl() const return PR_TRUE; } +nsresult nsTextControlFrame::MaybeBeginSecureKeyboardInput() +{ + nsresult rv = NS_OK; + if (IsPasswordTextControl() && !mInSecureKeyboardInputMode) { + nsIWidget* window = GetWindow(); + NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); + rv = window->BeginSecureKeyboardInput(); + mInSecureKeyboardInputMode = NS_SUCCEEDED(rv); + } + return rv; +} + +void nsTextControlFrame::MaybeEndSecureKeyboardInput() +{ + if (mInSecureKeyboardInputMode) { + nsIWidget* window = GetWindow(); + if (!window) + return; + window->EndSecureKeyboardInput(); + mInSecureKeyboardInputMode = PR_FALSE; + } +} + PRBool nsTextControlFrame::IsPasswordTextControl() const { nsCOMPtr formControl = do_QueryInterface(mContent); diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h index 11cbf11b84f6..32a0234cb98d 100644 --- a/layout/forms/nsTextControlFrame.h +++ b/layout/forms/nsTextControlFrame.h @@ -213,7 +213,11 @@ public: //for methods who access nsTextControlFrame directly /* called to free up native keybinding services */ static NS_HIDDEN_(void) ShutDown(); - + + // called by the focus listener + nsresult MaybeBeginSecureKeyboardInput(); + void MaybeEndSecureKeyboardInput(); + protected: /** * Find out whether this control is scrollable (i.e. if it is not a single @@ -296,6 +300,7 @@ private: // Calls to SetValue will be treated as user values (i.e. trigger onChange // eventually) when mFireChangeEventState==true, this is used by nsFileControlFrame. PRPackedBool mFireChangeEventState; + PRPackedBool mInSecureKeyboardInputMode; nsCOMPtr mSelCon; nsCOMPtr mFrameSel; diff --git a/widget/public/nsIWidget.h b/widget/public/nsIWidget.h index d43ffa9b7dd5..b300dcb120d1 100644 --- a/widget/public/nsIWidget.h +++ b/widget/public/nsIWidget.h @@ -95,11 +95,11 @@ typedef nsEventStatus (*PR_CALLBACK EVENT_CALLBACK)(nsGUIEvent *event); #define NS_NATIVE_PLUGIN_PORT_CG 101 #endif -// f60fa720-a9bc-4fd3-b863-812496fa85e6 +// 15800FBD-650A-4F67-81FB-186E73F45BE1 #define NS_IWIDGET_IID \ -{ 0xf60fa720, 0xa9bc, 0x4fd3, \ - { 0xb8, 0x63, 0x81, 0x24, 0x96, 0xfa, 0x85, 0xe6 } } +{ 0x15800FBD, 0x650A, 0x4F67, \ + { 0x81, 0xFB, 0x18, 0x6E, 0x73, 0xF4, 0x5B, 0xE1 } } // Hide the native window systems real window type so as to avoid // including native window system types and api's. This is necessary @@ -1012,6 +1012,24 @@ class nsIWidget : public nsISupports { */ NS_IMETHOD GetLastInputEventTime(PRUint32& aTime) = 0; + /** + * Called when when we need to begin secure keyboard input, such as when a password field + * gets focus. + * + * NOTE: Calls to this method may not be nested and you can only enable secure keyboard input + * for one widget at a time. + */ + NS_IMETHOD BeginSecureKeyboardInput() = 0; + + /** + * Called when when we need to end secure keyboard input, such as when a password field + * loses focus. + * + * NOTE: Calls to this method may not be nested and you can only enable secure keyboard input + * for one widget at a time. + */ + NS_IMETHOD EndSecureKeyboardInput() = 0; + /** * Get the Thebes surface associated with this widget. */ diff --git a/widget/src/cocoa/nsChildView.h b/widget/src/cocoa/nsChildView.h index 4f9c75a7d756..22ac35f522bc 100644 --- a/widget/src/cocoa/nsChildView.h +++ b/widget/src/cocoa/nsChildView.h @@ -312,6 +312,9 @@ public: virtual gfxASurface* GetThebesSurface(); + NS_IMETHOD BeginSecureKeyboardInput(); + NS_IMETHOD EndSecureKeyboardInput(); + protected: PRBool ReportDestroyEvent(); diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index 023bd3f04cef..dbbc31db2087 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -1744,6 +1744,26 @@ nsChildView::GetThebesSurface() } +NS_IMETHODIMP +nsChildView::BeginSecureKeyboardInput() +{ + nsresult rv = nsBaseWidget::BeginSecureKeyboardInput(); + if (NS_SUCCEEDED(rv)) + ::EnableSecureEventInput(); + return rv; +} + + +NS_IMETHODIMP +nsChildView::EndSecureKeyboardInput() +{ + nsresult rv = nsBaseWidget::EndSecureKeyboardInput(); + if (NS_SUCCEEDED(rv)) + ::DisableSecureEventInput(); + return rv; +} + + #ifdef ACCESSIBILITY void nsChildView::GetDocumentAccessible(nsIAccessible** aAccessible) diff --git a/widget/src/cocoa/nsCocoaWindow.h b/widget/src/cocoa/nsCocoaWindow.h index fb15ec7ecf8d..b5168d6181fc 100644 --- a/widget/src/cocoa/nsCocoaWindow.h +++ b/widget/src/cocoa/nsCocoaWindow.h @@ -203,6 +203,9 @@ public: // nsIKBStateControl interface NS_IMETHOD ResetInputState(); + NS_IMETHOD BeginSecureKeyboardInput(); + NS_IMETHOD EndSecureKeyboardInput(); + protected: nsIWidget* mParent; // if we're a popup, this is our parent [WEAK] diff --git a/widget/src/cocoa/nsCocoaWindow.mm b/widget/src/cocoa/nsCocoaWindow.mm index 5514b477f29d..1721eee56712 100644 --- a/widget/src/cocoa/nsCocoaWindow.mm +++ b/widget/src/cocoa/nsCocoaWindow.mm @@ -1057,6 +1057,24 @@ gfxASurface* nsCocoaWindow::GetThebesSurface() } +NS_IMETHODIMP nsCocoaWindow::BeginSecureKeyboardInput() +{ + nsresult rv = nsBaseWidget::BeginSecureKeyboardInput(); + if (NS_SUCCEEDED(rv)) + ::EnableSecureEventInput(); + return rv; +} + + +NS_IMETHODIMP nsCocoaWindow::EndSecureKeyboardInput() +{ + nsresult rv = nsBaseWidget::EndSecureKeyboardInput(); + if (NS_SUCCEEDED(rv)) + ::DisableSecureEventInput(); + return rv; +} + + @implementation WindowDelegate diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index 1f1d50e13aac..9375df06885b 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -56,6 +56,7 @@ static void debug_RegisterPrefCallbacks(); +static PRBool debug_InSecureKeyboardInputMode = PR_FALSE; #endif #ifdef NOISY_WIDGET_LEAKS @@ -837,6 +838,26 @@ nsBaseWidget::SetIcon(const nsAString&) return NS_OK; } +NS_IMETHODIMP +nsBaseWidget::BeginSecureKeyboardInput() +{ +#ifdef DEBUG + NS_ASSERTION(!debug_InSecureKeyboardInputMode, "Attempting to nest call to BeginSecureKeyboardInput!"); + debug_InSecureKeyboardInputMode = PR_TRUE; +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsBaseWidget::EndSecureKeyboardInput() +{ +#ifdef DEBUG + NS_ASSERTION(debug_InSecureKeyboardInputMode, "Calling EndSecureKeyboardInput when it hasn't been enabled!"); + debug_InSecureKeyboardInputMode = PR_FALSE; +#endif + return NS_OK; +} + /** * Modifies aFile to point at an icon file with the given name and suffix. The * suffix may correspond to a file extension with leading '.' if appropriate. diff --git a/widget/src/xpwidgets/nsBaseWidget.h b/widget/src/xpwidgets/nsBaseWidget.h index 799f119954c0..dfe2fa0f422d 100644 --- a/widget/src/xpwidgets/nsBaseWidget.h +++ b/widget/src/xpwidgets/nsBaseWidget.h @@ -131,8 +131,10 @@ public: NS_IMETHOD GetAttention(PRInt32 aCycleCount); NS_IMETHOD GetLastInputEventTime(PRUint32& aTime); NS_IMETHOD SetIcon(const nsAString &anIconSpec); + NS_IMETHOD BeginSecureKeyboardInput(); + NS_IMETHOD EndSecureKeyboardInput(); virtual void ConvertToDeviceCoordinates(nscoord &aX,nscoord &aY) {} - virtual void FreeNativeData(void * data, PRUint32 aDataType) {}//~~~ + virtual void FreeNativeData(void * data, PRUint32 aDataType) {} protected: