diff --git a/.github/workflows/build-dotnet.yml b/.github/workflows/build-dotnet.yml
index c281b3eb9..cb09b8a2b 100644
--- a/.github/workflows/build-dotnet.yml
+++ b/.github/workflows/build-dotnet.yml
@@ -34,7 +34,7 @@ jobs:
- run: |
dotnet workload install ios
dotnet restore
- dotnet build -c Release /p:IsBrowser=true ./Trinsic
+ dotnet build -c Release -f net6.0 -p:IsBrowser=true ./Trinsic
dotnet build -c Release
dotnet test -c Release -v n
working-directory: ./dotnet
diff --git a/dotnet/.editorconfig b/dotnet/.editorconfig
index 796fc6597..30e12b719 100644
--- a/dotnet/.editorconfig
+++ b/dotnet/.editorconfig
@@ -1,4 +1,3 @@
-
[*]
charset = utf-8
end_of_line = lf
@@ -10,7 +9,7 @@ indent_size = 4
# Microsoft .NET properties
csharp_new_line_before_catch = false
csharp_new_line_before_members_in_object_initializers = false
-csharp_new_line_before_open_brace = accessors,control_blocks,events,indexers,properties,types
+csharp_new_line_before_open_brace = accessors, control_blocks, events, indexers, properties, types
csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion
csharp_style_var_elsewhere = true:suggestion
csharp_style_var_for_built_in_types = true:suggestion
diff --git a/dotnet/Directory.Build.props b/dotnet/Directory.Build.props
index 5405a7d3a..b3fa60092 100644
--- a/dotnet/Directory.Build.props
+++ b/dotnet/Directory.Build.props
@@ -1,25 +1,25 @@
-
-
- Trinsic Engineering Team
- Trinsic
- Apache-2.0
- https://github.com/trinsic-id/sdk
- Trinsic
- Trinsic SDK for NET
- https://github.com/trinsic-id/sdk.git
- git
- 1.0.0
- true
- snupkg
-
-
-
-
- full
- latest
- $(NoWarn);1591
- enable
- true
-
+
+
+ Trinsic Engineering Team
+ Trinsic
+ Apache-2.0
+ https://github.com/trinsic-id/sdk
+ Trinsic
+ Trinsic SDK for NET
+ https://github.com/trinsic-id/sdk.git
+ git
+ 1.0.0
+ true
+ snupkg
+
+
+
+
+ full
+ latest
+ $(NoWarn);1591
+ enable
+ true
+
\ No newline at end of file
diff --git a/dotnet/Tests/HostTests.cs b/dotnet/Tests/HostTests.cs
new file mode 100644
index 000000000..45da8500c
--- /dev/null
+++ b/dotnet/Tests/HostTests.cs
@@ -0,0 +1,69 @@
+using System.Threading.Tasks;
+using FluentAssertions;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Trinsic;
+using Trinsic.Services.Common.V1;
+using Xunit;
+
+namespace Tests;
+
+public class HostTests
+{
+ [Fact(DisplayName = "Test default service host")]
+ public async Task TestGenericHost() {
+ var host = Host
+ .CreateDefaultBuilder()
+ .ConfigureServices(services => {
+ services.AddTrinsic();
+ }).Build();
+
+ await host.StartAsync();
+
+ var providerService = host.Services.GetService();
+ var accountService = host.Services.GetRequiredService();
+
+ providerService.Should().NotBeNull();
+ accountService.Should().NotBeNull();
+
+ accountService.Options.ServerEndpoint.Should().Be(ServiceBase.DefaultServerEndpoint);
+ accountService.Options.ServerPort.Should().Be(ServiceBase.DefaultServerPort);
+ accountService.Options.ServerUseTls.Should().Be(ServiceBase.DefaultServerUseTls);
+ accountService.Options.DefaultEcosystem.Should().Be(ServiceBase.DefaultEcosystem);
+ accountService.Options.AuthToken.Should().Be(string.Empty);
+ accountService.TokenProvider.Should().BeOfType();
+
+ await host.StopAsync();
+ }
+
+ [Fact(DisplayName = "Test configured service host")]
+ public async Task TestConfiguredGenericHost() {
+ var host = Host
+ .CreateDefaultBuilder()
+ .ConfigureServices(services => {
+ services.AddTrinsic(options => {
+ options.AuthToken = "auth";
+ options.DefaultEcosystem = "eco";
+ options.ServerEndpoint = "example.com";
+ options.ServerPort = 42;
+ options.ServerUseTls = true;
+ });
+ }).Build();
+
+ await host.StartAsync();
+
+ var providerService = host.Services.GetService();
+ var accountService = host.Services.GetRequiredService();
+
+ providerService.Should().NotBeNull();
+ accountService.Should().NotBeNull();
+
+ accountService.Options.ServerEndpoint.Should().Be("example.com");
+ accountService.Options.ServerPort.Should().Be(42);
+ accountService.Options.ServerUseTls.Should().BeTrue();
+ accountService.Options.DefaultEcosystem.Should().Be("eco");
+ accountService.Options.AuthToken.Should().Be("auth");
+
+ await host.StopAsync();
+ }
+}
diff --git a/dotnet/Tests/Tests.cs b/dotnet/Tests/Tests.cs
index f07f45e6e..6b145c189 100644
--- a/dotnet/Tests/Tests.cs
+++ b/dotnet/Tests/Tests.cs
@@ -20,6 +20,7 @@
using Trinsic.Services.VerifiableCredentials.V1;
using FieldType = Trinsic.Services.VerifiableCredentials.Templates.V1.FieldType;
using JsonSerializer = System.Text.Json.JsonSerializer;
+
#pragma warning disable CS0618
namespace Tests;
@@ -32,9 +33,9 @@ public class Tests
const int DefaultPort = 5000;
const bool DefaultUseTls = false;
#else
- const string DefaultEndpoint = "staging-internal.trinsic.cloud";
- const int DefaultPort = 443;
- const bool DefaultUseTls = true;
+ private const string DefaultEndpoint = "staging-internal.trinsic.cloud";
+ private const int DefaultPort = 443;
+ private const bool DefaultUseTls = true;
#endif
private readonly ITestOutputHelper _testOutputHelper;
@@ -67,9 +68,9 @@ public async Task TestWalletService() {
// SETUP ACTORS
// Create 3 different profiles for each participant in the scenario
// setupActors() {
- var allison = await accountService.SignInAsync(new SignInRequest {EcosystemId = ecosystemId});
- var clinic = await accountService.SignInAsync(new SignInRequest {EcosystemId = ecosystemId});
- var airline = await accountService.SignInAsync(new SignInRequest {EcosystemId = ecosystemId});
+ var allison = await accountService.SignInAsync(new() {EcosystemId = ecosystemId});
+ var clinic = await accountService.SignInAsync(new() {EcosystemId = ecosystemId});
+ var airline = await accountService.SignInAsync(new() {EcosystemId = ecosystemId});
// }
accountService.Options.AuthToken = clinic;
@@ -251,7 +252,7 @@ public async Task TestInvitationIdSet() {
invitationResponse.Should().NotBeNull();
invitationResponse.InvitationCode.Should().NotBeEmpty();
- await Assert.ThrowsAsync(async () => await providerService.InvitationStatusAsync(new InvitationStatusRequest()));
+ await Assert.ThrowsAsync(async () => await providerService.InvitationStatusAsync(new()));
}
[Fact(Skip = "Ecosystem support not complete yet")]
@@ -263,7 +264,7 @@ public async Task TestInviteParticipant() {
var response = await myProviderService.InviteParticipantAsync(invite);
Assert.NotNull(response);
- var statusResponse = await myProviderService.InvitationStatusAsync(new InvitationStatusRequest {InvitationId = response.InvitationId});
+ var statusResponse = await myProviderService.InvitationStatusAsync(new() {InvitationId = response.InvitationId});
Assert.NotNull(statusResponse);
}
@@ -352,7 +353,6 @@ public async Task DemoTemplatesWithIssuance() {
}
}
}
-
public static class Extensions
{
public static ServiceOptions CloneWithAuthToken(this ServiceOptions options, string authToken) {
@@ -360,4 +360,4 @@ public static ServiceOptions CloneWithAuthToken(this ServiceOptions options, str
cloned.AuthToken = authToken;
return cloned;
}
-}
\ No newline at end of file
+}
diff --git a/dotnet/Tests/Tests.csproj b/dotnet/Tests/Tests.csproj
index f5e11665d..c47f1af61 100644
--- a/dotnet/Tests/Tests.csproj
+++ b/dotnet/Tests/Tests.csproj
@@ -10,9 +10,10 @@
4
-
-
-
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
@@ -27,16 +28,16 @@
-
+
-
- TestData/vaccination-certificate-unsigned.jsonld
- PreserveNewest
-
-
- TestData/vaccination-certificate-frame.jsonld
- PreserveNewest
-
+
+ TestData/vaccination-certificate-unsigned.jsonld
+ PreserveNewest
+
+
+ TestData/vaccination-certificate-frame.jsonld
+ PreserveNewest
+
\ No newline at end of file
diff --git a/dotnet/Trinsic/AccountService.cs b/dotnet/Trinsic/AccountService.cs
index b229c3f2c..1efd4e4e5 100644
--- a/dotnet/Trinsic/AccountService.cs
+++ b/dotnet/Trinsic/AccountService.cs
@@ -1,11 +1,11 @@
using System;
using System.Threading.Tasks;
using Google.Protobuf;
+using Microsoft.Extensions.Options;
using Okapi.Security;
using Okapi.Security.V1;
using Trinsic.Sdk.Options.V1;
using Trinsic.Services.Account.V1;
-using AccountServiceClient = Trinsic.Services.Account.V1.Account.AccountClient;
namespace Trinsic;
@@ -22,11 +22,20 @@ public AccountService(ServiceOptions options)
public AccountService() {
Client = new(Channel);
}
-
+
+ internal AccountService(ITokenProvider tokenProvider) : base(new(), tokenProvider) {
+ Client = new(Channel);
+ }
+
+ internal AccountService(ITokenProvider tokenProvider, IOptions options)
+ : base(options.Value, tokenProvider) {
+ Client = new(Channel);
+ }
+
///
/// Gets the underlying grpc client
///
- public AccountServiceClient Client { get; }
+ private Account.AccountClient Client { get; }
///
/// Perform a sign-in to obtain an account profile. If the are
@@ -35,16 +44,12 @@ public AccountService() {
///
///
public async Task SignInAsync(SignInRequest request) {
- if (string.IsNullOrWhiteSpace(request.EcosystemId)) {
- request.EcosystemId = Options.DefaultEcosystem;
- }
+ if (string.IsNullOrWhiteSpace(request.EcosystemId)) request.EcosystemId = Options.DefaultEcosystem;
var response = await Client.SignInAsync(request);
var authToken = Convert.ToBase64String(response.Profile.ToByteArray());
-
- if (!response.Profile.Protection?.Enabled ?? true) {
- Options.AuthToken = authToken;
- }
+
+ if (!response.Profile.Protection?.Enabled ?? true) await TokenProvider.SaveAsync(authToken);
return authToken;
}
@@ -55,13 +60,13 @@ public async Task SignInAsync(SignInRequest request) {
///
///
public string SignIn(SignInRequest request) {
- if (string.IsNullOrWhiteSpace(request.EcosystemId)) {
- request.EcosystemId = Options.DefaultEcosystem;
- }
+ if (string.IsNullOrWhiteSpace(request.EcosystemId)) request.EcosystemId = Options.DefaultEcosystem;
var response = Client.SignIn(request);
-
- Options.AuthToken = Convert.ToBase64String(response.Profile.ToByteArray());
- return Options.AuthToken;
+
+ var authToken = Convert.ToBase64String(response.Profile.ToByteArray());
+
+ if (!response.Profile.Protection?.Enabled ?? true) TokenProvider.Save(authToken);
+ return authToken;
}
///
@@ -150,4 +155,4 @@ public RevokeDeviceResponse RevokeDevice() {
RevokeDeviceRequest request = new();
return Client.RevokeDevice(request, BuildMetadata(request));
}
-}
\ No newline at end of file
+}
diff --git a/dotnet/Trinsic/CredentialsService.cs b/dotnet/Trinsic/CredentialsService.cs
index 1f1afac73..35aa581e1 100644
--- a/dotnet/Trinsic/CredentialsService.cs
+++ b/dotnet/Trinsic/CredentialsService.cs
@@ -1,5 +1,6 @@
using System;
using System.Threading.Tasks;
+using Microsoft.Extensions.Options;
using Trinsic.Sdk.Options.V1;
using Trinsic.Services.Common.V1;
using Trinsic.Services.VerifiableCredentials.Templates.V1;
@@ -18,6 +19,15 @@ public CredentialsService() {
Client = new(Channel);
}
+ internal CredentialsService(ITokenProvider tokenProvider) : base(new(), tokenProvider) {
+ Client = new(Channel);
+ }
+
+ internal CredentialsService(ITokenProvider tokenProvider, IOptions options)
+ : base(options.Value, tokenProvider) {
+ Client = new(Channel);
+ }
+
private VerifiableCredential.VerifiableCredentialClient Client { get; }
///
@@ -26,16 +36,12 @@ public CredentialsService() {
///
///
public async Task IssueCredentialAsync(IssueRequest request) {
- if (string.IsNullOrWhiteSpace(request.DocumentJson)) {
- throw new ArgumentException("document json must not be empty");
- }
+ if (string.IsNullOrWhiteSpace(request.DocumentJson)) throw new ArgumentException("document json must not be empty");
return await Client.IssueAsync(request, await BuildMetadataAsync(request));
}
public IssueResponse IssueCredential(IssueRequest request) {
- if (string.IsNullOrWhiteSpace(request.DocumentJson)) {
- throw new ArgumentException("document json must not be empty");
- }
+ if (string.IsNullOrWhiteSpace(request.DocumentJson)) throw new ArgumentException("document json must not be empty");
return Client.Issue(request, BuildMetadata(request));
}
@@ -86,16 +92,16 @@ public CreateProofResponse CreateProof(CreateProofRequest request) {
///
public async Task VerifyProofAsync(VerifyProofRequest request) {
var response = await Client.VerifyProofAsync(
- request: request,
- headers: await BuildMetadataAsync(request));
+ request,
+ await BuildMetadataAsync(request));
return response.IsValid;
}
public bool VerifyProof(VerifyProofRequest request) {
var response = Client.VerifyProof(
- request: request,
- headers: BuildMetadata(request));
+ request,
+ BuildMetadata(request));
return response.IsValid;
}
@@ -125,14 +131,14 @@ public async Task UpdateStatusAsync(string credentialStatusId, bool revoked) {
UpdateStatusRequest request = new() {CredentialStatusId = credentialStatusId, Revoked = revoked};
var response = await Client.UpdateStatusAsync(request, await BuildMetadataAsync(request));
if (response.Status == ResponseStatus.Success) return;
- throw new Exception($"Status not completely updated {response.Status}");
+ throw new($"Status not completely updated {response.Status}");
}
public void UpdateStatus(string credentialStatusId, bool revoked) {
UpdateStatusRequest request = new() {CredentialStatusId = credentialStatusId, Revoked = revoked};
var response = Client.UpdateStatus(request, BuildMetadata(request));
if (response.Status == ResponseStatus.Success) return;
- throw new Exception($"Status not completely updated {response.Status}");
+ throw new($"Status not completely updated {response.Status}");
}
@@ -143,13 +149,13 @@ public void UpdateStatus(string credentialStatusId, bool revoked) {
///
public async Task SendAsync(SendRequest request) {
var response = await Client.SendAsync(
- request: request,
- headers: await BuildMetadataAsync(request));
+ request,
+ await BuildMetadataAsync(request));
}
public void Send(SendRequest request) {
var response = Client.Send(
- request: request,
- headers: BuildMetadata(request));
+ request,
+ BuildMetadata(request));
}
-}
\ No newline at end of file
+}
diff --git a/dotnet/Trinsic/Extensions/MessageExtensions.cs b/dotnet/Trinsic/Extensions/MessageExtensions.cs
index f3da768a8..3870ec49d 100644
--- a/dotnet/Trinsic/Extensions/MessageExtensions.cs
+++ b/dotnet/Trinsic/Extensions/MessageExtensions.cs
@@ -10,8 +10,7 @@ public static class ProtoMessageExtensions
///
///
public static T As(this IMessage message)
- where T : IMessage, new()
- {
+ where T : IMessage, new() {
var target = new T();
target.MergeFrom(message.ToByteString());
diff --git a/dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs b/dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs
new file mode 100644
index 000000000..d0b859ce2
--- /dev/null
+++ b/dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using Microsoft.Extensions.Options;
+using Trinsic;
+using Trinsic.Sdk.Options.V1;
+
+namespace Microsoft.Extensions.DependencyInjection;
+
+[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
+[SuppressMessage("ReSharper", "UnusedType.Global")]
+[SuppressMessage("ReSharper", "UnusedMember.Global")]
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Registers Trinsic SDK services and dependencies
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddTrinsic(this IServiceCollection services, Action configure) {
+ services.Configure(configure);
+
+ return AddTrinsic(services);
+ }
+
+ ///
+ /// Registers Trinsic SDK services and dependencies
+ ///
+ ///
+ ///
+ public static IServiceCollection AddTrinsic(this IServiceCollection services) {
+#if __IOS__
+ services.AddSingleton();
+#elif __BROWSER__
+ services.AddSingleton();
+#else
+ services.AddSingleton();
+#endif
+ services.AddSingleton(provider =>
+ new(provider.GetRequiredService(),
+ provider.GetRequiredService>()));
+ services.AddSingleton(provider =>
+ new(provider.GetRequiredService(),
+ provider.GetRequiredService>()));
+ services.AddSingleton(provider =>
+ new(provider.GetRequiredService(),
+ provider.GetRequiredService>()));
+ services.AddSingleton(provider =>
+ new(provider.GetRequiredService(),
+ provider.GetRequiredService>()));
+ services.AddSingleton(provider =>
+ new(provider.GetRequiredService(),
+ provider.GetRequiredService>()));
+ services.AddSingleton(provider =>
+ new(provider.GetRequiredService(),
+ provider.GetRequiredService>()));
+ return services;
+ }
+}
diff --git a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs
index 2c033999a..d7854479d 100644
--- a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs
+++ b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs
@@ -4,6 +4,7 @@ namespace Trinsic.Services.Common.V1;
public static class ServiceOptionsExtensions
{
- public static string FormatUrl(this ServiceOptions options) =>
- $"{(options.ServerUseTls ? "https" : "http")}://{options.ServerEndpoint}:{options.ServerPort}";
-}
\ No newline at end of file
+ public static string FormatUrl(this ServiceOptions options) {
+ return $"{(options.ServerUseTls ? "https" : "http")}://{options.ServerEndpoint}:{options.ServerPort}";
+ }
+}
diff --git a/dotnet/Trinsic/ProviderService.cs b/dotnet/Trinsic/ProviderService.cs
index fa5597a6b..8f58ca2dc 100644
--- a/dotnet/Trinsic/ProviderService.cs
+++ b/dotnet/Trinsic/ProviderService.cs
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Google.Protobuf;
+using Microsoft.Extensions.Options;
using Trinsic.Sdk.Options.V1;
using Trinsic.Services.Provider.V1;
@@ -17,6 +18,15 @@ public ProviderService() {
Client = new(Channel);
}
+ internal ProviderService(ITokenProvider tokenProvider) : base(new(), tokenProvider) {
+ Client = new(Channel);
+ }
+
+ internal ProviderService(ITokenProvider tokenProvider, IOptions options)
+ : base(options.Value, tokenProvider) {
+ Client = new(Channel);
+ }
+
private Provider.ProviderClient Client { get; }
///
@@ -71,9 +81,7 @@ public InvitationStatusResponse InvitationStatus(InvitationStatusRequest request
var authToken = Convert.ToBase64String(response.Profile.ToByteArray());
- if (!response.Profile.Protection?.Enabled ?? false) {
- Options.AuthToken = authToken;
- }
+ if (!response.Profile.Protection?.Enabled ?? false) Options.AuthToken = authToken;
return (response.Ecosystem, authToken);
}
@@ -89,9 +97,7 @@ public InvitationStatusResponse InvitationStatus(InvitationStatusRequest request
var response = Client.CreateEcosystem(request);
var authToken = Convert.ToBase64String(response.Profile.ToByteArray());
- if (!response.Profile.Protection?.Enabled ?? true) {
- Options.AuthToken = authToken;
- }
+ if (!response.Profile.Protection?.Enabled ?? true) Options.AuthToken = authToken;
return (response.Ecosystem, authToken);
}
@@ -118,4 +124,4 @@ public string GenerateToken(GenerateTokenRequest request) {
return Convert.ToBase64String(response.ToByteArray());
}
-}
\ No newline at end of file
+}
diff --git a/dotnet/Trinsic/Security/OberonSecurityProvider.cs b/dotnet/Trinsic/Security/OberonSecurityProvider.cs
index 13771d748..e502556b5 100644
--- a/dotnet/Trinsic/Security/OberonSecurityProvider.cs
+++ b/dotnet/Trinsic/Security/OberonSecurityProvider.cs
@@ -11,8 +11,7 @@ namespace Trinsic;
internal class OberonSecurityProvider : ISecurityProvider
{
- public Task GetAuthHeaderAsync(AccountProfile accountProfile, IMessage message)
- {
+ public Task GetAuthHeaderAsync(AccountProfile accountProfile, IMessage message) {
return Task.FromResult(GetAuthHeader(accountProfile, message));
}
@@ -21,42 +20,38 @@ public Task GetAuthHeaderAsync(AccountProfile accountProfile, IMessage m
///
///
///
- private static string Base64UrlEncode(byte[] data) => Convert.ToBase64String(data)
- .Replace('+', '-')
- .Replace('/', '_')
- .Trim('=');
+ private static string Base64UrlEncode(byte[] data) {
+ return Convert.ToBase64String(data)
+ .Replace('+', '-')
+ .Replace('/', '_')
+ .Trim('=');
+ }
- public string GetAuthHeader(AccountProfile accountProfile, IMessage message)
- {
+ public string GetAuthHeader(AccountProfile accountProfile, IMessage message) {
if (accountProfile.Protection?.Enabled ?? false) throw new("The token must be unprotected before use.");
// compute the hash of the request and capture current timestamp
- byte[] requestBytes = message.ToByteArray();
- ByteString requestHash = ByteString.Empty;
+ var requestBytes = message.ToByteArray();
+ var requestHash = ByteString.Empty;
- if (requestBytes.Any())
- {
- requestHash = Okapi.Hashing.Blake3.Hash(new() {Data = ByteString.CopyFrom(requestBytes)}).Digest;
- }
+ if (requestBytes.Any()) requestHash = Okapi.Hashing.Blake3.Hash(new() {Data = ByteString.CopyFrom(requestBytes)}).Digest;
- Nonce nonce = new()
- {
+ Nonce nonce = new() {
Timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
RequestHash = requestHash
};
- var proof = Oberon.CreateProof(new()
- {
+ var proof = Oberon.CreateProof(new() {
Token = accountProfile!.AuthToken,
Data = accountProfile!.AuthData,
Nonce = nonce.ToByteString()
});
var header = "Oberon " +
- $"ver={1}," +
- $"proof={Base64UrlEncode(proof.Proof.ToByteArray())}," +
- $"data={Base64UrlEncode(accountProfile.AuthData.ToByteArray())}," +
- $"nonce={Base64UrlEncode(nonce.ToByteArray())}";
+ $"ver={1}," +
+ $"proof={Base64UrlEncode(proof.Proof.ToByteArray())}," +
+ $"data={Base64UrlEncode(accountProfile.AuthData.ToByteArray())}," +
+ $"nonce={Base64UrlEncode(nonce.ToByteArray())}";
return header;
}
diff --git a/dotnet/Trinsic/ServiceBase.cs b/dotnet/Trinsic/ServiceBase.cs
index f994daefe..ed74d4250 100644
--- a/dotnet/Trinsic/ServiceBase.cs
+++ b/dotnet/Trinsic/ServiceBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using Grpc.Core;
using Google.Protobuf;
using Trinsic.Services.Common.V1;
@@ -13,38 +14,39 @@
namespace Trinsic;
+[SuppressMessage("Usage", "CA2211:Non-constant fields should not be visible")]
public abstract class ServiceBase
{
- private const string DefaultEcosystem = "default";
- private const bool DefaultServerUseTls = true;
- private const int DefaultServerPort = 443;
- private const string DefaultServerEndpoint = "prod.trinsic.cloud";
-
- protected internal ServiceBase() {
- Options = new();
- EnsureOptionDefaults();
- Channel = CreateChannel(Options);
- }
+ internal const string DefaultEcosystem = "default";
+ internal const bool DefaultServerUseTls = true;
+ internal const int DefaultServerPort = 443;
+ internal const string DefaultServerEndpoint = "prod.trinsic.cloud";
+
+ protected internal readonly ITokenProvider TokenProvider;
+
+ protected internal ServiceBase() : this(new()) { }
protected internal ServiceBase(ServiceOptions options) {
Options = options;
EnsureOptionDefaults();
- Channel = CreateChannel(options);
+ Channel = CreateChannel(Options);
+
+#if __IOS__
+ TokenProvider = KeyChainTokenProvider.StaticInstance;
+#else
+ TokenProvider = FileTokenProvider.StaticInstance;
+#endif
+ }
+
+ protected internal ServiceBase(ServiceOptions options, ITokenProvider tokenProvider) : this(options) {
+ TokenProvider = tokenProvider;
}
private void EnsureOptionDefaults() {
- if (string.IsNullOrWhiteSpace(Options.ServerEndpoint)) {
- Options.ServerEndpoint = DefaultServerEndpoint;
- }
- if (Options.ServerPort == default) {
- Options.ServerPort = DefaultServerPort;
- }
- if (Options.ServerPort == DefaultServerPort) {
- Options.ServerUseTls = DefaultServerUseTls;
- }
- if (string.IsNullOrWhiteSpace(Options.DefaultEcosystem)) {
- Options.DefaultEcosystem = DefaultEcosystem;
- }
+ if (string.IsNullOrWhiteSpace(Options.ServerEndpoint)) Options.ServerEndpoint = DefaultServerEndpoint;
+ if (Options.ServerPort == default) Options.ServerPort = DefaultServerPort;
+ if (Options.ServerPort == DefaultServerPort) Options.ServerUseTls = DefaultServerUseTls;
+ if (string.IsNullOrWhiteSpace(Options.DefaultEcosystem)) Options.DefaultEcosystem = DefaultEcosystem;
}
private static GrpcChannel CreateChannel(ServiceOptions options) {
@@ -64,18 +66,17 @@ private static GrpcChannel CreateChannel(ServiceOptions options) {
/// Gets the gRPC channel used by this service. This channel can be reused
/// by passing this instance to other service constructors.
///
- public GrpcChannel Channel { get; set; }
+ protected GrpcChannel Channel { get; }
///
/// Create call metadata by setting the required authentication headers
///
///
protected async Task BuildMetadataAsync(IMessage request) {
- if (Options is null || string.IsNullOrWhiteSpace(Options.AuthToken)) {
- throw new("Cannot call authenticated endpoint: auth token must be set in service options");
- }
+ var authToken = string.IsNullOrWhiteSpace(Options.AuthToken) ? TokenProvider.Get() : Options.AuthToken;
+ if (authToken is null) throw new("Cannot call authenticated endpoint before signing in");
- var profile = AccountProfile.Parser.ParseFrom(Convert.FromBase64String(Options.AuthToken));
+ var profile = AccountProfile.Parser.ParseFrom(Convert.FromBase64String(authToken));
return new() {
{"Authorization", await _securityProvider.GetAuthHeaderAsync(profile, request)}
@@ -87,14 +88,13 @@ protected async Task BuildMetadataAsync(IMessage request) {
///
///
protected Metadata BuildMetadata(IMessage request) {
- if (Options is null || string.IsNullOrWhiteSpace(Options.AuthToken)) {
- throw new("Cannot call authenticated endpoint: auth token must be set in service options");
- }
+ var authToken = string.IsNullOrWhiteSpace(Options.AuthToken) ? TokenProvider.Get() : Options.AuthToken;
+ if (authToken is null) throw new("Cannot call authenticated endpoint before signing in");
- var profile = AccountProfile.Parser.ParseFrom(Convert.FromBase64String(Options.AuthToken));
+ var profile = AccountProfile.Parser.ParseFrom(Convert.FromBase64String(authToken));
return new() {
{"Authorization", _securityProvider.GetAuthHeader(profile, request)}
};
}
-}
\ No newline at end of file
+}
diff --git a/dotnet/Trinsic/Storage/BrowserTokenProvider.cs b/dotnet/Trinsic/Storage/BrowserTokenProvider.cs
new file mode 100644
index 000000000..89b1738a1
--- /dev/null
+++ b/dotnet/Trinsic/Storage/BrowserTokenProvider.cs
@@ -0,0 +1,35 @@
+#if __BROWSER__
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.JSInterop;
+using Microsoft.JSInterop.WebAssembly;
+
+namespace Trinsic;
+
+public class BrowserTokenProvider : ITokenProvider
+{
+ private readonly IJSRuntime _jsRuntime;
+ private string? _cachedToken;
+ public BrowserTokenProvider(IJSRuntime jsRuntime) {
+ _jsRuntime = jsRuntime;
+ }
+
+ public async Task GetAsync(string name = TokenDefaults.Name, CancellationToken cancellationToken = default) {
+ if (_cachedToken is not null) return _cachedToken;
+
+ _cachedToken = await _jsRuntime.InvokeAsync("localStorage.getItem", cancellationToken, name);
+ return _cachedToken;
+ }
+ public string? Get(string name = TokenDefaults.Name) {
+ throw new NotImplementedException("sync method not supported, please use async overload instead");
+ }
+ public async Task SaveAsync(string authToken, string name = TokenDefaults.Name, CancellationToken cancellationToken = default) {
+ _cachedToken = authToken;
+ await _jsRuntime.InvokeVoidAsync("localStorage.setItem", cancellationToken, name, authToken);
+ }
+ public void Save(string authToken, string name = TokenDefaults.Name) {
+ throw new NotImplementedException("sync method not supported, please use async overload instead");
+ }
+}
+#endif
diff --git a/dotnet/Trinsic/Storage/FileProfileProvider.cs b/dotnet/Trinsic/Storage/FileProfileProvider.cs
deleted file mode 100644
index 8faad1fc2..000000000
--- a/dotnet/Trinsic/Storage/FileProfileProvider.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using System.IO;
-using System.Security.Cryptography;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Google.Protobuf;
-using Multiformats.Base;
-using Trinsic.Services.Account.V1;
-
-namespace Trinsic;
-
-internal class FileProfileProvider : IProfileProvider
-{
- public async Task GetAsync(string name, CancellationToken cancellationToken = default)
- {
- var rootPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
- var filename = Path.Combine(
- rootPath,
- Multibase.Base58.Encode(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(name))));
-
- return AccountProfile.Parser.ParseFrom(
- await File.ReadAllBytesAsync(filename, cancellationToken));
- }
-
- public Task SaveAsync(string name, AccountProfile accountProfile, CancellationToken cancellationToken = default)
- {
- var rootPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
- var filename = Path.Combine(
- rootPath,
- Multibase.Base58.Encode(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(name))));
-
- return File.WriteAllBytesAsync(filename, accountProfile.ToByteArray(), cancellationToken);
- }
-}
\ No newline at end of file
diff --git a/dotnet/Trinsic/Storage/FileTokenProvider.cs b/dotnet/Trinsic/Storage/FileTokenProvider.cs
new file mode 100644
index 000000000..f3ceb235e
--- /dev/null
+++ b/dotnet/Trinsic/Storage/FileTokenProvider.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Trinsic;
+
+internal class FileTokenProvider : ITokenProvider
+{
+ private const string Vendor = "Trinsic";
+
+ public static FileTokenProvider StaticInstance => new();
+
+ private string? _cachedToken;
+
+ public async Task GetAsync(string name = TokenDefaults.Name, CancellationToken cancellationToken = default) {
+ if (_cachedToken is not null) return _cachedToken;
+
+ var rootPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ var filename = Path.Combine(rootPath, Vendor, name);
+
+ try {
+ _cachedToken = await File.ReadAllTextAsync(filename, cancellationToken);
+ } catch {
+ // ignored
+ }
+ return _cachedToken;
+ }
+ public string? Get(string name = TokenDefaults.Name) {
+ if (_cachedToken is not null) return _cachedToken;
+
+ var rootPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ var filename = Path.Combine(rootPath, Vendor, name);
+
+ try {
+ _cachedToken = File.ReadAllText(filename);
+ } catch {
+ // ignored
+ }
+ return _cachedToken;
+ }
+
+ public Task SaveAsync(string authToken, string name = TokenDefaults.Name, CancellationToken cancellationToken = default) {
+ var rootPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ var filename = Path.Combine(rootPath, Vendor, name);
+
+ Directory.CreateDirectory(Path.Combine(rootPath, Vendor));
+
+ _cachedToken = authToken;
+
+ return File.WriteAllTextAsync(filename, authToken, cancellationToken);
+ }
+ public void Save(string authToken, string name = TokenDefaults.Name) {
+ var rootPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ var filename = Path.Combine(rootPath, Vendor, name);
+
+ Directory.CreateDirectory(Path.Combine(rootPath, Vendor));
+
+ _cachedToken = authToken;
+
+ File.WriteAllText(filename, authToken);
+ }
+}
diff --git a/dotnet/Trinsic/Storage/IProfileProvider.cs b/dotnet/Trinsic/Storage/IProfileProvider.cs
deleted file mode 100644
index 890a0ed75..000000000
--- a/dotnet/Trinsic/Storage/IProfileProvider.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Threading;
-using System.Threading.Tasks;
-using Trinsic.Services.Account.V1;
-
-namespace Trinsic;
-
-public interface IProfileProvider
-{
- Task GetAsync(string name, CancellationToken cancellationToken = default);
-
- Task SaveAsync(string name, AccountProfile accountProfile, CancellationToken cancellationToken = default);
-}
diff --git a/dotnet/Trinsic/Storage/ITokenProvider.cs b/dotnet/Trinsic/Storage/ITokenProvider.cs
new file mode 100644
index 000000000..0339387c1
--- /dev/null
+++ b/dotnet/Trinsic/Storage/ITokenProvider.cs
@@ -0,0 +1,21 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Trinsic;
+
+[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
+internal class TokenDefaults
+{
+ internal const string Name = "dotnet.authtoken";
+}
+public interface ITokenProvider
+{
+ Task GetAsync(string name = TokenDefaults.Name, CancellationToken cancellationToken = default);
+
+ string? Get(string name = TokenDefaults.Name);
+
+ Task SaveAsync(string authToken, string name = TokenDefaults.Name, CancellationToken cancellationToken = default);
+
+ void Save(string authToken, string name = TokenDefaults.Name);
+}
diff --git a/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs b/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs
new file mode 100644
index 000000000..6e4887e43
--- /dev/null
+++ b/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs
@@ -0,0 +1,58 @@
+#if __IOS__
+
+using System.Threading.Tasks;
+using Google.Protobuf;
+using Trinsic.Services.Account.V1;
+using Foundation;
+using Security;
+using System.Threading;
+using Intents;
+
+namespace Trinsic;
+
+internal class KeyChainTokenProvider : ITokenProvider
+{
+ public static KeyChainTokenProvider StaticInstance => new();
+
+ public Task GetAsync(string name, CancellationToken cancellationToken = default) {
+ return Task.Run(() => Get(name), cancellationToken);
+ }
+ public string? Get(string name) {
+ var rec = new SecRecord(SecKind.GenericPassword) {
+ Generic = NSData.FromString(name)
+ };
+
+ var @record = SecKeyChain.QueryAsRecord(rec, out var res);
+ return res != SecStatusCode.Success ? null : @record!.ValueData!.ToString();
+ }
+
+ public Task SaveAsync(string authToken, string name = "default", CancellationToken cancellationToken = default) {
+ return Task.Run(() => Save(authToken, name), cancellationToken);
+ }
+
+ public void Save(string authToken, string name = "default") {
+ var rec = new SecRecord(SecKind.GenericPassword) {
+ Generic = NSData.FromString(name)
+ };
+ _ = SecKeyChain.QueryAsRecord(rec, out var res);
+ if (res != SecStatusCode.Success) {
+ var s = new SecRecord(SecKind.GenericPassword) {
+ Label = $"Account Profile: {name}",
+ Description = "Oberon Account Profile",
+ Account = "Account",
+ Service = "Service",
+ Comment = "Your comment here",
+ ValueData = NSData.FromString(authToken),
+ Generic = NSData.FromString(name)
+ };
+
+ var err = SecKeyChain.Add(s);
+ if (err != SecStatusCode.Success) throw new($"error saving token: {err:G}");
+ }
+ else {
+ throw new("Profile already exists");
+ }
+ }
+}
+
+#endif
diff --git a/dotnet/Trinsic/Storage/KeychainProfileProvider.cs b/dotnet/Trinsic/Storage/KeychainProfileProvider.cs
deleted file mode 100644
index a2dada480..000000000
--- a/dotnet/Trinsic/Storage/KeychainProfileProvider.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-
-#if __IOS__
-
-using System.Threading.Tasks;
-using Google.Protobuf;
-using Trinsic.Services.Account.V1;
-using Foundation;
-using Security;
-using System.Threading;
-using System;
-using Multiformats.Base;
-using System.Security.Cryptography;
-using System.Text;
-
-namespace Trinsic;
-
-internal class KeychainProfileProvider : IProfileProvider
-{
- public Task GetAsync(string name, CancellationToken cancellationToken = default)
- {
- var nameSerialized = Multibase.Base58.Encode(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(name)));
-
- var rec = new SecRecord(SecKind.GenericPassword)
- {
- Generic = NSData.FromString(nameSerialized)
- };
-
- var match = SecKeyChain.QueryAsRecord(rec, out SecStatusCode res);
- if (res != SecStatusCode.Success)
- {
- throw new("Profile not found");
- }
-
- return Task.FromResult(AccountProfile.Parser.ParseFrom(rec.ValueData!.ToArray()));
- }
-
- public Task SaveAsync(string name, AccountProfile accountProfile, CancellationToken cancellationToken = default)
- {
- var nameSerialized = Multibase.Base58.Encode(SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(name)));
-
- var rec = new SecRecord(SecKind.GenericPassword)
- {
- Generic = NSData.FromString(nameSerialized)
- };
- _ = SecKeyChain.QueryAsRecord(rec, out SecStatusCode res);
- if (res != SecStatusCode.Success)
- {
- var s = new SecRecord(SecKind.GenericPassword)
- {
- Label = $"Account Profile: {name}",
- Description = "Oberon Account Profile",
- Account = "Account",
- Service = "Service",
- Comment = "Your comment here",
- ValueData = NSData.FromArray(accountProfile.ToByteArray()),
- Generic = NSData.FromString(nameSerialized)
- };
-
- var err = SecKeyChain.Add(s);
- }
- else
- {
- throw new("Profile already exists");
- }
-
- return Task.CompletedTask;
- }
-}
-
-#endif
diff --git a/dotnet/Trinsic/TemplateService.cs b/dotnet/Trinsic/TemplateService.cs
index 1360fd285..9c568e3b3 100644
--- a/dotnet/Trinsic/TemplateService.cs
+++ b/dotnet/Trinsic/TemplateService.cs
@@ -1,8 +1,6 @@
using System.Threading.Tasks;
-using Grpc.Net.Client;
+using Microsoft.Extensions.Options;
using Trinsic.Sdk.Options.V1;
-using Trinsic.Services.Account.V1;
-using Trinsic.Services.Common.V1;
using Trinsic.Services.VerifiableCredentials.Templates.V1;
namespace Trinsic;
@@ -21,7 +19,16 @@ public TemplateService() {
Client = new(Channel);
}
- private CredentialTemplates.CredentialTemplatesClient Client { get; set; }
+ internal TemplateService(ITokenProvider tokenProvider) : base(new(), tokenProvider) {
+ Client = new(Channel);
+ }
+
+ internal TemplateService(ITokenProvider tokenProvider, IOptions options)
+ : base(options.Value, tokenProvider) {
+ Client = new(Channel);
+ }
+
+ private CredentialTemplates.CredentialTemplatesClient Client { get; }
///
/// Create new credential template with the given parameters
@@ -48,7 +55,7 @@ public async Task GetAsync(GetCredentialTemplateR
public GetCredentialTemplateResponse Get(GetCredentialTemplateRequest request) {
return Client.Get(request, BuildMetadata(request));
}
-
+
///
/// List the available templates for the given ecosystem.
/// Results can be customized using a SQL query.
@@ -64,7 +71,7 @@ public GetCredentialTemplateResponse Get(GetCredentialTemplateRequest request) {
public async Task ListAsync(ListCredentialTemplatesRequest request) {
return await Client.ListAsync(request, await BuildMetadataAsync(request));
}
-
+
public ListCredentialTemplatesResponse List(ListCredentialTemplatesRequest request) {
return Client.List(request, BuildMetadata(request));
}
@@ -96,4 +103,4 @@ public async Task DeleteAsync(DeleteCredential
public DeleteCredentialTemplateResponse Delete(DeleteCredentialTemplateRequest request) {
return Client.Delete(request, BuildMetadata(request));
}
-}
\ No newline at end of file
+}
diff --git a/dotnet/Trinsic/Trinsic.csproj b/dotnet/Trinsic/Trinsic.csproj
index 7d4cefd8d..1db5451c5 100644
--- a/dotnet/Trinsic/Trinsic.csproj
+++ b/dotnet/Trinsic/Trinsic.csproj
@@ -13,9 +13,10 @@
-
+
+
-
+
- <_BuiltProjectOutputGroupOutputIntermediate Remove="$(OutDir)$(_DeploymentTargetApplicationManifestFileName)" />
-
+ <_BuiltProjectOutputGroupOutputIntermediate Remove="$(OutDir)$(_DeploymentTargetApplicationManifestFileName)"/>
+
-
-
+
-
+
+
+
none
@@ -42,23 +44,26 @@
<_Parameter1>Tests
+
+ <_Parameter1>Trinsic.Browser
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
+
diff --git a/dotnet/Trinsic/Trinsic.xml b/dotnet/Trinsic/Trinsic.xml
index 43a5efd23..534a3ca5f 100644
--- a/dotnet/Trinsic/Trinsic.xml
+++ b/dotnet/Trinsic/Trinsic.xml
@@ -2843,5 +2843,20 @@
+
+
+ Registers Trinsic SDK services and dependencies
+
+
+
+
+
+
+
+ Registers Trinsic SDK services and dependencies
+
+
+
+
diff --git a/dotnet/Trinsic/TrustRegistryService.cs b/dotnet/Trinsic/TrustRegistryService.cs
index a3a61f81b..7998dcc8c 100644
--- a/dotnet/Trinsic/TrustRegistryService.cs
+++ b/dotnet/Trinsic/TrustRegistryService.cs
@@ -1,9 +1,8 @@
using System;
using System.Threading.Tasks;
using Grpc.Core;
-using Grpc.Net.Client;
+using Microsoft.Extensions.Options;
using Trinsic.Sdk.Options.V1;
-using Trinsic.Services.Account.V1;
using Trinsic.Services.Common.V1;
using Trinsic.Services.TrustRegistry.V1;
@@ -20,6 +19,14 @@ public TrustRegistryService() {
Client = new(Channel);
}
+ internal TrustRegistryService(ITokenProvider tokenProvider)
+ : this(tokenProvider, Microsoft.Extensions.Options.Options.Create(new ServiceOptions())) { }
+
+ internal TrustRegistryService(ITokenProvider tokenProvider, IOptions options)
+ : base(options.Value, tokenProvider) {
+ Client = new(Channel);
+ }
+
private TrustRegistry.TrustRegistryClient Client { get; }
///
@@ -32,9 +39,7 @@ public TrustRegistryService() {
/// The framework description
///
public async Task RegisterGovernanceFrameworkAsync(string governanceFramework, string description) {
- if (!Uri.TryCreate(governanceFramework, UriKind.Absolute, out _)) {
- throw new("Invalid URI string");
- }
+ if (!Uri.TryCreate(governanceFramework, UriKind.Absolute, out _)) throw new("Invalid URI string");
AddFrameworkRequest request = new() {
GovernanceFramework = new() {
@@ -46,9 +51,7 @@ public async Task RegisterGovernanceFrameworkAsync(string governanceFramework, s
}
public void RegisterGovernanceFramework(string governanceFramework, string description) {
- if (!Uri.TryCreate(governanceFramework, UriKind.Absolute, out _)) {
- throw new("Invalid URI string");
- }
+ if (!Uri.TryCreate(governanceFramework, UriKind.Absolute, out _)) throw new("Invalid URI string");
AddFrameworkRequest request = new() {
GovernanceFramework = new() {
GovernanceFrameworkUri = governanceFramework,
@@ -73,16 +76,12 @@ public RemoveFrameworkResponse RemoveGovernanceFramework(RemoveFrameworkRequest
///
public async Task RegisterIssuerAsync(RegisterIssuerRequest request) {
var response = await Client.RegisterIssuerAsync(request, await BuildMetadataAsync(request));
- if (response.Status != ResponseStatus.Success) {
- throw new($"cannot register issuer: code {response.Status}");
- }
+ if (response.Status != ResponseStatus.Success) throw new($"cannot register issuer: code {response.Status}");
}
public void RegisterIssuer(RegisterIssuerRequest request) {
var response = Client.RegisterIssuer(request, BuildMetadata(request));
- if (response.Status != ResponseStatus.Success) {
- throw new($"cannot register issuer: code {response.Status}");
- }
+ if (response.Status != ResponseStatus.Success) throw new($"cannot register issuer: code {response.Status}");
}
public async Task UnregisterIssuerAsync(UnregisterIssuerRequest request) {
@@ -100,16 +99,12 @@ public UnregisterIssuerResponse UnregisterIssuer(UnregisterIssuerRequest request
///
public async Task RegisterVerifierAsync(RegisterVerifierRequest request) {
var response = await Client.RegisterVerifierAsync(request, await BuildMetadataAsync(request));
- if (response.Status != ResponseStatus.Success) {
- throw new($"cannot register verifier: code {response.Status}");
- }
+ if (response.Status != ResponseStatus.Success) throw new($"cannot register verifier: code {response.Status}");
}
public void RegisterVerifier(RegisterVerifierRequest request) {
var response = Client.RegisterVerifier(request, BuildMetadata(request));
- if (response.Status != ResponseStatus.Success) {
- throw new($"cannot register verifier: code {response.Status}");
- }
+ if (response.Status != ResponseStatus.Success) throw new($"cannot register verifier: code {response.Status}");
}
public async Task UnregisterVerifierAsync(UnregisterVerifierRequest request) {
@@ -144,7 +139,7 @@ public async Task CheckVerifierStatusAsync(CheckVerifierStat
return response.Status;
}
-
+
public RegistrationStatus CheckVerifierStatus(CheckVerifierStatusRequest request) {
return Client.CheckVerifierStatus(request, BuildMetadata(request)).Status;
}
@@ -175,4 +170,4 @@ public SearchRegistryResponse SearchRegistry(string query = "SELECT * FROM c", s
public IAsyncStreamReader FetchData(FetchDataRequest request) {
return Client.FetchData(request, BuildMetadata(request)).ResponseStream;
}
-}
\ No newline at end of file
+}
diff --git a/dotnet/Trinsic/WalletService.cs b/dotnet/Trinsic/WalletService.cs
index aa187a94d..7f018b125 100644
--- a/dotnet/Trinsic/WalletService.cs
+++ b/dotnet/Trinsic/WalletService.cs
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
+using Microsoft.Extensions.Options;
using Trinsic.Services.UniversalWallet.V1;
using Trinsic.Sdk.Options.V1;
@@ -15,6 +16,14 @@ public WalletService() {
Client = new(Channel);
}
+ internal WalletService(ITokenProvider tokenProvider)
+ : this(tokenProvider, Microsoft.Extensions.Options.Options.Create(new ServiceOptions())) { }
+
+ internal WalletService(ITokenProvider tokenProvider, IOptions options)
+ : base(options.Value, tokenProvider) {
+ Client = new(Channel);
+ }
+
private UniversalWallet.UniversalWalletClient Client { get; }
///
@@ -25,9 +34,8 @@ public WalletService() {
/// See https://docs.microsoft.com/en-us/azure/cosmos-db/sql-query-select
///
///
- public async Task SearchAsync(string query = "SELECT * FROM c")
- {
- SearchRequest request = new() { Query = query };
+ public async Task SearchAsync(string query = "SELECT * FROM c") {
+ SearchRequest request = new() {Query = query};
var response = await Client.SearchAsync(request, await BuildMetadataAsync(request));
return response;
}
@@ -40,9 +48,8 @@ public async Task SearchAsync(string query = "SELECT * FROM c")
/// See https://docs.microsoft.com/en-us/azure/cosmos-db/sql-query-select
///
///
- public SearchResponse Search(string query = "SELECT * FROM c")
- {
- SearchRequest request = new() { Query = query };
+ public SearchResponse Search(string query = "SELECT * FROM c") {
+ SearchRequest request = new() {Query = query};
var response = Client.Search(request, BuildMetadata(request));
return response;
}
@@ -54,8 +61,8 @@ public SearchResponse Search(string query = "SELECT * FROM c")
///
public async Task InsertItemAsync(InsertItemRequest request) {
var response = await Client.InsertItemAsync(
- request: request,
- headers: await BuildMetadataAsync(request));
+ request,
+ await BuildMetadataAsync(request));
return response.ItemId;
}
@@ -66,8 +73,8 @@ public async Task InsertItemAsync(InsertItemRequest request) {
///
public string InsertItem(InsertItemRequest request) {
var response = Client.InsertItem(
- request: request,
- headers: BuildMetadata(request));
+ request,
+ BuildMetadata(request));
return response.ItemId;
}
diff --git a/node/.env b/node/.env
index 3ef4fdec6..dc8bf2f84 100644
--- a/node/.env
+++ b/node/.env
@@ -1,3 +1,3 @@
-TEST_SERVER_ENDPOINT=dev-internal.trinsic.cloud
+TEST_SERVER_ENDPOINT=staging-internal.trinsic.cloud
TEST_SERVER_PORT=443
TEST_SERVER_USE_TLS=true
\ No newline at end of file
diff --git a/node/test/TestData.ts b/node/test/TestData.ts
index 4d3facdfa..bb1261bcd 100644
--- a/node/test/TestData.ts
+++ b/node/test/TestData.ts
@@ -21,7 +21,7 @@ export function getVaccineCertUnsignedJSON(): any {
}
export function getTestServerOptions(): ServiceOptions {
- const endpoint = process.env.TEST_SERVER_ENDPOINT || "dev-internal.trinsic.cloud";
+ const endpoint = process.env.TEST_SERVER_ENDPOINT || "staging-internal.trinsic.cloud";
const port = process.env.TEST_SERVER_PORT || "443";
const useTls = (process.env.TEST_SERVER_USE_TLS || "true") != "false";
diff --git a/web/test/env.js b/web/test/env.js
index aac195f12..f179f113a 100644
--- a/web/test/env.js
+++ b/web/test/env.js
@@ -1,6 +1,7 @@
const { ServiceOptions } = require("../lib/proto");
export const options = new ServiceOptions()
- .setServerEndpoint("dev-internal.trinsic.cloud")
+ .setServerEndpoint("staging-internal.trinsic.cloud")
.setServerPort(443)
- .setServerUseTls(true);
+ .setServerUseTls(true)
+ .setDefaultEcosystem("default");