1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013-2023 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 // SettingGitCredential.cpp : implementation file
23 #include "TortoiseProc.h"
24 #include "SettingGitCredential.h"
26 #include "GitAdminDir.h"
27 #include "MessageBox.h"
30 #include "PathUtils.h"
32 namespace SimpleCredentialType
34 static int Advanced
= -1;
36 static int LocalWincred
= -1;
37 static int LocalWinstore
= -1;
38 static int LocalGCM
= -1;
39 static int LocalGCMCore
= -1;
40 static int GlobalWincred
= -1;
41 static int GlobalWinstore
= -1;
42 static int GlobalGCM
= -1;
43 static int GlobalGCMCore
= -1;
44 static int SystemWincred
= -1;
45 static int SystemGCM
= -1;
46 static int SystemGCMCore
= -1;
51 static int Local
= -1;
52 static int Global
= -1;
53 static int System
= -1;
56 // CSettingGitCredential dialog
58 IMPLEMENT_DYNAMIC(CSettingGitCredential
, ISettingsPropPage
)
60 CSettingGitCredential::CSettingGitCredential()
61 : ISettingsPropPage(CSettingGitCredential::IDD
)
62 , m_bUseHttpPath(FALSE
)
63 , m_iSimpleStoredValue(-2)
67 CSettingGitCredential::~CSettingGitCredential()
71 void CSettingGitCredential::DoDataExchange(CDataExchange
* pDX
)
73 CPropertyPage::DoDataExchange(pDX
);
74 DDX_Control(pDX
, IDC_COMBO_SIMPLECREDENTIAL
, m_ctrlSimpleCredential
);
75 DDX_Control(pDX
, IDC_LIST_REMOTE
, m_ctrlUrlList
);
76 DDX_Text(pDX
, IDC_EDIT_URL
, m_strUrl
);
77 DDX_Text(pDX
, IDC_COMBO_HELPER
, m_strHelper
);
78 DDX_Text(pDX
, IDC_EDIT_USERNAME
, m_strUsername
);
79 DDX_Check(pDX
, IDC_CHECK_USEHTTPPATH
, m_bUseHttpPath
);
80 DDX_Control(pDX
, IDC_COMBO_CONFIGTYPE
, m_ctrlConfigType
);
84 BEGIN_MESSAGE_MAP(CSettingGitCredential
, CPropertyPage
)
85 ON_CBN_SELCHANGE(IDC_COMBO_SIMPLECREDENTIAL
, &CSettingGitCredential::OnCbnSelchangeComboSimplecredential
)
86 ON_BN_CLICKED(IDC_BUTTON_ADD
, &CSettingGitCredential::OnBnClickedButtonAdd
)
87 ON_LBN_SELCHANGE(IDC_LIST_REMOTE
, &CSettingGitCredential::OnLbnSelchangeListUrl
)
88 ON_CBN_SELCHANGE(IDC_COMBO_CONFIGTYPE
, &CSettingGitCredential::OnCbnSelchangeComboConfigType
)
89 ON_EN_CHANGE(IDC_EDIT_URL
, &CSettingGitCredential::OnEnChangeEditUrl
)
90 ON_CBN_EDITCHANGE(IDC_COMBO_HELPER
, &CSettingGitCredential::OnEnChangeEditHelper
)
91 ON_CBN_SELCHANGE(IDC_COMBO_HELPER
, &CSettingGitCredential::OnEnChangeEditHelper
)
92 ON_EN_CHANGE(IDC_EDIT_USERNAME
, &CSettingGitCredential::OnEnChangeEditUsername
)
93 ON_BN_CLICKED(IDC_CHECK_USEHTTPPATH
, &CSettingGitCredential::OnBnClickedCheckUsehttppath
)
94 ON_BN_CLICKED(IDC_BUTTON_REMOVE
, &CSettingGitCredential::OnBnClickedButtonRemove
)
95 ON_BN_CLICKED(IDC_OPENSETTINGSELEVATED
, &CSettingGitCredential::OnBnClickedOpensettingselevated
)
96 ON_BN_CLICKED(IDC_WINDOWSCREDMGR
, &CSettingGitCredential::OnBnClickedWindowscredmgr
)
99 static CStringA
RegexEscape(CStringA str
)
102 for (int i
= 0; i
< str
.GetLength(); ++i
)
107 case '\\': case '*': case '+': case '?': case '|':
108 case '{': case '[': case '(': case ')': case '^':
109 case '$': case '.': case '#': case ' ':
110 result
.AppendChar('\\');
111 result
.AppendChar(c
);
113 case '\t': result
.Append("\\t"); break;
114 case '\n': result
.Append("\\n"); break;
115 case '\r': result
.Append("\\r"); break;
116 case '\f': result
.Append("\\f"); break;
117 default: result
.AppendChar(c
); break;
124 BOOL
CSettingGitCredential::OnInitDialog()
126 ISettingsPropPage::OnInitDialog();
128 AdjustControlSize(IDC_CHECK_USEHTTPPATH
);
130 bool hasLocal
= GitAdminDir::HasAdminDir(g_Git
.m_CurrentDir
);
132 m_ctrlUrlList
.ResetContent();
134 AddConfigType(ConfigType::Local
, CString(MAKEINTRESOURCE(IDS_SETTINGS_LOCAL
)), hasLocal
);
135 AddConfigType(ConfigType::Global
, CString(MAKEINTRESOURCE(IDS_SETTINGS_GLOBAL
)));
136 AddConfigType(ConfigType::System
, CString(MAKEINTRESOURCE(IDS_SETTINGS_SYSTEM
)));
137 m_ctrlConfigType
.SetCurSel(0);
140 static_cast<CComboBox
*>(GetDlgItem(IDC_COMBO_HELPER
))->AddString(L
"wincred");
141 if (WinstoreExists())
142 static_cast<CComboBox
*>(GetDlgItem(IDC_COMBO_HELPER
))->AddString(GetWinstorePath());
144 static_cast<CComboBox
*>(GetDlgItem(IDC_COMBO_HELPER
))->AddString(L
"manager");
146 static_cast<CComboBox
*>(GetDlgItem(IDC_COMBO_HELPER
))->AddString(L
"manager-core");
149 m_iSimpleStoredValue
= m_ctrlSimpleCredential
.GetCurSel();
151 if (!CAppUtils::IsAdminLogin())
153 reinterpret_cast<CButton
*>(GetDlgItem(IDC_OPENSETTINGSELEVATED
))->SetShield(TRUE
);
154 GetDlgItem(IDC_OPENSETTINGSELEVATED
)->EnableWindow(TRUE
);
155 GetDlgItem(IDC_OPENSETTINGSELEVATED
)->ShowWindow(SW_SHOW
);
156 GetDlgItem(IDC_STATICELEVATIONNEEDED
)->ShowWindow(SW_SHOW
);
159 EnableAdvancedOptions();
164 // CSettingGitCredential message handlers
166 void CSettingGitCredential::OnCbnSelchangeComboSimplecredential()
168 EnableAdvancedOptions();
170 m_ChangedMask
|= CREDENTIAL_SIMPLE
;
173 void CSettingGitCredential::OnBnClickedButtonAdd()
177 if (m_strHelper
.Trim().IsEmpty())
179 CMessageBox::Show(GetSafeHwnd(), IDS_GITCREDENTIAL_HELPEREMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
183 m_ChangedMask
= CREDENTIAL_URL
| CREDENTIAL_HELPER
| CREDENTIAL_USERNAME
| CREDENTIAL_USEHTTPPATH
;
184 int sel
= m_ctrlConfigType
.GetCurSel();
185 CString prefix
= sel
== ConfigType::System
? L
"S" : sel
== ConfigType::Global
? L
"G" : L
"L";
187 if (!m_strUrl
.IsEmpty())
188 text
.Format(L
"%s:%s", static_cast<LPCWSTR
>(prefix
), static_cast<LPCWSTR
>(m_strUrl
));
191 if (IsUrlExist(text
))
194 msg
.Format(IDS_GITCREDENTIAL_OVERWRITEHELPER
, static_cast<LPCWSTR
>(m_strUrl
));
195 if (CMessageBox::Show(GetSafeHwnd(), msg
, L
"TortoiseGit", MB_YESNO
| MB_ICONQUESTION
| MB_DEFBUTTON2
) == IDYES
)
196 m_ChangedMask
&= ~CREDENTIAL_URL
;
202 if (m_strUsername
.IsEmpty())
203 m_ChangedMask
&= ~CREDENTIAL_USERNAME
;
205 m_ChangedMask
&= ~CREDENTIAL_USEHTTPPATH
;
211 void CSettingGitCredential::EnableAdvancedOptions()
213 BOOL enable
= m_ctrlSimpleCredential
.GetCurSel() == SimpleCredentialType::Advanced
? TRUE
: FALSE
;
214 GetDlgItem(IDC_LIST_REMOTE
)->EnableWindow(enable
);
215 GetDlgItem(IDC_EDIT_URL
)->EnableWindow(enable
);
216 GetDlgItem(IDC_COMBO_HELPER
)->EnableWindow(enable
);
217 GetDlgItem(IDC_EDIT_USERNAME
)->EnableWindow(enable
);
218 GetDlgItem(IDC_COMBO_CONFIGTYPE
)->EnableWindow(enable
);
219 GetDlgItem(IDC_CHECK_USEHTTPPATH
)->EnableWindow(enable
);
221 bool canModifySystem
= CAppUtils::IsAdminLogin() || (m_ctrlConfigType
.GetCurSel() != ConfigType::System
);
222 GetDlgItem(IDC_BUTTON_ADD
)->EnableWindow(enable
&& canModifySystem
);
223 GetDlgItem(IDC_BUTTON_REMOVE
)->EnableWindow(enable
&& canModifySystem
);
226 BOOL
CSettingGitCredential::IsUrlExist(const CString
& text
)
229 for(int i
= 0; i
< m_ctrlUrlList
.GetCount();i
++)
231 m_ctrlUrlList
.GetText(i
, str
);
238 void CSettingGitCredential::OnLbnSelchangeListUrl()
242 if (m_ChangedMask
& CREDENTIAL_ADVANCED_MASK
)
244 if (CMessageBox::Show(GetSafeHwnd(), IDS_GITCREDENTIAL_SAVEHELPER
, IDS_APPNAME
, 1, IDI_QUESTION
, IDS_SAVEBUTTON
, IDS_DISCARDBUTTON
) == 1)
247 m_ChangedMask
&= ~CREDENTIAL_ADVANCED_MASK
;
252 int index
= m_ctrlUrlList
.GetCurSel();
258 m_bUseHttpPath
= FALSE
;
264 m_ctrlUrlList
.GetText(index
, text
);
265 int pos
= text
.Find(L
':');
266 CString prefix
= pos
>= 0 ? text
.Left(pos
) : text
.Left(1);
267 m_ctrlConfigType
.SetCurSel((prefix
== L
"S" || prefix
== L
"P") ? ConfigType::System
: prefix
== L
"X" ? ConfigType::Global
: prefix
== L
"G" ? ConfigType::Global
: ConfigType::Local
);
268 m_strUrl
= pos
>= 0 ? text
.Mid(pos
+ 1) : CString();
270 m_strHelper
= Load(L
"helper");
271 m_strUsername
= Load(L
"username");
272 m_bUseHttpPath
= Load(L
"useHttpPath") == L
"true" ? TRUE
: FALSE
;
274 bool canModifySystem
= CAppUtils::IsAdminLogin() || (m_ctrlConfigType
.GetCurSel() != ConfigType::System
);
275 GetDlgItem(IDC_BUTTON_ADD
)->EnableWindow(canModifySystem
? TRUE
: FALSE
);
276 GetDlgItem(IDC_BUTTON_REMOVE
)->EnableWindow(canModifySystem
? TRUE
: FALSE
);
277 this->UpdateData(FALSE
);
280 void CSettingGitCredential::OnCbnSelchangeComboConfigType()
282 if (!CAppUtils::IsAdminLogin())
284 int sel
= m_ctrlConfigType
.GetCurSel();
285 GetDlgItem(IDC_BUTTON_ADD
)->EnableWindow(sel
!= ConfigType::System
);
286 GetDlgItem(IDC_BUTTON_REMOVE
)->EnableWindow(sel
!= ConfigType::System
);
287 if (sel
== ConfigType::System
)
293 void CSettingGitCredential::OnEnChangeEditUrl()
295 m_ChangedMask
|= CREDENTIAL_URL
;
299 void CSettingGitCredential::OnEnChangeEditHelper()
301 m_ChangedMask
|= CREDENTIAL_HELPER
;
304 if (!m_strHelper
.IsEmpty())
306 else if (!m_ChangedMask
)
310 void CSettingGitCredential::OnEnChangeEditUsername()
312 m_ChangedMask
|= CREDENTIAL_USERNAME
;
316 void CSettingGitCredential::OnBnClickedCheckUsehttppath()
318 m_ChangedMask
|= CREDENTIAL_USEHTTPPATH
;
322 void CSettingGitCredential::AddConfigType(int &index
, CString text
, bool add
)
325 index
= m_ctrlConfigType
.AddString(text
);
328 void CSettingGitCredential::AddSimpleCredential(int &index
, CString text
, bool add
)
331 index
= m_ctrlSimpleCredential
.AddString(text
);
334 void CSettingGitCredential::FillSimpleList(bool anySystem
, bool systemWincred
, bool systemGCM
, bool systemGCMCore
)
336 ATLASSERT(SimpleCredentialType::Advanced
== -1);
338 bool hasLocal
= GitAdminDir::HasAdminDir(g_Git
.m_CurrentDir
);
339 bool isAdmin
= CAppUtils::IsAdminLogin();
341 AddSimpleCredential(SimpleCredentialType::Advanced
, CString(MAKEINTRESOURCE(IDS_ADVANCED
)));
342 if (isAdmin
|| !anySystem
)
343 AddSimpleCredential(SimpleCredentialType::None
, CString(MAKEINTRESOURCE(IDS_NONE
)));
344 if (isAdmin
|| !(systemWincred
|| systemGCM
|| systemGCMCore
|| anySystem
))
346 AddSimpleCredential(SimpleCredentialType::LocalWincred
, CString(MAKEINTRESOURCE(IDS_LOCAL_WINCRED
)), hasLocal
&& WincredExists());
347 AddSimpleCredential(SimpleCredentialType::LocalWinstore
, CString(MAKEINTRESOURCE(IDS_LOCAL_WINSTORE
)), hasLocal
&& WinstoreExists());
348 AddSimpleCredential(SimpleCredentialType::LocalGCM
, CString(MAKEINTRESOURCE(IDS_LOCAL_GCM
)), hasLocal
&& GCMExists());
349 AddSimpleCredential(SimpleCredentialType::LocalGCMCore
, CString(MAKEINTRESOURCE(IDS_LOCAL_GCMCORE
)), hasLocal
&& GCMCoreExists());
350 AddSimpleCredential(SimpleCredentialType::GlobalWincred
, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINCRED
)), WincredExists());
351 AddSimpleCredential(SimpleCredentialType::GlobalWinstore
, CString(MAKEINTRESOURCE(IDS_GLOBAL_WINSTORE
)), WinstoreExists());
352 AddSimpleCredential(SimpleCredentialType::GlobalGCM
, CString(MAKEINTRESOURCE(IDS_GLOBAL_GCM
)), GCMExists());
353 AddSimpleCredential(SimpleCredentialType::GlobalGCMCore
, CString(MAKEINTRESOURCE(IDS_GLOBAL_GCMCORE
)), GCMCoreExists());
355 if (isAdmin
|| systemWincred
)
356 AddSimpleCredential(SimpleCredentialType::SystemWincred
, CString(MAKEINTRESOURCE(IDS_SYSTEM_WINCRED
)), WincredExists());
357 if (isAdmin
|| systemGCM
)
358 AddSimpleCredential(SimpleCredentialType::SystemGCM
, CString(MAKEINTRESOURCE(IDS_SYSTEM_GCM
)), GCMExists());
359 if (isAdmin
|| systemGCMCore
)
360 AddSimpleCredential(SimpleCredentialType::SystemGCMCore
, CString(MAKEINTRESOURCE(IDS_SYSTEM_GCMCORE
)), GCMCoreExists());
363 void CSettingGitCredential::LoadList()
365 CAutoConfig
config(true);
366 CAutoRepository
repo(g_Git
.GetGitRepository());
367 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL
, repo
, FALSE
);
368 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL
, repo
, FALSE
);
369 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG
, repo
, FALSE
);
370 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM
, repo
, FALSE
);
372 STRING_VECTOR defaultList
, urlList
;
373 git_config_foreach_match(config
, "credential\\.helper", GetCredentialDefaultUrlCallback
, &defaultList
);
374 git_config_foreach_match(config
, "credential\\..*\\.helper", GetCredentialUrlCallback
, &urlList
);
375 STRING_VECTOR anyList
;
376 git_config_foreach_match(config
, "credential\\..*", GetCredentialAnyEntryCallback
, &anyList
);
378 for (size_t i
= 0; i
< defaultList
.size(); ++i
)
379 m_ctrlUrlList
.AddString(defaultList
[i
]);
380 for (size_t i
= 0; i
< urlList
.size(); ++i
)
381 m_ctrlUrlList
.AddString(urlList
[i
]);
385 FillSimpleList(false, false, false, false);
386 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::None
);
389 if (anyList
.size() > 1)
391 bool hasSystemType
= false;
392 for (size_t i
= 0; i
< anyList
.size(); ++i
)
395 CString prefix
= anyList
[i
].Tokenize(L
"\n", pos
);
396 if (prefix
== L
"S" || prefix
== L
"P")
398 hasSystemType
= true;
402 FillSimpleList(hasSystemType
, false, false, false);
403 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::Advanced
);
408 CString prefix
= anyList
[0].Tokenize(L
"\n", pos
);
409 CString key
= anyList
[0].Tokenize(L
"\n", pos
);
410 CString value
= anyList
[0].Tokenize(L
"\n", pos
);
411 if (key
!= L
"credential.helper")
413 FillSimpleList(true, false, false, false);
414 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::Advanced
);
418 CString winstore
= GetWinstorePath();
421 if (value
== L
"wincred")
423 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::LocalWincred
);
426 else if (value
== winstore
)
428 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::LocalWinstore
);
431 else if (value
== L
"manager")
433 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::LocalGCM
);
436 else if (value
== L
"manager-core")
438 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::LocalGCMCore
);
443 if (prefix
== L
"G" || prefix
== L
"X")
445 if (value
== L
"wincred")
447 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::GlobalWincred
);
450 else if (value
== winstore
)
452 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::GlobalWinstore
);
455 else if (value
== L
"manager")
457 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::GlobalGCM
);
460 else if (value
== L
"manager-core")
462 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::GlobalGCMCore
);
467 if (prefix
== L
"S" || prefix
== L
"P")
469 if (value
== L
"wincred")
471 FillSimpleList(true, true, false, false);
472 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::SystemWincred
);
475 else if (value
== L
"manager")
477 FillSimpleList(true, false, true, false);
478 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::SystemGCM
);
481 else if (value
== L
"manager-core")
483 FillSimpleList(true, false, false, true);
484 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::SystemGCMCore
);
489 FillSimpleList((prefix
== L
"S" || prefix
== L
"P"), false, false, false);
490 m_ctrlSimpleCredential
.SetCurSel(SimpleCredentialType::Advanced
);
493 CString
CSettingGitCredential::Load(CString key
)
497 if (m_strUrl
.IsEmpty())
498 cmd
.Format(L
"credential.%s", static_cast<LPCWSTR
>(key
));
500 cmd
.Format(L
"credential.%s.%s", static_cast<LPCWSTR
>(m_strUrl
), static_cast<LPCWSTR
>(key
));
502 CAutoConfig
config(true);
503 CAutoRepository
repo(g_Git
.GetGitRepository());
504 int sel
= m_ctrlConfigType
.GetCurSel();
505 if (sel
== ConfigType::Local
)
506 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL
, repo
, FALSE
);
507 else if (sel
== ConfigType::Global
)
509 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL
, repo
, FALSE
);
510 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG
, repo
, FALSE
);
512 else if (sel
== ConfigType::System
)
513 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM
, repo
, FALSE
);
515 CStringA cmdA
= CUnicodeUtils::GetUTF8(cmd
);
517 git_config_entry
* entry
;
518 if (!git_config_get_entry(&entry
, config
, cmdA
))
519 valueA
= CStringA(entry
->value
);
520 git_config_entry_free(entry
);
522 return CUnicodeUtils::GetUnicode(valueA
);
525 void CSettingGitCredential::Save(CString key
, CString value
)
529 if (m_strUrl
.IsEmpty())
530 cmd
.Format(L
"credential.%s", static_cast<LPCWSTR
>(key
));
532 cmd
.Format(L
"credential.%s.%s", static_cast<LPCWSTR
>(m_strUrl
), static_cast<LPCWSTR
>(key
));
534 int sel
= m_ctrlConfigType
.GetCurSel();
535 CONFIG_TYPE configLevel
= sel
== ConfigType::System
? CONFIG_SYSTEM
: sel
== ConfigType::Global
? CONFIG_GLOBAL
: CONFIG_LOCAL
;
537 bool old
= g_Git
.m_IsUseGitDLL
;
538 // workaround gitdll bug
539 // TODO: switch to libgit2
540 g_Git
.m_IsUseGitDLL
= false;
541 if (g_Git
.SetConfigValue(cmd
, value
, configLevel
))
544 msg
.FormatMessage(IDS_PROC_SAVECONFIGFAILED
, static_cast<LPCWSTR
>(cmd
), static_cast<LPCWSTR
>(value
));
545 CMessageBox::Show(GetSafeHwnd(), msg
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
549 if (g_Git
.UnsetConfigValue(cmd
, configLevel
))
552 msg
.FormatMessage(IDS_PROC_SAVECONFIGFAILED
, static_cast<LPCWSTR
>(cmd
), static_cast<LPCWSTR
>(value
));
553 CMessageBox::Show(GetSafeHwnd(), msg
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
556 g_Git
.m_IsUseGitDLL
= old
;
559 int CSettingGitCredential::DeleteOtherKeys(int type
)
562 if (type
== SimpleCredentialType::LocalWincred
)
563 match
= L
"L\ncredential.helper\nwincred";
564 else if (type
== SimpleCredentialType::LocalWinstore
)
565 match
= L
"L\ncredential.helper\n" + GetWinstorePath();
566 else if (type
== SimpleCredentialType::LocalGCM
)
567 match
= L
"L\ncredential.helper\nmanager";
568 else if (type
== SimpleCredentialType::LocalGCMCore
)
569 match
= L
"L\ncredential.helper\nmanager-core";
570 else if (type
== SimpleCredentialType::GlobalWincred
)
571 match
= L
"G\ncredential.helper\nwincred";
572 else if (type
== SimpleCredentialType::GlobalWinstore
)
573 match
= L
"G\ncredential.helper\n" + GetWinstorePath();
574 else if (type
== SimpleCredentialType::GlobalGCM
)
575 match
= L
"G\ncredential.helper\nmanager";
576 else if (type
== SimpleCredentialType::GlobalGCMCore
)
577 match
= L
"G\ncredential.helper\nmanager-core";
578 else if (type
== SimpleCredentialType::SystemWincred
)
579 match
= L
"S\ncredential.helper\nwincred";
580 else if (type
== SimpleCredentialType::SystemGCM
)
581 match
= L
"S\ncredential.helper\nmanager";
582 else if (type
== SimpleCredentialType::SystemGCMCore
)
583 match
= L
"S\ncredential.helper\nmanager-core";
585 CAutoConfig
config(true);
586 CAutoRepository repo
= g_Git
.GetGitRepository();
587 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL
, repo
, FALSE
);
588 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL
, repo
, FALSE
);
589 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG
, repo
, FALSE
);
590 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM
, repo
, FALSE
);
593 git_config_foreach_match(config
, "credential\\..*", GetCredentialAnyEntryCallback
, &list
);
594 for (size_t i
= 0; i
< list
.size(); ++i
)
597 CString prefix
= list
[i
].Tokenize(L
"\n", pos
);
598 if ((prefix
== L
"S" || prefix
== L
"P") && list
[i
] != match
&& !CAppUtils::IsAdminLogin())
600 if (MessageBox(L
"Cannot modify a system config without proper rights.\nDiscard changes?", L
"TortoiseGit", MB_ICONERROR
| MB_YESNO
) == IDYES
)
606 // workaround gitdll bug
607 // TODO: switch to libgit2
608 bool old
= g_Git
.m_IsUseGitDLL
;
609 g_Git
.m_IsUseGitDLL
= false;
610 SCOPE_EXIT
{ g_Git
.m_IsUseGitDLL
= old
; };
611 for (size_t i
= 0; i
< list
.size(); ++i
)
613 if (list
[i
] == match
)
617 CString prefix
= list
[i
].Tokenize(L
"\n", pos
);
618 CString key
= list
[i
].Tokenize(L
"\n", pos
);
619 CONFIG_TYPE configLevel
= (prefix
== L
"S" || prefix
== L
"P") ? CONFIG_SYSTEM
: prefix
== L
"G" || prefix
== L
"X" ? CONFIG_GLOBAL
: CONFIG_LOCAL
;
620 if (g_Git
.UnsetConfigValue(key
, configLevel
))
623 msg
.FormatMessage(IDS_PROC_SAVECONFIGFAILED
, static_cast<LPCWSTR
>(key
), L
"");
624 CMessageBox::Show(GetSafeHwnd(), msg
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
632 bool CSettingGitCredential::SaveSimpleCredential(int type
)
634 CONFIG_TYPE configLevel
;
636 if (type
== SimpleCredentialType::LocalWincred
)
638 configLevel
= CONFIG_LOCAL
;
641 else if (type
== SimpleCredentialType::LocalWinstore
)
643 configLevel
= CONFIG_LOCAL
;
644 value
= GetWinstorePath();
646 else if (type
== SimpleCredentialType::LocalGCM
)
648 configLevel
= CONFIG_LOCAL
;
651 else if (type
== SimpleCredentialType::LocalGCMCore
)
653 configLevel
= CONFIG_LOCAL
;
654 value
= L
"manager-core";
656 else if (type
== SimpleCredentialType::GlobalWincred
)
658 configLevel
= CONFIG_GLOBAL
;
661 else if (type
== SimpleCredentialType::GlobalWinstore
)
663 configLevel
= CONFIG_GLOBAL
;
664 value
= GetWinstorePath();
666 else if (type
== SimpleCredentialType::GlobalGCM
)
668 configLevel
= CONFIG_GLOBAL
;
671 else if (type
== SimpleCredentialType::GlobalGCMCore
)
673 configLevel
= CONFIG_GLOBAL
;
674 value
= L
"manager-core";
676 else if (type
== SimpleCredentialType::SystemWincred
)
678 configLevel
= CONFIG_SYSTEM
;
681 else if (type
== SimpleCredentialType::SystemGCM
)
683 configLevel
= CONFIG_SYSTEM
;
686 else if (type
== SimpleCredentialType::SystemGCMCore
)
688 configLevel
= CONFIG_SYSTEM
;
689 value
= L
"manager-core";
694 // workaround gitdll bug
695 // TODO: switch to libgit2
696 bool old
= g_Git
.m_IsUseGitDLL
;
697 g_Git
.m_IsUseGitDLL
= false;
698 if (g_Git
.SetConfigValue(L
"credential.helper", value
, configLevel
))
701 msg
.FormatMessage(IDS_PROC_SAVECONFIGFAILED
, L
"credential.helper", static_cast<LPCWSTR
>(value
));
702 CMessageBox::Show(GetSafeHwnd(), msg
, L
"TortoiseGit", MB_OK
| MB_ICONERROR
);
705 g_Git
.m_IsUseGitDLL
= old
;
709 BOOL
CSettingGitCredential::OnApply()
712 return ISettingsPropPage::OnApply();
715 return ISettingsPropPage::OnApply();
720 bool CSettingGitCredential::SaveSettings()
725 int type
= m_ctrlSimpleCredential
.GetCurSel();
726 if ((type
== SimpleCredentialType::SystemWincred
|| type
== SimpleCredentialType::SystemGCM
|| type
== SimpleCredentialType::SystemGCMCore
) && !CAppUtils::IsAdminLogin())
728 if (m_iSimpleStoredValue
== type
)
730 if (DeleteOtherKeys(type
) > 0)
736 if (MessageBox(L
"Cannot modify a system config without proper rights.\nDiscard changes?", L
"TortoiseGit", MB_ICONERROR
| MB_YESNO
) == IDYES
)
740 if (type
!= SimpleCredentialType::Advanced
)
742 if (!SaveSimpleCredential(type
))
745 if (DeleteOtherKeys(type
) > 0)
751 int sel
= m_ctrlConfigType
.GetCurSel();
752 if (sel
== ConfigType::System
&& !CAppUtils::IsAdminLogin())
754 if (MessageBox(L
"Cannot modify a system config without proper rights.\nDiscard changes?", L
"TortoiseGit", MB_ICONERROR
| MB_YESNO
) == IDYES
)
759 if (m_ChangedMask
& CREDENTIAL_URL
)
762 if (m_strHelper
.IsEmpty())
764 CMessageBox::Show(GetSafeHwnd(), IDS_GITCREDENTIAL_HELPEREMPTY
, IDS_APPNAME
, MB_OK
| MB_ICONERROR
);
767 m_strUrl
.Replace(L
'\\', L
'/');
768 m_strHelper
.Replace(L
'\\', L
'/');
770 Save(L
"helper", m_strHelper
);
771 m_ChangedMask
&= ~CREDENTIAL_HELPER
;
773 sel
= m_ctrlConfigType
.GetCurSel();
774 CString prefix
= sel
== ConfigType::System
? L
"S" : sel
== ConfigType::Global
? L
"G" : L
"L";
776 if (!m_strUrl
.IsEmpty())
777 text
.Format(L
"%s:%s", static_cast<LPCWSTR
>(prefix
), static_cast<LPCWSTR
>(m_strUrl
));
780 int urlIndex
= m_ctrlUrlList
.AddString(text
);
781 m_ctrlUrlList
.SetCurSel(urlIndex
);
782 GetDlgItem(IDC_BUTTON_ADD
)->EnableWindow(TRUE
);
785 if (m_ChangedMask
& CREDENTIAL_HELPER
)
787 m_strHelper
.Replace(L
'\\', L
'/');
788 Save(L
"helper", m_strHelper
);
791 if (m_ChangedMask
& CREDENTIAL_USERNAME
)
792 Save(L
"username", m_strUsername
);
794 if (m_ChangedMask
& CREDENTIAL_USEHTTPPATH
)
795 Save(L
"useHttpPath", m_bUseHttpPath
? L
"true" : L
"");
797 m_ChangedMask
&= ~CREDENTIAL_ADVANCED_MASK
;
804 void CSettingGitCredential::OnBnClickedButtonRemove()
806 int index
= m_ctrlUrlList
.GetCurSel();
810 m_ctrlUrlList
.GetText(index
, str
);
812 msg
.Format(IDS_WARN_REMOVE
, static_cast<LPCWSTR
>(str
));
813 if (CMessageBox::Show(GetSafeHwnd(), msg
, L
"TortoiseGit", MB_YESNO
| MB_ICONQUESTION
) == IDYES
)
815 CAutoConfig
config(true);
816 CAutoRepository
repo(g_Git
.GetGitRepository());
817 int pos
= str
.Find(L
':');
818 CString prefix
= pos
>= 0 ? str
.Left(pos
) : str
;
819 CString url
= pos
>= 0 ? str
.Mid(pos
+ 1) : CString();
820 CONFIG_TYPE configLevel
= CONFIG_LOCAL
;
825 configLevel
= CONFIG_LOCAL
;
826 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitLocalConfig()), GIT_CONFIG_LEVEL_LOCAL
, repo
, FALSE
);
832 configLevel
= CONFIG_GLOBAL
;
833 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalConfig()), GIT_CONFIG_LEVEL_GLOBAL
, repo
, FALSE
);
834 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitGlobalXDGConfig()), GIT_CONFIG_LEVEL_XDG
, repo
, FALSE
);
840 if (!CAppUtils::IsAdminLogin())
842 MessageBox(L
"Cannot modify a system config without proper rights.", L
"TortoiseGit", MB_ICONERROR
);
845 configLevel
= CONFIG_SYSTEM
;
846 git_config_add_file_ondisk(config
, CGit::GetGitPathStringA(g_Git
.GetGitSystemConfig()), GIT_CONFIG_LEVEL_SYSTEM
, repo
, FALSE
);
852 CStringA urlA
= CUnicodeUtils::GetUTF8(url
);
853 CStringA pattern
= urlA
.IsEmpty() ? CStringA("^credential\\.[^.]+$") : ("credential\\." + RegexEscape(urlA
) + "\\..*");
854 git_config_foreach_match(config
, pattern
, GetCredentialEntryCallback
, &list
);
855 for (size_t i
= 0; i
< list
.size(); ++i
)
856 g_Git
.UnsetConfigValue(list
[i
], configLevel
);
857 m_ctrlUrlList
.DeleteString(index
);
858 OnLbnSelchangeListUrl();
863 void CSettingGitCredential::OnBnClickedOpensettingselevated()
866 sCmd
.Format(L
"/command:settings /page:gitcredential /path:\"%s\"", static_cast<LPCWSTR
>(g_Git
.m_CurrentDir
));
867 CAppUtils::RunTortoiseGitProc(sCmd
, true);
870 void CSettingGitCredential::OnBnClickedWindowscredmgr()
872 // https://stackoverflow.com/a/31782500/3906760
873 if (CComHeapPtr
<WCHAR
> wcharPtr
; SUCCEEDED(SHGetKnownFolderPath(FOLDERID_System
, 0, nullptr, &wcharPtr
)))
875 CString folder
{ static_cast<LPCWSTR
>(wcharPtr
) };
876 CAppUtils::LaunchApplication(folder
+ L
"\\rundll32.exe keymgr.dll,KRShowKeyMgr", CAppUtils::LaunchApplicationFlags());