Compare commits
6
Commits
f41d12b7fd
...
b186c1e1ca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b186c1e1ca | ||
|
|
716d79739c | ||
|
|
e3b4194653 | ||
|
|
29ba185c56 | ||
|
|
e6891a72ea | ||
|
|
7ad14767b6 |
No files matched your search
@@ -34,6 +34,9 @@ insert_final_newline = false
|
||||
#### .NET Coding Conventions ####
|
||||
[*.{cs,vb}]
|
||||
|
||||
# Analyzer settings
|
||||
dotnet_diagnostic.CA1822.severity = none
|
||||
|
||||
# Organize usings
|
||||
dotnet_separate_import_directive_groups = true
|
||||
dotnet_sort_system_directives_first = true
|
||||
|
||||
+27
-13
@@ -1,22 +1,36 @@
|
||||
Write-Host "Starting test execution..." -ForegroundColor Magenta
|
||||
Write-Host ""
|
||||
$RepoRoot = Resolve-Path (Join-Path -Path $PSScriptRoot -ChildPath "..")
|
||||
|
||||
dotnet test
|
||||
Push-Location -Path $RepoRoot
|
||||
|
||||
try {
|
||||
Write-Host "Starting test execution..." -ForegroundColor Magenta
|
||||
Write-Host ""
|
||||
|
||||
$TestExitCode = $LASTEXITCODE
|
||||
$TestResultsPath = Join-Path -Path $RepoRoot -ChildPath "TestResults"
|
||||
|
||||
if ($TestExitCode -eq 0) {
|
||||
Write-Host ""
|
||||
Write-Host "Tests passed. Generating code coverage HTML report..." -ForegroundColor Magenta
|
||||
Write-Host ""
|
||||
if (Test-Path $TestResultsPath) {
|
||||
Remove-Item -Path $TestResultsPath -Recurse -Force
|
||||
}
|
||||
|
||||
reportgenerator -reports:"**/*.cobertura.xml" -targetdir:"CoverageReport"
|
||||
dotnet test
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "SUCCESS: All tests passed and coverage report generated." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "FAILURE: Tests failed with exit code $TestExitCode. Skipping coverage report generation." -ForegroundColor Red
|
||||
$TestExitCode = $LASTEXITCODE
|
||||
|
||||
if ($TestExitCode -eq 0) {
|
||||
Write-Host ""
|
||||
Write-Host "Tests passed. Generating code coverage HTML report..." -ForegroundColor Magenta
|
||||
Write-Host ""
|
||||
|
||||
reportgenerator -reports:"**/*.cobertura.xml" -targetdir:"CoverageReport"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "SUCCESS: All tests passed and coverage report generated." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "FAILURE: Tests failed with exit code $TestExitCode. Skipping coverage report generation." -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
exit $TestExitCode
|
||||
@@ -0,0 +1,132 @@
|
||||
namespace StevanFreeborn.Atproto.IdentityResolver;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public abstract class AtprotoId
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Value { get; protected set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static AtprotoId From(string atprotoId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(atprotoId))
|
||||
{
|
||||
throw new ArgumentException("Cannot be null or empty", nameof(atprotoId));
|
||||
}
|
||||
|
||||
if (IsDomain(atprotoId))
|
||||
{
|
||||
return Handle.From(atprotoId);
|
||||
}
|
||||
|
||||
return Did.From(atprotoId);
|
||||
}
|
||||
|
||||
private static bool IsDomain(string did)
|
||||
{
|
||||
var hostType = Uri.CheckHostName(did);
|
||||
return hostType == UriHostNameType.Dns && did.Contains('.', StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class Did : AtprotoId
|
||||
{
|
||||
private static readonly string[] ValidPrefixes = ["did:web:", "did:plc:"];
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Method { get; private set; }
|
||||
|
||||
private Did(string did)
|
||||
{
|
||||
if (string.IsNullOrEmpty(did))
|
||||
{
|
||||
throw new ArgumentException("Cannot be null or empty", nameof(did));
|
||||
}
|
||||
|
||||
if (TryParseWithoutPrefix(did, out var prefix, out var didWithoutPrefix) is false)
|
||||
{
|
||||
throw new ArgumentException($"Must be did with one of these methods: {string.Join(',', ValidPrefixes)}", nameof(did));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(didWithoutPrefix))
|
||||
{
|
||||
throw new ArgumentException("Must not be null or empty without did method prefix", nameof(did));
|
||||
}
|
||||
|
||||
// Method should probably be a strongly
|
||||
// typed object
|
||||
Method = prefix.Contains("web", StringComparison.OrdinalIgnoreCase) ? "web" : "plc";
|
||||
Value = did;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static new Did From(string did)
|
||||
{
|
||||
return new(did);
|
||||
}
|
||||
|
||||
private static bool TryParseWithoutPrefix(
|
||||
string did,
|
||||
out string prefix,
|
||||
out string didWithoutPrefix
|
||||
)
|
||||
{
|
||||
prefix = string.Empty;
|
||||
didWithoutPrefix = string.Empty;
|
||||
|
||||
foreach (var validPrefix in ValidPrefixes)
|
||||
{
|
||||
if (did.StartsWith(validPrefix, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
prefix = did[..validPrefix.Length];
|
||||
didWithoutPrefix = did[validPrefix.Length..];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class Handle : AtprotoId
|
||||
{
|
||||
private Handle(string handle)
|
||||
{
|
||||
if (string.IsNullOrEmpty(handle))
|
||||
{
|
||||
throw new ArgumentException("Cannot be null or empty", nameof(handle));
|
||||
}
|
||||
|
||||
if (handle.StartsWith('@'))
|
||||
{
|
||||
throw new ArgumentException("Cannot start with @", nameof(handle));
|
||||
}
|
||||
|
||||
Value = handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static new Handle From(string handle)
|
||||
{
|
||||
return new(handle);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace StevanFreeborn.Atproto.IdentityResolver;
|
||||
|
||||
internal class Greeter
|
||||
{
|
||||
public static string SayHello()
|
||||
{
|
||||
return "Hi!";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace StevanFreeborn.Atproto.IdentityResolver;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public interface IResolver
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
Task<DidDocument> ResolveOrThrowAsync(AtprotoId atprotoId, CancellationToken ct);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace StevanFreeborn.Atproto.IdentityResolver;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class Resolver : IResolver
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<DidDocument> ResolveOrThrowAsync(AtprotoId atprotoId, CancellationToken ct)
|
||||
{
|
||||
// you need to retrieve the did document based on what you got
|
||||
// if you have domain
|
||||
// you are going to try to retrieve the did
|
||||
// either through using /.well-known/did.json
|
||||
// or looking for _atproto.domain txt record
|
||||
//
|
||||
// you now for sure have a did
|
||||
// check method
|
||||
// if method is web
|
||||
// retrieve doc from domain/.well-known/did.json
|
||||
// if method is plc
|
||||
// retrieve doc from plc.directory/{did}
|
||||
// you now have the document
|
||||
// extract alsoKnownAs which is the handle
|
||||
// make sure you can get back the same did
|
||||
// from the handle's domain at /.well-known/did.json
|
||||
// or _atproto.domain txt record
|
||||
|
||||
return Task.FromResult(new DidDocument());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class DidDocument();
|
||||
@@ -1,2 +1,3 @@
|
||||
[*.cs]
|
||||
dotnet_diagnostic.CA1707.severity = none
|
||||
dotnet_diagnostic.CA2007.severity = none
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace StevanFreeborn.Atproto.IdentityResolver.Tests;
|
||||
|
||||
public class AtprotoIdTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("localhost")]
|
||||
[InlineData("did:web:")]
|
||||
[InlineData("did:plc:")]
|
||||
[InlineData("did:mu:dxbmien5xsrkov5yhywgc4zu")]
|
||||
[InlineData("@stevanfreeborn.com")]
|
||||
[InlineData(null)]
|
||||
public void From_WhenCalledWithInvalidDid_ItShouldThrowInvalidArgumentException(string? atprotoId)
|
||||
{
|
||||
var act = () => AtprotoId.From(atprotoId!);
|
||||
|
||||
act.Should().Throw<ArgumentException>();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace StevanFreeborn.Atproto.IdentityResolver.Tests;
|
||||
|
||||
public class GreeterTests
|
||||
{
|
||||
[Fact]
|
||||
public void SayHello_WhenCalled_ItShouldReturnHi()
|
||||
{
|
||||
Greeter.SayHello().Should().Be("Hi!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace StevanFreeborn.Atproto.IdentityResolver.Tests;
|
||||
|
||||
public class ResolverTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ResolveAsync_WhenCalledWithInvalidDid_ItShouldThrowInvalidArgumentException()
|
||||
{
|
||||
true.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user