Compare commits

...

5 Commits

Author SHA1 Message Date
JoannaaKL
9c6857c60f Remove unused code 2023-10-31 13:54:36 +00:00
JoannaaKL
2b7faad20d Don't escape percent 2023-10-31 13:48:35 +00:00
JoannaaKL
ae6eddbea9 Replace copy-pasted code with one method 2023-10-30 11:11:57 +00:00
JoannaaKL
088fb13563 Add StringEscapingUtil that will be used in many places 2023-10-30 10:51:38 +00:00
JoannaaKL
bd79ba0be7 Add test for percent encoding 2023-10-30 09:50:22 +00:00
4 changed files with 77 additions and 83 deletions

View File

@@ -1,4 +1,5 @@
using GitHub.Runner.Sdk; using GitHub.Runner.Sdk;
using GitHub.Runner.Common.Util;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -6,29 +7,28 @@ namespace GitHub.Runner.Common
{ {
public sealed class ActionCommand public sealed class ActionCommand
{ {
private static readonly EscapeMapping[] _escapeMappings = new[] private static readonly StringEscapingUtil.EscapeMapping[] _escapeMappings = new[]
{ {
new EscapeMapping(token: ";", replacement: "%3B"), new StringEscapingUtil.EscapeMapping(token: ";", replacement: "%3B"),
new EscapeMapping(token: "\r", replacement: "%0D"), new StringEscapingUtil.EscapeMapping(token: "\r", replacement: "%0D"),
new EscapeMapping(token: "\n", replacement: "%0A"), new StringEscapingUtil.EscapeMapping(token: "\n", replacement: "%0A"),
new EscapeMapping(token: "]", replacement: "%5D"), new StringEscapingUtil.EscapeMapping(token: "]", replacement: "%5D"),
new EscapeMapping(token: "%", replacement: "%25"), new StringEscapingUtil.EscapeMapping(token: "%", replacement: "%25"),
}; };
private static readonly EscapeMapping[] _escapeDataMappings = new[] private static readonly StringEscapingUtil.EscapeMapping[] _escapeDataMappings = new[]
{ {
new EscapeMapping(token: "\r", replacement: "%0D"), new StringEscapingUtil.EscapeMapping(token: "\r", replacement: "%0D"),
new EscapeMapping(token: "\n", replacement: "%0A"), new StringEscapingUtil.EscapeMapping(token: "\n", replacement: "%0A"),
new EscapeMapping(token: "%", replacement: "%25"),
}; };
private static readonly EscapeMapping[] _escapePropertyMappings = new[] private static readonly StringEscapingUtil.EscapeMapping[] _escapePropertyMappings = new[]
{ {
new EscapeMapping(token: "\r", replacement: "%0D"), new StringEscapingUtil.EscapeMapping(token: "\r", replacement: "%0D"),
new EscapeMapping(token: "\n", replacement: "%0A"), new StringEscapingUtil.EscapeMapping(token: "\n", replacement: "%0A"),
new EscapeMapping(token: ":", replacement: "%3A"), new StringEscapingUtil.EscapeMapping(token: ":", replacement: "%3A"),
new EscapeMapping(token: ",", replacement: "%2C"), new StringEscapingUtil.EscapeMapping(token: ",", replacement: "%2C"),
new EscapeMapping(token: "%", replacement: "%25"), new StringEscapingUtil.EscapeMapping(token: "%", replacement: "%25"),
}; };
private readonly Dictionary<string, string> _properties = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, string> _properties = new(StringComparer.OrdinalIgnoreCase);
@@ -103,12 +103,12 @@ namespace GitHub.Runner.Common
string[] pair = propertyStr.Split(new[] { '=' }, count: 2, options: StringSplitOptions.RemoveEmptyEntries); string[] pair = propertyStr.Split(new[] { '=' }, count: 2, options: StringSplitOptions.RemoveEmptyEntries);
if (pair.Length == 2) if (pair.Length == 2)
{ {
command.Properties[pair[0]] = UnescapeProperty(pair[1]); command.Properties[pair[0]] = StringEscapingUtil.UnescapeString(pair[1], _escapePropertyMappings);
} }
} }
} }
command.Data = UnescapeData(message.Substring(endIndex + _commandKey.Length)); command.Data = StringEscapingUtil.UnescapeString(message.Substring(endIndex + _commandKey.Length), _escapeDataMappings);
return true; return true;
} }
catch catch
@@ -173,12 +173,12 @@ namespace GitHub.Runner.Common
string[] pair = propertyStr.Split(new[] { '=' }, count: 2, options: StringSplitOptions.RemoveEmptyEntries); string[] pair = propertyStr.Split(new[] { '=' }, count: 2, options: StringSplitOptions.RemoveEmptyEntries);
if (pair.Length == 2) if (pair.Length == 2)
{ {
command.Properties[pair[0]] = Unescape(pair[1]); command.Properties[pair[0]] = StringEscapingUtil.UnescapeString(pair[1], _escapeMappings);
} }
} }
} }
command.Data = Unescape(message.Substring(rbIndex + 1)); command.Data = StringEscapingUtil.UnescapeString(message.Substring(rbIndex + 1), _escapeMappings);
return true; return true;
} }
catch catch
@@ -187,67 +187,5 @@ namespace GitHub.Runner.Common
return false; return false;
} }
} }
private static string Unescape(string escaped)
{
if (string.IsNullOrEmpty(escaped))
{
return string.Empty;
}
string unescaped = escaped;
foreach (EscapeMapping mapping in _escapeMappings)
{
unescaped = unescaped.Replace(mapping.Replacement, mapping.Token);
}
return unescaped;
}
private static string UnescapeProperty(string escaped)
{
if (string.IsNullOrEmpty(escaped))
{
return string.Empty;
}
string unescaped = escaped;
foreach (EscapeMapping mapping in _escapePropertyMappings)
{
unescaped = unescaped.Replace(mapping.Replacement, mapping.Token);
}
return unescaped;
}
private static string UnescapeData(string escaped)
{
if (string.IsNullOrEmpty(escaped))
{
return string.Empty;
}
string unescaped = escaped;
foreach (EscapeMapping mapping in _escapeDataMappings)
{
unescaped = unescaped.Replace(mapping.Replacement, mapping.Token);
}
return unescaped;
}
private sealed class EscapeMapping
{
public string Replacement { get; }
public string Token { get; }
public EscapeMapping(string token, string replacement)
{
ArgUtil.NotNullOrEmpty(token, nameof(token));
ArgUtil.NotNullOrEmpty(replacement, nameof(replacement));
Token = token;
Replacement = replacement;
}
}
} }
} }

View File

@@ -0,0 +1,41 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using GitHub.Runner.Sdk;
using GitHub.Runner.Common;
namespace GitHub.Runner.Common.Util
{
public static class StringEscapingUtil
{
public static string UnescapeString(string escaped, EscapeMapping[] _escapeDataMappings)
{
if (string.IsNullOrEmpty(escaped))
{
return string.Empty;
}
string unescaped = escaped;
foreach (EscapeMapping mapping in _escapeDataMappings)
{
unescaped = unescaped.Replace(mapping.Replacement, mapping.Token);
}
return unescaped;
}
public class EscapeMapping
{
public string Replacement { get; }
public string Token { get; }
public EscapeMapping(string token, string replacement)
{
ArgUtil.NotNullOrEmpty(token, nameof(token));
ArgUtil.NotNullOrEmpty(replacement, nameof(replacement));
Token = token;
Replacement = replacement;
}
}
}
}

View File

@@ -139,7 +139,7 @@ namespace GitHub.Runner.Common.Tests.Worker
message = "::do-something k1=;=%252C=%250D=%250A=]=%253A,::;-%250D-%250A-]-:-,"; message = "::do-something k1=;=%252C=%250D=%250A=]=%253A,::;-%250D-%250A-]-:-,";
test = new ActionCommand("do-something") test = new ActionCommand("do-something")
{ {
Data = ";-%0D-%0A-]-:-,", Data = ";-%250D-%250A-]-:-,",
}; };
test.Properties.Add("k1", ";=%2C=%0D=%0A=]=%3A"); test.Properties.Add("k1", ";=%2C=%0D=%0A=]=%3A");
Assert.True(ActionCommand.TryParseV2(message, commands, out verify)); Assert.True(ActionCommand.TryParseV2(message, commands, out verify));

View File

@@ -443,6 +443,21 @@ namespace GitHub.Runner.Common.Tests.Worker
} }
} }
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void AddMaskWithPercentEncodedString()
{
using (TestHostContext hc = CreateTestContext())
{
// Act
_commandManager.TryProcessCommand(_ec.Object, $"::add-mask::%252F%2F", null);
// Assert
Assert.Equal("***", hc.SecretMasker.MaskSecrets("%252F%2F"));
}
}
private TestHostContext CreateTestContext([CallerMemberName] string testName = "") private TestHostContext CreateTestContext([CallerMemberName] string testName = "")
{ {
var hostContext = new TestHostContext(this, testName); var hostContext = new TestHostContext(this, testName);