Skip to content

Commit

Permalink
feat(scan): provide a default scan factory (#76)
Browse files Browse the repository at this point in the history
closes #68
  • Loading branch information
ostridm authored Dec 8, 2022
1 parent d0c26bc commit 2c7ef66
Show file tree
Hide file tree
Showing 51 changed files with 1,445 additions and 190 deletions.
5 changes: 4 additions & 1 deletion src/SecTester.Core/Utils/StringUtils.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace SecTester.Core.Utils;
Expand All @@ -21,6 +20,10 @@ public static class StringUtils
: SupportedCaseRegexes.Aggregate(value!,
(input, regex) => regex.Replace(input, "$1_$2"))
.ToLowerInvariant();
}

public static string Truncate(this string value, int n)
{
return value.Length > n ? Regex.Replace(value.Substring(0, n), @"\w$", "") : value;
}
}
1 change: 0 additions & 1 deletion src/SecTester.Scan/CI/DefaultCiDiscovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ internal class DefaultCiDiscovery : CiDiscovery
public CiServer? Server { get; }

public bool IsCi => Server != null;

}
11 changes: 10 additions & 1 deletion src/SecTester.Scan/Commands/CreateScan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,16 @@ public CreateScan(ScanConfig config, string configurationName, string configurat
config.ProjectId,
config.SlowEpTimeout,
config.TargetTimeout,
Info = new { Source = "utlib", client = new { Name = configurationName, Version = configurationVersion }, Provider = ciProvider }
Info = new
{
Source = "utlib",
client = new
{
Name = configurationName,
Version = configurationVersion
},
Provider = ciProvider
}
};

Body = new StringContent(MessageSerializer.Serialize(payload), Encoding.UTF8, "application/json");
Expand Down
9 changes: 5 additions & 4 deletions src/SecTester.Scan/Commands/UploadHar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ public UploadHar(UploadHarOptions options)
: base("/api/v1/files", HttpMethod.Post)
{
Params = options.Discard
? new[] { new KeyValuePair<string, string>("discard", options.Discard.ToString().ToLowerInvariant()) }
? new[]
{
new KeyValuePair<string, string>("discard", options.Discard.ToString().ToLowerInvariant())
}
: default;


var content = new MultipartFormDataContent
{
{
new StringContent(MessageSerializer.Serialize(options.Har), Encoding.UTF8, "application/json"),
"file",
options.FileName
new StringContent(MessageSerializer.Serialize(options.Har), Encoding.UTF8, "application/json"), "file", options.FileName
}
};

Expand Down
116 changes: 116 additions & 0 deletions src/SecTester.Scan/DefaultScanFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SecTester.Core;
using SecTester.Core.Utils;
using SecTester.Scan.Models;
using SecTester.Scan.Models.HarSpec;

namespace SecTester.Scan;

public class DefaultScanFactory : ScanFactory
{
internal const int MaxSlugLength = 200;

private static readonly IEnumerable<Discovery> DefaultDiscoveryTypes = new List<Discovery>
{
Discovery.Archive
};

private readonly Configuration _configuration;
private readonly ILogger _logger;

private readonly Scans _scans;
private readonly SystemTimeProvider _systemTimeProvider;

public DefaultScanFactory(Configuration configuration, Scans scans, ILogger logger,
SystemTimeProvider systemTimeProvider)
{
_scans = scans ?? throw new ArgumentNullException(nameof(scans));
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
_systemTimeProvider = systemTimeProvider ?? throw new ArgumentNullException(nameof(systemTimeProvider));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}

public async Task<Scan> CreateScan(ScanSettingsOptions settingsOptions, ScanOptions? options)
{
var scanConfig = await BuildScanConfig(new ScanSettings(settingsOptions)).ConfigureAwait(false);
var scanId = await _scans.CreateScan(scanConfig).ConfigureAwait(false);

return new Scan(scanId, _scans, _logger, options ?? new ScanOptions());
}

private async Task<ScanConfig> BuildScanConfig(ScanSettings scanSettings)
{
var fileId = await CreateAndUploadHar((Target)scanSettings.Target).ConfigureAwait(false);

return new ScanConfig(scanSettings.Name!)
{
FileId = fileId,
Smart = scanSettings.Smart,
PoolSize = scanSettings.PoolSize,
SkipStaticParams = scanSettings.SkipStaticParams,
Module = Module.Dast,
DiscoveryTypes = DefaultDiscoveryTypes,
AttackParamLocations = scanSettings.AttackParamLocations,
Tests = scanSettings.Tests,
Repeaters = scanSettings.RepeaterId is null
? default
: new List<string>
{
scanSettings.RepeaterId
},
SlowEpTimeout =
scanSettings.SlowEpTimeout is null ? default : (int)scanSettings.SlowEpTimeout.Value.TotalSeconds,
TargetTimeout =
scanSettings.TargetTimeout is null ? default : (int)scanSettings.TargetTimeout.Value.TotalSeconds
};
}

private async Task<string> CreateAndUploadHar(Target target)
{
var filename = GenerateFileName(target.Url);
var har = await CreateHar(target).ConfigureAwait(false);

return await _scans.UploadHar(new UploadHarOptions(har, filename, true)).ConfigureAwait(false);
}

private static string GenerateFileName(string url)
{
var host = new Uri(url).Host;

host = host.Length <= MaxSlugLength ? host : host.Substring(0, MaxSlugLength);

return $"{host.TrimEnd(".-".ToCharArray())}-{Guid.NewGuid()}.har";
}

private async Task<Entry> CreateHarEntry(Target target)
{
return new Entry(_systemTimeProvider.Now,
await target.ToHarRequest().ConfigureAwait(false),
new ResponseMessage(200, "OK", "", new Content(-1, "text/plain"))
{
HttpVersion = "HTTP/1.1"
},
new Timings(),
new Cache()
);
}

private async Task<Har> CreateHar(Target target)
{
var entry = await CreateHarEntry(target).ConfigureAwait(false);

return new Har(
new Log(
new Tool(_configuration.Name, _configuration.Version))
{
Entries = new List<Entry>
{
entry
}
}
);
}
}
6 changes: 3 additions & 3 deletions src/SecTester.Scan/DefaultScans.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ namespace SecTester.Scan;

public class DefaultScans : Scans
{
private readonly Configuration _configuration;
private readonly CommandDispatcher _commandDispatcher;
private readonly CiDiscovery _ciDiscovery;
private readonly CommandDispatcher _commandDispatcher;
private readonly Configuration _configuration;

public DefaultScans(Configuration configuration, CommandDispatcher commandDispatcher, CiDiscovery ciDiscovery)
{
Expand Down Expand Up @@ -60,7 +60,7 @@ public async Task<string> UploadHar(UploadHarOptions options)

private async Task<T> SendCommand<T>(Command<T> command)
{
var result = await this._commandDispatcher.Execute(command).ConfigureAwait(false);
var result = await _commandDispatcher.Execute(command).ConfigureAwait(false);

return AssertReply(result);
}
Expand Down
3 changes: 3 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/Cache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace SecTester.Scan.Models.HarSpec;

public record Cache;
3 changes: 3 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/Content.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace SecTester.Scan.Models.HarSpec;

public record Content(int Size, string MimeType);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;

namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record Cookie(string Name, string Value) : Parameter(Name, Value)
{
Expand Down
8 changes: 8 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/Entry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System;

namespace SecTester.Scan.Models.HarSpec;

public record Entry(DateTime StartedDateTime, RequestMessage RequestMessage, ResponseMessage ResponseMessage, Timings Timings, Cache Cache)
{
public int Time { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.Collections.Generic;

namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record Message
public record EntryMessage
{
public int HeadersSize { get; init; } = -1;
public int? BodySize { get; init; } = -1;
public int BodySize { get; init; } = -1;
public IEnumerable<Cookie> Cookies { get; init; } = new List<Cookie>();
public IEnumerable<Header> Headers { get; init; } = new List<Header>();
public string HttpVersion { get; init; } = "HTTP/0.9";
Expand Down
3 changes: 3 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/Har.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace SecTester.Scan.Models.HarSpec;

public record Har(Log Log);
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record Header(string Name, string Value) : Parameter(Name, Value);
9 changes: 9 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/Log.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace SecTester.Scan.Models.HarSpec;

public record Log(Tool Creator)
{
public IEnumerable<Entry> Entries { get; init; } = new List<Entry>();
public string Version { get; init; } = "1.2";
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record Parameter(string Name, string Value);
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Collections.Generic;

namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record PostData
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record PostDataParameter(string Name, string Value) : Parameter(Name, Value)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record QueryParameter(string Name, string Value) : Parameter(Name, Value);
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Collections.Generic;

namespace SecTester.Scan.Target.Har;
namespace SecTester.Scan.Models.HarSpec;

public record Request : Message
public record RequestMessage : EntryMessage
{
public string? Method { get; init; }
public string? Url { get; init; }
Expand Down
3 changes: 3 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/ResponseMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace SecTester.Scan.Models.HarSpec;

public record ResponseMessage(int Status, string StatusText, string RedirectUrl, Content Content) : EntryMessage;
3 changes: 3 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/Timings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace SecTester.Scan.Models.HarSpec;

public record Timings(int Send = 0, int Wait = 0, int Receive = 0);
3 changes: 3 additions & 0 deletions src/SecTester.Scan/Models/HarSpec/Tool.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace SecTester.Scan.Models.HarSpec;

public record Tool(string Name, string Version);
3 changes: 2 additions & 1 deletion src/SecTester.Scan/Models/Identifiable.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System;

namespace SecTester.Scan.Models;

public record Identifiable<T>(T Id)
{
public T Id { get; } = Id ?? throw new ArgumentNullException(nameof(Id));
};
}
2 changes: 1 addition & 1 deletion src/SecTester.Scan/Models/ScanConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace SecTester.Scan.Models;

public record ScanConfig(string Name)
{
public string Name { get; init; } = Name ?? throw new ArgumentNullException(nameof(Name));
public string Name { get; } = Name ?? throw new ArgumentNullException(nameof(Name));
public Module? Module { get; init; }
public IEnumerable<TestType>? Tests { get; init; }
public IEnumerable<Discovery>? DiscoveryTypes { get; init; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
using System.Text;
using System.Threading.Tasks;
using SecTester.Core.Utils;
using SecTester.Scan.Target.Har;
using SecTester.Scan.Models.HarSpec;

namespace SecTester.Scan.Target;
namespace SecTester.Scan.Models;

public sealed class Target : TargetOptions
{
Expand Down Expand Up @@ -242,7 +242,7 @@ public Target WithHeaders(IEnumerable<KeyValuePair<string, IEnumerable<string>>>
/// <summary>
/// Returns a HAR request containing detailed info about performed request
/// </summary>
internal async Task<Request> ToHarRequest()
internal async Task<RequestMessage> ToHarRequest()
{
var uriBuilder = new UriBuilder(Url)
{
Expand All @@ -254,7 +254,7 @@ internal async Task<Request> ToHarRequest()
var headers = BuildHeaderParameters();
var postData = _bodyGenerator is not null ? await _bodyGenerator.Invoke().ConfigureAwait(false) : null;

return new Request
return new RequestMessage
{
Url = url,
Headers = headers,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Net.Http;

namespace SecTester.Scan.Target;
namespace SecTester.Scan.Models;

public interface TargetOptions
{
Expand Down
2 changes: 1 addition & 1 deletion src/SecTester.Scan/Models/UploadHarOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System;
using SecTester.Scan.Target.Har;
using SecTester.Scan.Models.HarSpec;

namespace SecTester.Scan.Models;

Expand Down
Loading

0 comments on commit 2c7ef66

Please sign in to comment.