Skip to content

Commit 11a5d7c

Browse files
authored
Merge pull request #22 from mjcheetham/tracing-tweaks
Fix a few problems with tracing secrets and missing vital error codes
2 parents c4c5054 + 38695fb commit 11a5d7c

File tree

5 files changed

+69
-7
lines changed

5 files changed

+69
-7
lines changed

common/src/Microsoft.Git.CredentialManager/Application.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT license.
33
using System;
4+
using System.ComponentModel;
45
using System.Threading.Tasks;
56
using Microsoft.Git.CredentialManager.Commands;
7+
using Microsoft.Git.CredentialManager.SecureStorage;
68

79
namespace Microsoft.Git.CredentialManager
810
{
@@ -75,12 +77,23 @@ protected override void Dispose(bool disposing)
7577
base.Dispose(disposing);
7678
}
7779

78-
protected bool WriteException(Exception e)
80+
protected bool WriteException(Exception ex)
7981
{
80-
Context.StdError.WriteLine("fatal: {0}", e.Message);
81-
if (e.InnerException != null)
82+
// Try and use a nicer format for some well-known exception types
83+
switch (ex)
8284
{
83-
Context.StdError.WriteLine("fatal: {0}", e.InnerException.Message);
85+
case Win32Exception w32Ex:
86+
Context.StdError.WriteLine("fatal: {0} [0x{1:x}]", w32Ex.Message, w32Ex.NativeErrorCode);
87+
break;
88+
default:
89+
Context.StdError.WriteLine("fatal: {0}", ex.Message);
90+
break;
91+
}
92+
93+
// Recurse to print all inner exceptions
94+
if (!(ex.InnerException is null))
95+
{
96+
WriteException(ex.InnerException);
8497
}
8598

8699
return true;

common/src/Microsoft.Git.CredentialManager/Commands/Command.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public override async Task ExecuteAsync(ICommandContext context, string[] args)
6565

6666
// Determine the host provider
6767
context.Trace.WriteLine("Detecting host provider for input:");
68-
context.Trace.WriteDictionary(inputDict);
68+
context.Trace.WriteDictionarySecrets(inputDict, new []{ "password" }, StringComparer.OrdinalIgnoreCase);
6969
IHostProvider provider = _hostProviderRegistry.GetProvider(input);
7070
context.Trace.WriteLine($"Host provider '{provider.Name}' was selected.");
7171

common/src/Microsoft.Git.CredentialManager/SecureStorage/NativeMethods.Windows.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public static void ThrowIfError(int error, string defaultErrorMessage = null)
4141
default:
4242
// The Win32Exception constructor will automatically get the human-readable
4343
// message for the error code.
44-
throw new Win32Exception(error, defaultErrorMessage);
44+
throw new Exception(defaultErrorMessage, new Win32Exception(error));
4545
}
4646
}
4747

common/src/Microsoft.Git.CredentialManager/Trace.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ void WriteDictionary<TKey, TValue>(
6565
[System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0,
6666
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "");
6767

68+
/// <summary>
69+
/// Write the contents of a dictionary that contains sensitive information to the trace writer.
70+
/// <para/>
71+
/// Calls <see cref="object.ToString"/> on all keys and values, except keys specified as secret.
72+
/// </summary>
73+
/// <param name="dictionary">The dictionary to write.</param>
74+
/// <param name="secretKeys">Dictionary keys that contain secrets/sensitive information.</param>
75+
/// <param name="keyComparer">Comparer to use for <paramref name="secretKeys"/>.</param>
76+
/// <param name="filePath">Path of the file this method is called from.</param>
77+
/// <param name="lineNumber">Line number of file this method is called from.</param>
78+
/// <param name="memberName">Name of the member in which this method is called.</param>
79+
void WriteDictionarySecrets<TKey, TValue>(
80+
IDictionary<TKey, TValue> dictionary,
81+
TKey[] secretKeys,
82+
IEqualityComparer<TKey> keyComparer = null,
83+
[System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
84+
[System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0,
85+
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "");
86+
6887
/// <summary>
6988
/// Writes a message to the trace writer followed by a line terminator.
7089
/// </summary>
@@ -101,6 +120,8 @@ void WriteLineSecrets(
101120

102121
public class Trace : ITrace, IDisposable
103122
{
123+
private const string SecretMask = "********";
124+
104125
private readonly object _writersLock = new object();
105126
private readonly List<TextWriter> _writers = new List<TextWriter>();
106127

@@ -188,6 +209,30 @@ public void WriteDictionary<TKey, TValue>(
188209
}
189210
}
190211

212+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
213+
public void WriteDictionarySecrets<TKey, TValue>(
214+
IDictionary<TKey, TValue> dictionary,
215+
TKey[] secretKeys,
216+
IEqualityComparer<TKey> keyComparer = null,
217+
[System.Runtime.CompilerServices.CallerFilePath] string filePath = "",
218+
[System.Runtime.CompilerServices.CallerLineNumber] int lineNumber = 0,
219+
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "")
220+
{
221+
foreach (KeyValuePair<TKey, TValue> entry in dictionary)
222+
{
223+
bool isSecretEntry = !(secretKeys is null) &&
224+
secretKeys.Contains(entry.Key, keyComparer ?? EqualityComparer<TKey>.Default);
225+
if (isSecretEntry && !this.IsSecretTracingEnabled)
226+
{
227+
WriteLine($"\t{entry.Key}={SecretMask}", filePath, lineNumber, memberName);
228+
}
229+
else
230+
{
231+
WriteLine($"\t{entry.Key}={entry.Value}", filePath, lineNumber, memberName);
232+
}
233+
}
234+
}
235+
191236
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed")]
192237
public void WriteLine(
193238
string message,
@@ -227,7 +272,7 @@ public void WriteLineSecrets(
227272
{
228273
string message = this.IsSecretTracingEnabled
229274
? string.Format(format, secrets)
230-
: string.Format(format, secrets.Select(_ => (object)"********").ToArray());
275+
: string.Format(format, secrets.Select(_ => (object)SecretMask).ToArray());
231276

232277
WriteLine(message, filePath, lineNumber, memberName);
233278
}

common/tests/TestInfrastructure/Objects/NullTrace.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ void ITrace.WriteException(Exception exception, string filePath, int lineNumber,
3232
void ITrace.WriteDictionary<TKey, TValue>(
3333
IDictionary<TKey, TValue> dictionary, string filePath, int lineNumber, string memberName) { }
3434

35+
public void WriteDictionarySecrets<TKey, TValue>(IDictionary<TKey, TValue> dictionary, TKey[] secretKeys,
36+
IEqualityComparer<TKey> keyComparer = null, string filePath = "", int lineNumber = 0,
37+
string memberName = "") { }
38+
3539
void ITrace.WriteLine(string message, string filePath, int lineNumber, string memberName) { }
3640

3741
void ITrace.WriteLineSecrets(

0 commit comments

Comments
 (0)