diff --git a/Makefile.am b/Makefile.am index 6307759..8a0c1c9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -75,6 +75,8 @@ openvpn_gui_RESOURCES = \ res/disconnected.ico \ res/openvpn-gui.ico \ res/reconnecting.ico \ + res/eye.ico \ + res/eye-stroke.ico \ res/openvpn-gui.manifest \ res/tileimage.bmp diff --git a/as.c b/as.c index 6028688..9c23648 100644 --- a/as.c +++ b/as.c @@ -248,6 +248,8 @@ CRDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) /* disable OK button by default - not disabled in resources */ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), 0); break; case WM_COMMAND: @@ -255,6 +257,11 @@ CRDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) switch (LOWORD(wParam)) { case ID_EDT_RESPONSE: + if (!(param->flags & FLAG_CR_ECHO)) + { + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + } if (HIWORD(wParam) == EN_UPDATE) { /* enable OK if response is non-empty */ BOOL enableOK = GetWindowTextLength((HWND)lParam); @@ -272,6 +279,11 @@ CRDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) case IDCANCEL: EndDialog(hwndDlg, LOWORD(wParam)); return TRUE; + + case ID_PASSWORD_REVEAL: /* password reveal symbol clicked */ + ChangePasswordVisibility(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + return TRUE; } break; @@ -624,15 +636,19 @@ ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa } /* disable OK button until required data is filled in */ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); - + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_AUTH_PASS), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), 0); break; case WM_COMMAND: type = (server_type_t) GetProp(hwndDlg, cfgProp); switch (LOWORD(wParam)) { - case ID_EDT_AUTH_USER: case ID_EDT_AUTH_PASS: + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_AUTH_PASS), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + /* fall through */ + case ID_EDT_AUTH_USER: case ID_EDT_URL: if (HIWORD(wParam) == EN_UPDATE) { /* enable OK button only if url and username are filled */ @@ -690,6 +706,11 @@ ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa case IDCANCEL: EndDialog(hwndDlg, LOWORD(wParam)); return TRUE; + + case ID_PASSWORD_REVEAL: /* password reveal symbol clicked */ + ChangePasswordVisibility(GetDlgItem(hwndDlg, ID_EDT_AUTH_PASS), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + return TRUE; } break; diff --git a/misc.c b/misc.c index 69363c0..8fe7c9e 100644 --- a/misc.c +++ b/misc.c @@ -1083,3 +1083,64 @@ out: CryptReleaseContext(cp, 0); return retval; } + +/* Setup Password reveal + * Inputs: edit handle to password edit control + * btn handle to the control that toggles the reveal + * wParam action being handled, or 0 for init + */ +void +ResetPasswordReveal(HWND edit, HWND btn, WPARAM wParam) +{ + if (!edit || !btn) + { + return; + } + /* set the password field to be masked as a sane default */ + SendMessage(edit, EM_SETPASSWORDCHAR, (WPARAM)'*', 0); + SendMessage(btn, STM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM)LoadLocalizedSmallIcon(ID_ICO_EYE)); + + /* if password is not masked on init, disable reveal "button" */ + if (wParam == 0 && SendMessage(edit, EM_GETPASSWORDCHAR, 0, 0) == 0) + { + ShowWindow(btn, SW_HIDE); + } + /* on losing focus disable password reveal button */ + else if (HIWORD(wParam) == EN_KILLFOCUS) + { + ShowWindow(btn, SW_HIDE); + } + /* if/when password is cleared enable/re-enable reveal button */ + else if (GetWindowTextLength(edit) == 0) + { + ShowWindow(btn, SW_SHOW); + } +} + +/* Toggle masking of text in password field + * Inputs: edit handle to password edit control + * btn handle to the control that toggles the reveal + * wParam action being handled + */ +void +ChangePasswordVisibility(HWND edit, HWND btn, WPARAM wParam) +{ + if (!edit || !btn) + { + return; + } + if (HIWORD(wParam) == STN_CLICKED) + { + if (SendMessage(edit, EM_GETPASSWORDCHAR, 0, 0) == 0) /* currently visible */ + { + SendMessage(edit, EM_SETPASSWORDCHAR, (WPARAM)'*', 0); + SendMessage(btn, STM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM)LoadLocalizedSmallIcon(ID_ICO_EYE)); + } + else + { + SendMessage(edit, EM_SETPASSWORDCHAR, 0, 0); + SendMessage(btn, STM_SETIMAGE, (WPARAM) IMAGE_ICON, (LPARAM)LoadLocalizedSmallIcon(ID_ICO_EYESTROKE)); + } + InvalidateRect(edit, NULL, TRUE); /* without this the control doesn't seem to get redrawn promptly */ + } +} diff --git a/misc.h b/misc.h index 1315d5a..2e5f093 100644 --- a/misc.h +++ b/misc.h @@ -156,4 +156,7 @@ bool OVPNMsgWait(DWORD timeout, HWND hdlg); bool GetRandomPassword(char *buf, size_t len); +void ResetPasswordReveal(HWND edit, HWND btn, WPARAM wParam); +void ChangePasswordVisibility(HWND edit, HWND btn, WPARAM wParam); + #endif diff --git a/openvpn-gui-res.h b/openvpn-gui-res.h index fcc45dd..149bac2 100644 --- a/openvpn-gui-res.h +++ b/openvpn-gui-res.h @@ -27,6 +27,8 @@ #define ID_ICO_CONNECTED 91 #define ID_ICO_CONNECTING 92 #define ID_ICO_DISCONNECTED 93 +#define ID_ICO_EYE 94 +#define ID_ICO_EYESTROKE 95 /* About Dialog */ #define ID_DLG_ABOUT 100 @@ -39,6 +41,7 @@ #define ID_DLG_PASSPHRASE 150 #define ID_EDT_PASSPHRASE 151 #define ID_LTEXT_PASSWORD 152 +#define ID_PASSWORD_REVEAL 153 /* Status Dialog */ #define ID_DLG_STATUS 160 diff --git a/openvpn.c b/openvpn.c index febdd49..5c2e4f5 100644 --- a/openvpn.c +++ b/openvpn.c @@ -575,7 +575,8 @@ UserAuthDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) ForceForegroundWindow(hwndDlg); else SetForegroundWindow(hwndDlg); - + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_AUTH_PASS), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), 0); break; case WM_LBUTTONDOWN: @@ -590,8 +591,11 @@ UserAuthDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) param = (auth_param_t *) GetProp(hwndDlg, cfgProp); switch (LOWORD(wParam)) { - case ID_EDT_AUTH_USER: case ID_EDT_AUTH_PASS: + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_AUTH_PASS), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + /* fall through */ + case ID_EDT_AUTH_USER: case ID_EDT_AUTH_CHALLENGE: if (HIWORD(wParam) == EN_UPDATE) { @@ -654,6 +658,11 @@ UserAuthDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) EndDialog(hwndDlg, LOWORD(wParam)); StopOpenVPN(param->c); return TRUE; + + case ID_PASSWORD_REVEAL: /* password reveal symbol clicked */ + ChangePasswordVisibility(GetDlgItem(hwndDlg, ID_EDT_AUTH_PASS), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + return TRUE; } break; @@ -771,6 +780,8 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) /* disable OK button until response is filled-in */ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); } + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), 0); break; @@ -781,6 +792,11 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) switch (LOWORD(wParam)) { case ID_EDT_RESPONSE: + if (!(param->flags & FLAG_CR_ECHO)) + { + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + } if (HIWORD(wParam) == EN_UPDATE) { /* enable OK if response is non-empty */ @@ -854,6 +870,11 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) EndDialog(hwndDlg, LOWORD(wParam)); StopOpenVPN(param->c); return TRUE; + + case ID_PASSWORD_REVEAL: /* password reveal symbol clicked */ + ChangePasswordVisibility(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + return TRUE; } break; @@ -926,6 +947,8 @@ PrivKeyPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) /* disable OK button by default - not disabled in resources */ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_PASSPHRASE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), 0); break; case WM_COMMAND: @@ -944,6 +967,8 @@ PrivKeyPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) break; case ID_EDT_PASSPHRASE: + ResetPasswordReveal(GetDlgItem(hwndDlg, ID_EDT_PASSPHRASE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); if (HIWORD(wParam) == EN_UPDATE) { /* enable OK if response is non-empty */ @@ -975,6 +1000,11 @@ PrivKeyPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) EndDialog(hwndDlg, LOWORD(wParam)); StopOpenVPN (c); return TRUE; + + case ID_PASSWORD_REVEAL: /* password reveal symbol clicked */ + ChangePasswordVisibility(GetDlgItem(hwndDlg, ID_EDT_PASSPHRASE), + GetDlgItem(hwndDlg, ID_PASSWORD_REVEAL), wParam); + return TRUE; } break; diff --git a/plap/Makefile.am b/plap/Makefile.am index b9a4320..50fe432 100644 --- a/plap/Makefile.am +++ b/plap/Makefile.am @@ -67,6 +67,8 @@ libopenvpn_plap_la_RESOURCES = \ $(top_srcdir)/res/disconnected.ico \ $(top_srcdir)/res/openvpn-gui.ico \ $(top_srcdir)/res/reconnecting.ico \ + $(top_srcdir)/res/eye.ico \ + $(top_srcdir)/res/eye-stroke.ico \ openvpn-plap-res.rc \ openvpn-plap.manifest diff --git a/plap/openvpn-plap-res.rc b/plap/openvpn-plap-res.rc index 1dc7726..86e7885 100644 --- a/plap/openvpn-plap-res.rc +++ b/plap/openvpn-plap-res.rc @@ -39,6 +39,8 @@ ID_ICO_APP ICON DISCARDABLE "../res/openvpn-gui.ico" ID_ICO_CONNECTED ICON DISCARDABLE "../res/connected.ico" ID_ICO_CONNECTING ICON DISCARDABLE "../res/connecting.ico" ID_ICO_DISCONNECTED ICON DISCARDABLE "../res/disconnected.ico" +ID_ICO_EYE ICON DISCARDABLE "../res/eye.ico" +ID_ICO_EYESTROKE ICON DISCARDABLE "../res/eye-stroke.ico" IDB_TILE_IMAGE BITMAP DISCARDABLE "../res/tileimage.bmp" diff --git a/res/eye-stroke.ico b/res/eye-stroke.ico new file mode 100644 index 0000000..74d23ac Binary files /dev/null and b/res/eye-stroke.ico differ diff --git a/res/eye.ico b/res/eye.ico new file mode 100644 index 0000000..7857fe4 Binary files /dev/null and b/res/eye.ico differ diff --git a/res/openvpn-gui-res-en.rc b/res/openvpn-gui-res-en.rc index 42117ef..adae2af 100644 --- a/res/openvpn-gui-res-en.rc +++ b/res/openvpn-gui-res-en.rc @@ -30,6 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT BEGIN LTEXT "Enter &Password:", 201, 6, 6, 100, 10 EDITTEXT ID_EDT_PASSPHRASE, 6, 17, 107, 12, ES_PASSWORD | ES_AUTOHSCROLL + ICON ID_ICO_EYE, ID_PASSWORD_REVEAL, 126, 18, 14, 14, SS_ICON|SS_NOTIFY|SS_REALSIZEIMAGE CHECKBOX "&Save password", ID_CHK_SAVE_PASS, 6, 33, 100, 10 PUSHBUTTON "&OK", IDOK, 20, 49, 50, 14 PUSHBUTTON "&Cancel", IDCANCEL, 90, 49, 50, 14 @@ -37,7 +38,7 @@ BEGIN END /* Auth Username/Password Dialog */ -ID_DLG_AUTH DIALOGEX 6, 18, 160, 95 +ID_DLG_AUTH DIALOGEX 6, 18, 180, 95 STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER | DS_SETFOREGROUND EXSTYLE WS_EX_TOPMOST FONT 8, "Microsoft Sans Serif" @@ -47,6 +48,7 @@ BEGIN EDITTEXT ID_EDT_AUTH_USER, 60, 6, 94, 12, ES_AUTOHSCROLL LTEXT "&Password:", ID_LTEXT_PASSWORD, 6, 26, 50, 10 EDITTEXT ID_EDT_AUTH_PASS, 60, 23, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL + ICON ID_ICO_EYE, ID_PASSWORD_REVEAL, 156, 24, 14, 14, SS_ICON|SS_NOTIFY|SS_REALSIZEIMAGE CHECKBOX "&Save password", ID_CHK_SAVE_PASS, 6, 42, 100, 10 PUSHBUTTON "&OK", IDOK, 20, 58, 50, 14, BS_DEFPUSHBUTTON | WS_TABSTOP | WS_DISABLED PUSHBUTTON "&Cancel", IDCANCEL, 90, 58, 52, 14 @@ -54,7 +56,7 @@ BEGIN END /* Auth Username/Password/Challenge Dialog */ -ID_DLG_AUTH_CHALLENGE DIALOG 6, 18, 160, 129 +ID_DLG_AUTH_CHALLENGE DIALOGEX 6, 18, 180, 129 STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER | DS_SETFOREGROUND EXSTYLE WS_EX_TOPMOST CAPTION "OpenVPN – User Authentication" @@ -65,6 +67,7 @@ BEGIN EDITTEXT ID_EDT_AUTH_USER, 60, 6, 94, 12, ES_AUTOHSCROLL LTEXT "&Password:", ID_LTEXT_PASSWORD, 6, 26, 50, 10 EDITTEXT ID_EDT_AUTH_PASS, 60, 23, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL + ICON ID_ICO_EYE, ID_PASSWORD_REVEAL, 156, 24, 14, 14, SS_ICON|SS_NOTIFY|SS_REALSIZEIMAGE LTEXT "&Response:", ID_LTEXT_RESPONSE, 6, 60, 50, 10 LTEXT "", ID_TXT_AUTH_CHALLENGE, 6, 43, 148, 10 EDITTEXT ID_EDT_AUTH_CHALLENGE, 60, 57, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL @@ -75,7 +78,7 @@ BEGIN END /* Challenge Response Dialog */ -ID_DLG_CHALLENGE_RESPONSE DIALOG 6, 18, 212, 72 +ID_DLG_CHALLENGE_RESPONSE DIALOGEX 6, 18, 212, 72 STYLE WS_SIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER | DS_SETFOREGROUND EXSTYLE WS_EX_TOPMOST CAPTION "OpenVPN – Challenge Response" @@ -85,6 +88,7 @@ BEGIN LTEXT "", ID_TXT_DESCRIPTION, 6, 9, 400, 20 LTEXT "&Response:", ID_LTEXT_RESPONSE, 6, 30, 50, 10 EDITTEXT ID_EDT_RESPONSE, 60, 27, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL + ICON ID_ICO_EYE, ID_PASSWORD_REVEAL, 156, 28, 14, 14, SS_ICON|SS_NOTIFY|SS_REALSIZEIMAGE PUSHBUTTON "&OK", IDOK, 20, 51, 50, 14, BS_PUSHBUTTON | WS_TABSTOP PUSHBUTTON "&Cancel", IDCANCEL, 90, 51, 52, 14 END @@ -265,7 +269,7 @@ https://openvpn.net/", ID_LTEXT_ABOUT4, 8, 106, 240, 64 END /* Proxy Authentication Dialog */ -ID_DLG_PROXY_AUTH DIALOG 29, 23, 154, 65 +ID_DLG_PROXY_AUTH DIALOGEX 29, 23, 170, 65 STYLE DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | DS_CENTER EXSTYLE WS_EX_TOPMOST CAPTION "OpenVPN – Proxy Authentication" @@ -276,11 +280,12 @@ BEGIN EDITTEXT ID_EDT_PROXY_USER, 49, 5, 94, 12, ES_AUTOHSCROLL LTEXT "&Password:", 202, 9, 26, 38, 10 EDITTEXT ID_EDT_PROXY_PASS, 49, 23, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL + ICON ID_ICO_EYE, ID_PASSWORD_REVEAL, 145, 24, 14, 14, SS_ICON|SS_NOTIFY|SS_REALSIZEIMAGE PUSHBUTTON "&OK", IDOK, 58, 43, 40, 14, BS_PUSHBUTTON | WS_TABSTOP | WS_DISABLED END /* URL Profile Import Dialog */ -ID_DLG_URL_PROFILE_IMPORT DIALOG 6, 18, 249, 95 +ID_DLG_URL_PROFILE_IMPORT DIALOGEX 6, 18, 249, 95 STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER | DS_SETFOREGROUND CAPTION "Import Profile from Access Server" FONT 8, "Microsoft Sans Serif" @@ -292,6 +297,7 @@ BEGIN EDITTEXT ID_EDT_AUTH_USER, 60, 23, 94, 12, ES_AUTOHSCROLL LTEXT "&Password:", ID_LTEXT_PASSWORD, 6, 42, 50, 10 EDITTEXT ID_EDT_AUTH_PASS, 60, 40, 94, 12, ES_PASSWORD | ES_AUTOHSCROLL + ICON ID_ICO_EYE, ID_PASSWORD_REVEAL, 156, 41, 14, 14, SS_ICON|SS_NOTIFY|SS_REALSIZEIMAGE AUTOCHECKBOX "&Autologin", ID_CHK_AUTOLOGIN, 6, 59, 100, 10 PUSHBUTTON "&OK", IDOK, 20, 76, 50, 14, BS_PUSHBUTTON | WS_TABSTOP | WS_DISABLED PUSHBUTTON "&Cancel", IDCANCEL, 90, 76, 52, 14 diff --git a/res/openvpn-gui-res.rc b/res/openvpn-gui-res.rc index c4fbc31..a310acb 100644 --- a/res/openvpn-gui-res.rc +++ b/res/openvpn-gui-res.rc @@ -38,6 +38,8 @@ ID_ICO_APP ICON DISCARDABLE "openvpn-gui.ico" ID_ICO_CONNECTED ICON DISCARDABLE "connected.ico" ID_ICO_CONNECTING ICON DISCARDABLE "connecting.ico" ID_ICO_DISCONNECTED ICON DISCARDABLE "disconnected.ico" +ID_ICO_EYE ICON DISCARDABLE "eye.ico" +ID_ICO_EYESTROKE ICON DISCARDABLE "eye-stroke.ico" #ifdef ENABLE_OVPN3 #define ADVANCED_DIALOG_HEIGHT 320