Skip to content

Commit e0218ac

Browse files
committed
wincred: do not write creds if nothing has changed
Do no bother writing out credentials if there is already an existing credential for the same account, with the same secret/password value.
1 parent a7e81cf commit e0218ac

File tree

2 files changed

+22
-16
lines changed

2 files changed

+22
-16
lines changed

src/shared/Core/Interop/Windows/Native/Advapi32.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Runtime.InteropServices;
3+
using System.Text;
34
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
45

56
namespace GitCredentialManager.Interop.Windows.Native
@@ -93,5 +94,16 @@ public struct Win32Credential
9394
public string TargetAlias;
9495
[MarshalAs(UnmanagedType.LPWStr)]
9596
public string UserName;
97+
98+
public string GetCredentialBlobAsString()
99+
{
100+
if (CredentialBlobSize != 0 && CredentialBlob != IntPtr.Zero)
101+
{
102+
byte[] passwordBytes = InteropUtils.ToByteArray(CredentialBlob, CredentialBlobSize);
103+
return Encoding.Unicode.GetString(passwordBytes);
104+
}
105+
106+
return null;
107+
}
96108
}
97109
}

src/shared/Core/Interop/Windows/WindowsCredentialManager.cs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ public class WindowsCredentialManager : ICredentialStore
1313

1414
private readonly string _namespace;
1515

16-
#region Constructors
17-
1816
/// <summary>
1917
/// Open the Windows Credential Manager vault for the current user.
2018
/// </summary>
@@ -26,10 +24,6 @@ public WindowsCredentialManager(string @namespace = null)
2624
_namespace = @namespace;
2725
}
2826

29-
#endregion
30-
31-
#region ICredentialStore
32-
3327
public ICredential Get(string service, string account)
3428
{
3529
return Enumerate(service, account).FirstOrDefault();
@@ -66,6 +60,15 @@ public void AddOrUpdate(string service, string account, string secret)
6660
// Create new entry with the account in the target name
6761
targetName = CreateTargetName(service, account);
6862
}
63+
else
64+
{
65+
// No need to write out credential if the account and secret/password are the same
66+
string existingSecret = existingCred.GetCredentialBlobAsString();
67+
if (StringComparer.Ordinal.Equals(existingSecret, secret))
68+
{
69+
return;
70+
}
71+
}
6972
}
7073

7174
byte[] secretBytes = Encoding.Unicode.GetBytes(secret);
@@ -129,8 +132,6 @@ public bool Remove(string service, string account)
129132
return false;
130133
}
131134

132-
#endregion
133-
134135
/// <summary>
135136
/// Check if we can persist credentials to for the current process and logon session.
136137
/// </summary>
@@ -205,14 +206,7 @@ private IEnumerable<WindowsCredential> Enumerate(string service, string account)
205206

206207
private WindowsCredential CreateCredentialFromStructure(Win32Credential credential)
207208
{
208-
string password = null;
209-
if (credential.CredentialBlobSize != 0 && credential.CredentialBlob != IntPtr.Zero)
210-
{
211-
byte[] passwordBytes = InteropUtils.ToByteArray(
212-
credential.CredentialBlob,
213-
credential.CredentialBlobSize);
214-
password = Encoding.Unicode.GetString(passwordBytes);
215-
}
209+
string password = credential.GetCredentialBlobAsString();
216210

217211
// Recover the target name we gave from the internal (raw) target name
218212
string targetName = credential.TargetName.TrimUntilIndexOf(TargetNameLegacyGenericPrefix);

0 commit comments

Comments
 (0)