From fd2f4c2ec115babdc5245f0c33315f0269a6a742 Mon Sep 17 00:00:00 2001 From: Sup Yut Sum Date: Fri, 8 Mar 2013 22:27:05 +0800 Subject: [PATCH] Add simplified credential helper selection Signed-off-by: Sup Yut Sum Signed-off-by: Sven Strickroth --- Languages/Tortoise.pot | 73 +++++- src/Resources/TortoiseProcENG.rc | 12 + src/TortoiseProc/Settings/SettingGitCredential.cpp | 273 +++++++++++++++++++++ src/TortoiseProc/Settings/SettingGitCredential.h | 4 + src/TortoiseProc/resource.h | 9 +- 5 files changed, 368 insertions(+), 3 deletions(-) diff --git a/Languages/Tortoise.pot b/Languages/Tortoise.pot index 1abcd2e44..6a104f269 100644 --- a/Languages/Tortoise.pot +++ b/Languages/Tortoise.pot @@ -2626,6 +2626,10 @@ msgstr "" msgid "Config" msgstr "" +#. Resource IDs: (65535) +msgid "Config type:" +msgstr "" + #. Resource IDs: (236) msgid "Configure Hook Scripts" msgstr "" @@ -2982,6 +2986,14 @@ msgstr "" msgid "Creating pull-request..." msgstr "" +#. Resource IDs: (89) +msgid "Credential helper must not be empty." +msgstr "" + +#. Resource IDs: (65535) +msgid "Credential helper:" +msgstr "" + #. Resource IDs: (65535) msgid "Credits:" msgstr "" @@ -3193,8 +3205,8 @@ msgstr "" msgid "Deleting" msgstr "" -#. Resource IDs: (1397) -msgid "Deleting remote refs..." +#. Resource IDs: (88) +msgid "Deleting remote refs ..." msgstr "" #. Resource IDs: (1002) @@ -4337,10 +4349,18 @@ msgstr "" msgid "Git.exe Path:" msgstr "" +#. Resource IDs: (4591) +msgid "Git::Credential" +msgstr "" + #. Resource IDs: (4570) msgid "Git::Remote" msgstr "" +#. Resource IDs: (89) +msgid "Global" +msgstr "" + #. Resource IDs: (155) msgid "Go To Line" msgstr "" @@ -4429,6 +4449,14 @@ msgstr "" msgid "Help Keyboard" msgstr "" +#. Resource IDs: (65535) +msgid "Helper:" +msgstr "" + +#. Resource IDs: (65535) +msgid "Helpers:" +msgstr "" + #. Resource IDs: (16974) msgid "Hex" msgstr "" @@ -5090,6 +5118,10 @@ msgstr "" msgid "Loading..." msgstr "" +#. Resource IDs: (89) +msgid "Local" +msgstr "" + #. Resource IDs: (65535) msgid "Local Branch" msgstr "" @@ -7927,6 +7959,10 @@ msgstr "" msgid "Sync..." msgstr "" +#. Resource IDs: (89) +msgid "System" +msgstr "" + #. Resource IDs: (1556) msgid "System &sounds" msgstr "" @@ -8022,6 +8058,15 @@ msgstr "" msgid "The commit message must not be empty." msgstr "" +#. Resource IDs: (89) +#, c-format +msgid "The credential helper URL \"%s\" already exists.\nDo you want to overwrite it?" +msgstr "" + +#. Resource IDs: (89) +msgid "The credential helper was changed.\nDo you want to save now or discard changes?" +msgstr "" + #. Resource IDs: (603) msgid "The current working tree is not clean.\nDo you want to stash the changes?" msgstr "" @@ -8679,6 +8724,10 @@ msgstr "" msgid "Use Blocks" msgstr "" +#. Resource IDs: (1761) +msgid "Use HTTP path component" +msgstr "" + #. Resource IDs: (1482) msgid "Use MAPI" msgstr "" @@ -9495,6 +9544,26 @@ msgstr "" msgid "week" msgstr "" +#. Resource IDs: (89) +msgid "wincred - all Windows users" +msgstr "" + +#. Resource IDs: (88) +msgid "wincred - current Windows user" +msgstr "" + +#. Resource IDs: (88) +msgid "wincred - this repository only" +msgstr "" + +#. Resource IDs: (88) +msgid "winstore - current Windows user" +msgstr "" + +#. Resource IDs: (88) +msgid "winstore - this repository only" +msgstr "" + #. Resource IDs: (245) msgid "year" msgstr "" diff --git a/src/Resources/TortoiseProcENG.rc b/src/Resources/TortoiseProcENG.rc index b840d7b73..a49834cb8 100644 --- a/src/Resources/TortoiseProcENG.rc +++ b/src/Resources/TortoiseProcENG.rc @@ -1784,6 +1784,8 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Git::Credential" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN + LTEXT "Credential helper:",IDC_STATIC,7,7,58,8 + COMBOBOX IDC_COMBO_SIMPLECREDENTIAL,91,7,150,12,CBS_DROPDOWNLIST | WS_TABSTOP LTEXT "Helpers:",IDC_STATIC,7,24,76,8 LISTBOX IDC_LIST_REMOTE,7,37,83,173,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP LTEXT "Config type:",IDC_STATIC,97,38,40,8 @@ -3080,6 +3082,11 @@ BEGIN IDS_GITCREDENTIAL_SAVEHELPER "The credential helper was changed.\nDo you want to save now or discard changes?" IDS_GITCREDENTIAL_DELETEHELPER "Do you really want to remove ""%s""?" + IDS_ADVANCED "Advanced" + IDS_LOCAL_WINCRED "wincred - this repository only" + IDS_LOCAL_WINSTORE "winstore - this repository only" + IDS_GLOBAL_WINCRED "wincred - current Windows user" + IDS_GLOBAL_WINSTORE "winstore - current Windows user" END STRINGTABLE @@ -4065,6 +4072,11 @@ BEGIN "You have selected %d items to show the diff for.\nFor every of these items a new instance of the diff viewer will be started.\nDo you really want to show the diff for so many items at once?" END +STRINGTABLE +BEGIN + IDS_SYSTEM_WINCRED "wincred - all Windows users" +END + #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/src/TortoiseProc/Settings/SettingGitCredential.cpp b/src/TortoiseProc/Settings/SettingGitCredential.cpp index 3c5a24f28..69e3e5d9d 100644 --- a/src/TortoiseProc/Settings/SettingGitCredential.cpp +++ b/src/TortoiseProc/Settings/SettingGitCredential.cpp @@ -29,6 +29,28 @@ #include "git.h" #include "PathUtils.h" +namespace SimpleCredentialType +{ + static int Advanced; + static int None; + static int LocalWincred; + static int LocalWinstore; + static int GlobalWincred; + static int GlobalWinstore; + static int SystemWincred; + + static void Init() + { + Advanced = -1; + None = -1; + LocalWincred = -1; + LocalWinstore = -1; + GlobalWincred = -1; + GlobalWinstore = -1; + SystemWincred = -1; + } +} + namespace ConfigType { static int Local; @@ -66,6 +88,7 @@ CSettingGitCredential::~CSettingGitCredential() void CSettingGitCredential::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); + DDX_Control(pDX, IDC_COMBO_SIMPLECREDENTIAL, m_ctrlSimpleCredential); DDX_Control(pDX, IDC_LIST_REMOTE, m_ctrlUrlList); DDX_Text(pDX, IDC_EDIT_URL, m_strUrl); DDX_Text(pDX, IDC_COMBO_HELPER, m_strHelper); @@ -76,6 +99,7 @@ void CSettingGitCredential::DoDataExchange(CDataExchange* pDX) BEGIN_MESSAGE_MAP(CSettingGitCredential, CPropertyPage) + ON_CBN_SELCHANGE(IDC_COMBO_SIMPLECREDENTIAL, &CSettingGitCredential::OnCbnSelchangeComboSimplecredential) ON_BN_CLICKED(IDC_BUTTON_ADD, &CSettingGitCredential::OnBnClickedButtonAdd) ON_LBN_SELCHANGE(IDC_LIST_REMOTE, &CSettingGitCredential::OnLbnSelchangeListUrl) ON_CBN_SELCHANGE(IDC_COMBO_CONFIGTYPE, &CSettingGitCredential::OnCbnSelchangeComboConfigType) @@ -168,13 +192,30 @@ BOOL CSettingGitCredential::OnInitDialog() if (WinstoreExists()) ((CComboBox*) GetDlgItem(IDC_COMBO_HELPER))->AddString(GetWinstorePath()); + SimpleCredentialType::Init(); + AddSimpleCredential(SimpleCredentialType::Advanced, CString(MAKEINTRESOURCE(IDS_ADVANCED))); + AddSimpleCredential(SimpleCredentialType::None, CString(MAKEINTRESOURCE(IDS_NONE))); + AddSimpleCredential(SimpleCredentialType::LocalWincred, CString(MAKEINTRESOURCE(IDS_LOCAL_WINCRED)), hasLocal && WincredExists()); + AddSimpleCredential(SimpleCredentialType::LocalWinstore, CString(MAKEINTRESOURCE(IDS_LOCAL_WINSTORE)), hasLocal && WinstoreExists()); + AddSimpleCredential(SimpleCredentialType::GlobalWincred, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINCRED)), WincredExists()); + AddSimpleCredential(SimpleCredentialType::GlobalWinstore, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINSTORE)), WinstoreExists()); + AddSimpleCredential(SimpleCredentialType::SystemWincred, CString(MAKEINTRESOURCE(IDS_SYSTEM_WINCRED)), WincredExists()); + LoadList(); + EnableAdvancedOptions(); + UpdateData(FALSE); return TRUE; } // CSettingGitCredential message handlers +void CSettingGitCredential::OnCbnSelchangeComboSimplecredential() +{ + EnableAdvancedOptions(); + SetModified(); +} + void CSettingGitCredential::OnBnClickedButtonAdd() { UpdateData(); @@ -213,6 +254,19 @@ void CSettingGitCredential::OnBnClickedButtonAdd() OnApply(); } +void CSettingGitCredential::EnableAdvancedOptions() +{ + BOOL enable = m_ctrlSimpleCredential.GetCurSel() == SimpleCredentialType::Advanced ? TRUE : FALSE; + GetDlgItem(IDC_LIST_REMOTE)->EnableWindow(enable); + GetDlgItem(IDC_EDIT_URL)->EnableWindow(enable); + GetDlgItem(IDC_COMBO_HELPER)->EnableWindow(enable); + GetDlgItem(IDC_EDIT_USERNAME)->EnableWindow(enable); + GetDlgItem(IDC_COMBO_CONFIGTYPE)->EnableWindow(enable); + GetDlgItem(IDC_CHECK_USEHTTPPATH)->EnableWindow(enable); + GetDlgItem(IDC_BUTTON_ADD)->EnableWindow(enable); + GetDlgItem(IDC_BUTTON_REMOVE)->EnableWindow(enable); +} + BOOL CSettingGitCredential::IsUrlExist(CString &text) { CString str; @@ -328,12 +382,29 @@ static int GetCredentialEntryCallback(const git_config_entry *entry, void *paylo return 0; } +static int GetCredentialAnyEntryCallback(const git_config_entry *entry, void *payload) +{ + CString name = CUnicodeUtils::GetUnicode(entry->name); + CString value = CUnicodeUtils::GetUnicode(entry->value); + CString display = entry->level == 1 ? _T("S") : entry->level == 2 ? _T("X") : entry->level == 3 ? _T("G") : _T("L"); + CString text; + text.Format(_T("%s\n%s\n%s"), display, name, value); + ((STRING_VECTOR *)payload)->push_back(text); + return 0; +} + void CSettingGitCredential::AddConfigType(int &index, CString text, bool add) { if (add) index = m_ctrlConfigType.AddString(text); } +void CSettingGitCredential::AddSimpleCredential(int &index, CString text, bool add) +{ + if (add) + index = m_ctrlSimpleCredential.AddString(text); +} + void CSettingGitCredential::LoadList() { git_config * config; @@ -354,12 +425,75 @@ void CSettingGitCredential::LoadList() STRING_VECTOR defaultList, urlList; git_config_foreach_match(config, "credential\\.helper", GetCredentialDefaultUrlCallback, &defaultList); git_config_foreach_match(config, "credential\\..*\\.helper", GetCredentialUrlCallback, &urlList); + STRING_VECTOR anyList; + git_config_foreach_match(config, "credential\\..*", GetCredentialAnyEntryCallback, &anyList); git_config_free(config); for (int i = 0; i < defaultList.size(); ++i) m_ctrlUrlList.AddString(defaultList[i]); for (int i = 0; i < urlList.size(); ++i) m_ctrlUrlList.AddString(urlList[i]); + + if (anyList.empty()) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::None); + return; + } + if (anyList.size() > 1) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced); + return; + } + + int pos = 0; + CString prefix = anyList[0].Tokenize(_T("\n"), pos); + CString key = anyList[0].Tokenize(_T("\n"), pos); + CString value = anyList[0].Tokenize(_T("\n"), pos); + if (key != _T("credential.helper")) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced); + return; + } + + CString winstore = GetWinstorePath(); + if (prefix == _T("L")) + { + if (value == _T("wincred")) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::LocalWincred); + return; + } + else if (value == winstore) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::LocalWinstore); + return; + } + } + + if (prefix == _T("G") || prefix == _T("X")) + { + if (value == _T("wincred")) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::GlobalWincred); + return; + } + else if (value == winstore) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::GlobalWinstore); + return; + } + } + + if (prefix == _T("S")) + { + if (value == _T("wincred")) + { + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::SystemWincred); + return; + } + } + + m_ctrlSimpleCredential.SetCurSel(SimpleCredentialType::Advanced); } CString CSettingGitCredential::Load(CString key) @@ -441,11 +575,150 @@ void CSettingGitCredential::Save(CString key, CString value) g_Git.m_IsUseGitDLL = old; } +static int DeleteOtherKeys(int type) +{ + CString match; + if (type == SimpleCredentialType::LocalWincred) + match = _T("L\ncredential.helper\nwincred"); + else if (type == SimpleCredentialType::LocalWinstore) + match = _T("L\ncredential.helper\n") + GetWinstorePath(); + else if (type == SimpleCredentialType::GlobalWincred) + match = _T("G\ncredential.helper\nwincred"); + else if (type == SimpleCredentialType::GlobalWinstore) + match = _T("G\ncredential.helper\n") + GetWinstorePath(); + else if (type == SimpleCredentialType::SystemWincred) + match = _T("S\ncredential.helper\nwincred"); + + git_config * config; + git_config_new(&config); + CStringA projectConfigA = CUnicodeUtils::GetUTF8(g_Git.GetGitLocalConfig()); + git_config_add_file_ondisk(config, projectConfigA.GetBuffer(), 4, FALSE); + projectConfigA.ReleaseBuffer(); + CStringA globalConfigA = CUnicodeUtils::GetUTF8(g_Git.GetGitGlobalConfig()); + git_config_add_file_ondisk(config, globalConfigA.GetBuffer(), 3, FALSE); + globalConfigA.ReleaseBuffer(); + CStringA globalXDGConfigA = CUnicodeUtils::GetUTF8(g_Git.GetGitGlobalXDGConfig()); + git_config_add_file_ondisk(config, globalXDGConfigA.GetBuffer(), 2, FALSE); + globalXDGConfigA.ReleaseBuffer(); + CStringA systemConfigA = CUnicodeUtils::GetUTF8(g_Git.GetGitSystemConfig()); + git_config_add_file_ondisk(config, systemConfigA.GetBuffer(), 1, FALSE); + systemConfigA.ReleaseBuffer(); + + STRING_VECTOR list; + git_config_foreach_match(config, "credential\\..*", GetCredentialAnyEntryCallback, &list); + for (size_t i = 0; i < list.size(); ++i) + { + int pos = 0; + CString prefix = list[i].Tokenize(_T("\n"), pos); + if (prefix == _T("S") && !CAppUtils::IsAdminLogin()) + { + RunUAC(); + return -1; + } + } + + int result = 0; + // workaround gitdll bug + // TODO: switch to libgit2 + bool old = g_Git.m_IsUseGitDLL; + g_Git.m_IsUseGitDLL = false; + for (size_t i = 0; i < list.size(); ++i) + { + if (list[i] != match) + { + int pos = 0; + CString prefix = list[i].Tokenize(_T("\n"), pos); + CString key = list[i].Tokenize(_T("\n"), pos); + CONFIG_TYPE configLevel = prefix == _T("S") ? CONFIG_SYSTEM : prefix == _T("G") || prefix == _T("X") ? CONFIG_GLOBAL : CONFIG_LOCAL; + if (g_Git.UnsetConfigValue(key, configLevel, CP_UTF8, &g_Git.m_CurrentDir)) + { + CString msg; + msg.Format(IDS_PROC_SAVECONFIGFAILED, key, _T("")); + CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR); + result = 1; + break; + } + } + } + g_Git.m_IsUseGitDLL = old; + + return result; +} + +bool SaveSimpleCredential(int type) +{ + CONFIG_TYPE configLevel; + CString value; + if (type == SimpleCredentialType::LocalWincred) + { + configLevel = CONFIG_LOCAL; + value = _T("wincred"); + } + else if (type == SimpleCredentialType::LocalWinstore) + { + configLevel = CONFIG_LOCAL; + value = GetWinstorePath(); + } + else if (type == SimpleCredentialType::GlobalWincred) + { + configLevel = CONFIG_GLOBAL; + value = _T("wincred"); + } + else if (type == SimpleCredentialType::GlobalWinstore) + { + configLevel = CONFIG_GLOBAL; + value = GetWinstorePath(); + } + else if (type == SimpleCredentialType::SystemWincred) + { + configLevel = CONFIG_SYSTEM; + value = _T("wincred"); + } + else + { + return true; + } + + // workaround gitdll bug + // TODO: switch to libgit2 + bool old = g_Git.m_IsUseGitDLL; + g_Git.m_IsUseGitDLL = false; + if (g_Git.SetConfigValue(_T("credential.helper"), value, configLevel, CP_UTF8, &g_Git.m_CurrentDir)) + { + CString msg; + msg.Format(IDS_PROC_SAVECONFIGFAILED, _T("credential.helper"), value); + CMessageBox::Show(NULL, msg, _T("TortoiseGit"), MB_OK | MB_ICONERROR); + return false; + } + g_Git.m_IsUseGitDLL = old; + return true; +} + BOOL CSettingGitCredential::OnApply() { CWaitCursor wait; UpdateData(); + int type = m_ctrlSimpleCredential.GetCurSel(); + if (type == SimpleCredentialType::SystemWincred && !CAppUtils::IsAdminLogin()) + { + RunUAC(); + EndDialog(0); + return FALSE; + } + if (type != SimpleCredentialType::Advanced) + { + if (!SaveSimpleCredential(type)) + return FALSE; + + if (!DeleteOtherKeys(type)) + { + EndDialog(0); + return FALSE; + } + return ISettingsPropPage::OnApply(); + } + int sel = m_ctrlConfigType.GetCurSel(); if (sel == ConfigType::System && !CAppUtils::IsAdminLogin()) { diff --git a/src/TortoiseProc/Settings/SettingGitCredential.h b/src/TortoiseProc/Settings/SettingGitCredential.h index 79950af0a..13a9173a5 100644 --- a/src/TortoiseProc/Settings/SettingGitCredential.h +++ b/src/TortoiseProc/Settings/SettingGitCredential.h @@ -46,6 +46,7 @@ protected: DECLARE_MESSAGE_MAP() + afx_msg void OnCbnSelchangeComboSimplecredential(); afx_msg void OnBnClickedButtonAdd(); afx_msg void OnLbnSelchangeListUrl(); afx_msg void OnCbnSelchangeComboConfigType(); @@ -58,9 +59,11 @@ protected: BOOL OnInitDialog(); BOOL OnApply(); + void EnableAdvancedOptions(); BOOL IsUrlExist(CString &text); void AddConfigType(int &index, CString text, bool add = true); + void AddSimpleCredential(int &index, CString text, bool add = true); void LoadList(); CString Load(CString key); void Save(CString key, CString value); @@ -69,6 +72,7 @@ protected: CString m_cmdPath; + CComboBox m_ctrlSimpleCredential; CListBox m_ctrlUrlList; CComboBox m_ctrlConfigType; CString m_strUrl; diff --git a/src/TortoiseProc/resource.h b/src/TortoiseProc/resource.h index d7decd2e5..d8b5d4e77 100644 --- a/src/TortoiseProc/resource.h +++ b/src/TortoiseProc/resource.h @@ -877,12 +877,18 @@ #define IDS_LOG_CHRONOLOGICALREVERSEDORDER 1395 #define IDS_TORTOISEGITDEFAULT 1396 #define IDS_DELETING_REMOTE_REFS 1397 +#define IDS_ADVANCED 1398 +#define IDS_LOCAL_WINCRED 1399 #define IDS_WARN_FOLDERNOTEXIST 1400 +#define IDS_LOCAL_WINSTORE 1401 +#define IDS_GLOBAL_WINCRED 1402 +#define IDS_GLOBAL_WINSTORE 1403 #define IDS_WARN_GITINIT_FOLDERNOTEMPTY 1404 #define IDS_WARN_WARNING 1405 #define IDC_SELECTFILESONCOMMIT 1405 #define IDS_WARN_NOTE 1406 #define IDS_WARN_NOVALIDPATH 1407 +#define IDS_SYSTEM_WINCRED 1408 #define IDC_PROXYLABEL1 1409 #define IDC_PROXYLABEL2 1410 #define IDC_PROXYLABEL3 1411 @@ -1267,6 +1273,7 @@ #define IDC_STATIC_ORDER 1750 #define IDS_DLGTITLE_ADD_MERGE_TOOL 1751 #define IDC_COMBOBOXEX_ORDERING 1751 +#define IDC_COMBO_SIMPLECREDENTIAL 1752 #define IDS_DLGTITLE_EDIT_DIFF_TOOL 1752 #define IDS_DLGTITLE_EDIT_MERGE_TOOL 1753 #define IDS_DLGTITLE_ADV_DIFF 1754 @@ -1723,7 +1730,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 347 #define _APS_NEXT_COMMAND_VALUE 32860 -#define _APS_NEXT_CONTROL_VALUE 1752 +#define _APS_NEXT_CONTROL_VALUE 1753 #define _APS_NEXT_SYMED_VALUE 201 #endif #endif -- 2.11.4.GIT