diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 47469eb43..c8b32151f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -57,8 +57,8 @@ jobs:
- name: Set up signing/notarization infrastructure
env:
- A1: ${{ secrets.APPLICATION_CERTIFICATE_BASE64 }}
- A2: ${{ secrets.APPLICATION_CERTIFICATE_PASSWORD }}
+ A1: ${{ secrets.GATEWATCHER_DEVELOPER_ID_CERT }}
+ A2: ${{ secrets.GATEWATCHER_DEVELOPER_ID_PASSWORD }}
I1: ${{ secrets.INSTALLER_CERTIFICATE_BASE64 }}
I2: ${{ secrets.INSTALLER_CERTIFICATE_PASSWORD }}
N1: ${{ secrets.APPLE_TEAM_ID }}
diff --git a/VERSION b/VERSION
index 82f00d533..cfad4122e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.6.0.0
+2.6.1.0
diff --git a/src/shared/Core.Tests/GitStreamReaderTests.cs b/src/shared/Core.Tests/GitStreamReaderTests.cs
new file mode 100644
index 000000000..bf656d102
--- /dev/null
+++ b/src/shared/Core.Tests/GitStreamReaderTests.cs
@@ -0,0 +1,193 @@
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace GitCredentialManager.Tests;
+
+public class GitStreamReaderTests
+{
+ #region ReadLineAsync
+
+ [Fact]
+ public async Task GitStreamReader_ReadLineAsync_LF()
+ {
+ // hello\n
+ // world\n
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\nworld\n");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = await reader.ReadLineAsync();
+ string actual2 = await reader.ReadLineAsync();
+ string actual3 = await reader.ReadLineAsync();
+
+ Assert.Equal("hello", actual1);
+ Assert.Equal("world", actual2);
+ Assert.Null(actual3);
+ }
+
+ [Fact]
+ public async Task GitStreamReader_ReadLineAsync_CR()
+ {
+ // hello\rworld\r
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\rworld\r");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = await reader.ReadLineAsync();
+ string actual2 = await reader.ReadLineAsync();
+
+ Assert.Equal("hello\rworld\r", actual1);
+ Assert.Null(actual2);
+ }
+
+ [Fact]
+ public async Task GitStreamReader_ReadLineAsync_CRLF()
+ {
+ // hello\r\n
+ // world\r\n
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\r\nworld\r\n");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = await reader.ReadLineAsync();
+ string actual2 = await reader.ReadLineAsync();
+ string actual3 = await reader.ReadLineAsync();
+
+ Assert.Equal("hello", actual1);
+ Assert.Equal("world", actual2);
+ Assert.Null(actual3);
+ }
+
+ [Fact]
+ public async Task GitStreamReader_ReadLineAsync_Mixed()
+ {
+ // hello\r\n
+ // world\rthis\n
+ // is\n
+ // a\n
+ // \rmixed\rnewline\r\n
+ // \n
+ // string\n
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\r\nworld\rthis\nis\na\n\rmixed\rnewline\r\n\nstring\n");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = await reader.ReadLineAsync();
+ string actual2 = await reader.ReadLineAsync();
+ string actual3 = await reader.ReadLineAsync();
+ string actual4 = await reader.ReadLineAsync();
+ string actual5 = await reader.ReadLineAsync();
+ string actual6 = await reader.ReadLineAsync();
+ string actual7 = await reader.ReadLineAsync();
+ string actual8 = await reader.ReadLineAsync();
+
+ Assert.Equal("hello", actual1);
+ Assert.Equal("world\rthis", actual2);
+ Assert.Equal("is", actual3);
+ Assert.Equal("a", actual4);
+ Assert.Equal("\rmixed\rnewline", actual5);
+ Assert.Equal("", actual6);
+ Assert.Equal("string", actual7);
+ Assert.Null(actual8);
+ }
+
+ #endregion
+
+ #region ReadLine
+
+ [Fact]
+ public void GitStreamReader_ReadLine_LF()
+ {
+ // hello\n
+ // world\n
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\nworld\n");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = reader.ReadLine();
+ string actual2 = reader.ReadLine();
+ string actual3 = reader.ReadLine();
+
+ Assert.Equal("hello", actual1);
+ Assert.Equal("world", actual2);
+ Assert.Null(actual3);
+ }
+
+ [Fact]
+ public void GitStreamReader_ReadLine_CR()
+ {
+ // hello\rworld\r
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\rworld\r");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = reader.ReadLine();
+ string actual2 = reader.ReadLine();
+
+ Assert.Equal("hello\rworld\r", actual1);
+ Assert.Null(actual2);
+ }
+
+ [Fact]
+ public void GitStreamReader_ReadLine_CRLF()
+ {
+ // hello\r\n
+ // world\r\n
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\r\nworld\r\n");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = reader.ReadLine();
+ string actual2 = reader.ReadLine();
+ string actual3 = reader.ReadLine();
+
+ Assert.Equal("hello", actual1);
+ Assert.Equal("world", actual2);
+ Assert.Null(actual3);
+ }
+
+ [Fact]
+ public void GitStreamReader_ReadLine_Mixed()
+ {
+ // hello\r\n
+ // world\rthis\n
+ // is\n
+ // a\n
+ // \rmixed\rnewline\r\n
+ // \n
+ // string\n
+
+ byte[] buffer = Encoding.UTF8.GetBytes("hello\r\nworld\rthis\nis\na\n\rmixed\rnewline\r\n\nstring\n");
+ using var stream = new MemoryStream(buffer);
+ var reader = new GitStreamReader(stream, Encoding.UTF8);
+
+ string actual1 = reader.ReadLine();
+ string actual2 = reader.ReadLine();
+ string actual3 = reader.ReadLine();
+ string actual4 = reader.ReadLine();
+ string actual5 = reader.ReadLine();
+ string actual6 = reader.ReadLine();
+ string actual7 = reader.ReadLine();
+ string actual8 = reader.ReadLine();
+
+ Assert.Equal("hello", actual1);
+ Assert.Equal("world\rthis", actual2);
+ Assert.Equal("is", actual3);
+ Assert.Equal("a", actual4);
+ Assert.Equal("\rmixed\rnewline", actual5);
+ Assert.Equal("", actual6);
+ Assert.Equal("string", actual7);
+ Assert.Null(actual8);
+ }
+
+ #endregion
+}
diff --git a/src/shared/Core/GitStreamReader.cs b/src/shared/Core/GitStreamReader.cs
new file mode 100644
index 000000000..6512b2efc
--- /dev/null
+++ b/src/shared/Core/GitStreamReader.cs
@@ -0,0 +1,70 @@
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace GitCredentialManager;
+
+///
+/// StreamReader that does NOT consider a lone carriage-return as a new-line character,
+/// only a line-feed or carriage-return immediately followed by a line-feed.
+///
+/// The only major operating system that uses a lone carriage-return as a new-line character
+/// is the classic Macintosh OS (before OS X), which is not supported by Git.
+///
+public class GitStreamReader : StreamReader
+{
+ public GitStreamReader(Stream stream, Encoding encoding) : base(stream, encoding) { }
+
+ public override string ReadLine()
+ {
+#if NETFRAMEWORK
+ return ReadLineAsync().ConfigureAwait(false).GetAwaiter().GetResult();
+#else
+ return ReadLineAsync(CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
+#endif
+ }
+
+#if NETFRAMEWORK
+ public override async Task ReadLineAsync()
+#else
+ public override async ValueTask ReadLineAsync(CancellationToken cancellationToken)
+#endif
+ {
+ int nr;
+ var sb = new StringBuilder();
+ var buffer = new char[1];
+ bool lastWasCR = false;
+
+ while ((nr = await base.ReadAsync(buffer, 0, 1).ConfigureAwait(false)) > 0)
+ {
+ char c = buffer[0];
+
+ // Only treat a line-feed as a new-line character.
+ // Carriage-returns alone are NOT considered new-line characters.
+ if (c == '\n')
+ {
+ if (lastWasCR)
+ {
+ // If the last character was a carriage-return we should remove it from the string builder
+ // since together with this line-feed it is considered a new-line character.
+ sb.Length--;
+ }
+
+ // We have a new-line character, so we should stop reading.
+ break;
+ }
+
+ lastWasCR = c == '\r';
+
+ sb.Append(c);
+ }
+
+ if (sb.Length == 0 && nr == 0)
+ {
+ return null;
+ }
+
+ return sb.ToString();
+ }
+}
diff --git a/src/shared/Core/StandardStreams.cs b/src/shared/Core/StandardStreams.cs
index d0b3042b0..45f9f6cc7 100644
--- a/src/shared/Core/StandardStreams.cs
+++ b/src/shared/Core/StandardStreams.cs
@@ -39,7 +39,7 @@ public TextReader In
{
if (_stdIn == null)
{
- _stdIn = new StreamReader(Console.OpenStandardInput(), EncodingEx.UTF8NoBom);
+ _stdIn = new GitStreamReader(Console.OpenStandardInput(), EncodingEx.UTF8NoBom);
}
return _stdIn;