Skip to content

Commit

Permalink
not sure this is a good approach
Browse files Browse the repository at this point in the history
  • Loading branch information
TheButlah committed Feb 23, 2025
1 parent cdbff20 commit e35a099
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 49 deletions.
105 changes: 56 additions & 49 deletions Contrib/Auth/Did/DidAuth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Basis.Contrib.Auth.DecentralizedIds;
using Basis.Contrib.Auth.DecentralizedIds.Newtypes;
using Basis.Contrib.Auth.DecentralizedIds.Result;
using CryptoRng = System.Security.Cryptography.RandomNumberGenerator;
using Debug = System.Diagnostics.Debug;

Expand All @@ -23,6 +25,47 @@ public sealed record Config
};
}

/// Errors during resolution of DID Document.
public abstract record DidResolveErr : DidVerifyErr
{
private DidResolveErr() { }

/// Did had an invalid prefix.
public sealed record InvalidPrefix : DidResolveErr { }

/// Did method is not supported.
public sealed record UnsupportedMethod : DidResolveErr { }

/// Another generic error happened during DID document resolution.
public sealed record Other(Exception E) : DidResolveErr { }
}

/// Errors relating to the DID URL Fragment.
public abstract record DidFragmentErr : DidVerifyErr
{
private DidFragmentErr() { }

/// No such fragment was present in the DID document.
public sealed record NoSuchFragment : DidFragmentErr { }

/// The given fragment was ambiguous.
public sealed record AmbiguousFragment : DidFragmentErr { }
}

/// Errors relating to the signature validity.
public abstract record DidSignatureErr : DidVerifyErr
{
private DidSignatureErr() { }

// TODO: Define failure modes
}

/// Toplevel error type.
public abstract record DidVerifyErr
{
internal DidVerifyErr() { } // Seals class
}

// TODO(@thebutlah): Create and implement an `IChallengeResponseAuth`
// interface. This interface should live in basis core.
public sealed class DidAuthentication
Expand Down Expand Up @@ -60,13 +103,16 @@ public Challenge MakeChallenge(Did identity)
///
/// It is the caller's responsibility to keep track of which challenges
/// should be held for which responses.
public async Task<VerifyResponseResult> VerifyResponse(
public async Task<Result<Success, DidVerifyErr>> VerifyResponse(
Response response,
Challenge challenge
)
{
var document = await ResolveDid(challenge.Identity);
var pubkey = RetrieveKey(document, response.DidUrlFragment);
var resolveResult = await ResolveDid(challenge.Identity); /*var pubkey = RetrieveKey(document, response.DidUrlFragment);*/
if (resolveResult is Result<DidDocument, DidResolveErr>.Err(var err))
{
return new Result<Success, DidVerifyErr>.Err(err);
}
var (isVerified, verifySigErr) = VerifySignature(
pubkey,
challenge.Nonce,
Expand All @@ -79,7 +125,7 @@ Challenge challenge
return VerifyResponseResult.Success;
}

private (bool, DidSignatureErr?) VerifySignature(
private Result<Success, DidSignatureErr> VerifySignature(
JsonWebKey pubkey,
Nonce nonce,
Signature signature
Expand All @@ -88,13 +134,17 @@ Signature signature
throw new NotImplementedException("todo: do the cryptography");
}

private JsonWebKey RetrieveKey(DidDocument document, DidUrlFragment keyId)
private Result<JsonWebKey, DidFragmentErr> RetrieveKey(
DidDocument document,
DidUrlFragment keyId
)
{
JsonWebKey pubkeyJwk;
if (keyId.V.Equals(string.Empty))
{
if (document.Pubkeys.Count != 1)
{
return new Result<>.Err(new DidFragmentErr.AmbiguousFragment());
throw new DidResolveException(DidResolveErr.AmbiguousFragment);
}
pubkeyJwk = document.Pubkeys.First().Value;
Expand All @@ -106,7 +156,7 @@ private JsonWebKey RetrieveKey(DidDocument document, DidUrlFragment keyId)
return pubkeyJwk;
}

private async Task<DidDocument> ResolveDid(Did identity)
static async Task<Result<DidDocument, DidResolveErr>> ResolveDid(Did identity)
{
var segments = identity.V.Split(
separator: ":",
Expand All @@ -125,29 +175,6 @@ private async Task<DidDocument> ResolveDid(Did identity)
var resolver = Resolvers[method];
return await resolver.ResolveDocument(identity);
}

/// Errors related to validating to the signature itself.
public enum DidSignatureErr { }

/// Errors related to resolving a Did document from a Did.
public enum DidResolveErr
{
InvalidPrefix,
UnsupportedMethod,
NoSuchFragment,
AmbiguousFragment,
}

public sealed class DidResolveException : Exception
{
public DidResolveErr Error { get; }

public DidResolveException(DidResolveErr error)
: base(error.ToString())
{
Error = error;
}
}
}

/// Challenges are a randomized nonce. The nonce will be the payload
Expand All @@ -173,24 +200,4 @@ public record Response(
/// * `"z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"`
DidUrlFragment DidUrlFragment
);

/// Possible return values VerifyResponse method.
public enum VerifyResponseResult
{
/// The verification was successful
Success,

/// Was unable to resolve the Did to a DidDocument.
FailedToResolveDid,

/// The fragment in the response didn't exist in the DID Document resolved
/// from the challenge's identity.
NoSuchFragment,

/// The response signature did not match the challenge nonce
MismatchedNonce,

/// The verification failed due to an invalid signature
InvalidSig,
}
}
17 changes: 17 additions & 0 deletions Contrib/Auth/Did/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#nullable enable
using System;

namespace Basis.Contrib.Auth.DecentralizedIds.Result
{
public readonly struct Success { }

/// Analagous to rust's Result type.
public abstract record Result<T, E>
{
private Result() { }

public sealed record Ok(T Ok) : Result<T, E> { }

Check failure on line 13 in Contrib/Auth/Did/Result.cs

View workflow job for this annotation

GitHub Actions / Run `dotnet test`

Record member 'Basis.Contrib.Auth.DecentralizedIds.Result.Result<T, E>.Ok' must be a readable instance property or field of type 'T' to match positional parameter 'Ok'.

Check failure on line 13 in Contrib/Auth/Did/Result.cs

View workflow job for this annotation

GitHub Actions / Run `dotnet build`

Record member 'Basis.Contrib.Auth.DecentralizedIds.Result.Result<T, E>.Ok' must be a readable instance property or field of type 'T' to match positional parameter 'Ok'.

Check failure on line 13 in Contrib/Auth/Did/Result.cs

View workflow job for this annotation

GitHub Actions / Run `dotnet build`

Record member 'Basis.Contrib.Auth.DecentralizedIds.Result.Result<T, E>.Ok' must be a readable instance property or field of type 'T' to match positional parameter 'Ok'.

public sealed record Err(E Err) : Result<T, E> { }

Check failure on line 15 in Contrib/Auth/Did/Result.cs

View workflow job for this annotation

GitHub Actions / Run `dotnet test`

Record member 'Basis.Contrib.Auth.DecentralizedIds.Result.Result<T, E>.Err' must be a readable instance property or field of type 'E' to match positional parameter 'Err'.

Check failure on line 15 in Contrib/Auth/Did/Result.cs

View workflow job for this annotation

GitHub Actions / Run `dotnet build`

Record member 'Basis.Contrib.Auth.DecentralizedIds.Result.Result<T, E>.Err' must be a readable instance property or field of type 'E' to match positional parameter 'Err'.

Check failure on line 15 in Contrib/Auth/Did/Result.cs

View workflow job for this annotation

GitHub Actions / Run `dotnet build`

Record member 'Basis.Contrib.Auth.DecentralizedIds.Result.Result<T, E>.Err' must be a readable instance property or field of type 'E' to match positional parameter 'Err'.
}
}

0 comments on commit e35a099

Please sign in to comment.