From 11cf896e0d67333526a5f9916deca59a7995df1e Mon Sep 17 00:00:00 2001 From: Tomislav Markovski Date: Thu, 17 Mar 2022 10:30:08 -0400 Subject: [PATCH 1/6] Experimental token provider implementation --- .../Trinsic.Browser/BrowserTokenProvider.cs | 30 ++++++++ dotnet/Trinsic.Browser/Extensions.cs | 29 ++++++++ dotnet/Trinsic.Browser/Trinsic.Browser.csproj | 20 ++++++ dotnet/Trinsic/AccountService.cs | 16 +++-- dotnet/Trinsic/CredentialsService.cs | 4 ++ .../Extensions/ServiceOptionsExtensions.cs | 18 +++++ dotnet/Trinsic/ProviderService.cs | 4 ++ dotnet/Trinsic/ServiceBase.cs | 36 ++++++---- dotnet/Trinsic/Storage/FileProfileProvider.cs | 35 ---------- dotnet/Trinsic/Storage/FileTokenProvider.cs | 63 +++++++++++++++++ dotnet/Trinsic/Storage/IProfileProvider.cs | 12 ---- dotnet/Trinsic/Storage/ITokenProvider.cs | 22 ++++++ .../Trinsic/Storage/KeyChainTokenProvider.cs | 61 ++++++++++++++++ .../Storage/KeychainProfileProvider.cs | 70 ------------------- dotnet/Trinsic/TemplateService.cs | 7 +- dotnet/Trinsic/Trinsic.csproj | 6 +- dotnet/Trinsic/TrustRegistryService.cs | 6 +- dotnet/Trinsic/WalletService.cs | 4 ++ dotnet/TrinsicSdk.sln | 14 ++++ 19 files changed, 318 insertions(+), 139 deletions(-) create mode 100644 dotnet/Trinsic.Browser/BrowserTokenProvider.cs create mode 100644 dotnet/Trinsic.Browser/Extensions.cs create mode 100644 dotnet/Trinsic.Browser/Trinsic.Browser.csproj delete mode 100644 dotnet/Trinsic/Storage/FileProfileProvider.cs create mode 100644 dotnet/Trinsic/Storage/FileTokenProvider.cs delete mode 100644 dotnet/Trinsic/Storage/IProfileProvider.cs create mode 100644 dotnet/Trinsic/Storage/ITokenProvider.cs create mode 100644 dotnet/Trinsic/Storage/KeyChainTokenProvider.cs delete mode 100644 dotnet/Trinsic/Storage/KeychainProfileProvider.cs diff --git a/dotnet/Trinsic.Browser/BrowserTokenProvider.cs b/dotnet/Trinsic.Browser/BrowserTokenProvider.cs new file mode 100644 index 000000000..9095c8a65 --- /dev/null +++ b/dotnet/Trinsic.Browser/BrowserTokenProvider.cs @@ -0,0 +1,30 @@ +using Microsoft.JSInterop; +using Microsoft.JSInterop.WebAssembly; + +namespace Trinsic.Browser; + +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"); + } +} diff --git a/dotnet/Trinsic.Browser/Extensions.cs b/dotnet/Trinsic.Browser/Extensions.cs new file mode 100644 index 000000000..72c224967 --- /dev/null +++ b/dotnet/Trinsic.Browser/Extensions.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; +using Trinsic.Browser; +using Trinsic.Sdk.Options.V1; + +namespace Trinsic; + +public static class Extensions +{ + /// + /// Add Trinsic SDK services and dependencies + /// + /// + /// + /// + public static IServiceCollection AddTrinsicBrowser(this IServiceCollection services, Action? configure = default) { + + services.Configure(configure); + + services.AddSingleton(); + services.AddSingleton(provider => new(provider.GetRequiredService())); + services.AddSingleton(provider => new(provider.GetRequiredService())); + services.AddSingleton(provider => new(provider.GetRequiredService())); + services.AddSingleton(provider => new(provider.GetRequiredService())); + ; + services.AddSingleton(provider => new(provider.GetRequiredService())); + services.AddSingleton(provider => new(provider.GetRequiredService())); + return services; + } +} diff --git a/dotnet/Trinsic.Browser/Trinsic.Browser.csproj b/dotnet/Trinsic.Browser/Trinsic.Browser.csproj new file mode 100644 index 000000000..086074382 --- /dev/null +++ b/dotnet/Trinsic.Browser/Trinsic.Browser.csproj @@ -0,0 +1,20 @@ + + + + net6.0 + enable + enable + + false + $(DefineConstants);__BROWSER__ + + + + + + + + + + + diff --git a/dotnet/Trinsic/AccountService.cs b/dotnet/Trinsic/AccountService.cs index b229c3f2c..d7ef6c8d5 100644 --- a/dotnet/Trinsic/AccountService.cs +++ b/dotnet/Trinsic/AccountService.cs @@ -22,7 +22,11 @@ public AccountService(ServiceOptions options) public AccountService() { Client = new(Channel); } - + + internal AccountService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + Client = new(Channel); + } + /// /// Gets the underlying grpc client /// @@ -43,7 +47,7 @@ public async Task SignInAsync(SignInRequest request) { var authToken = Convert.ToBase64String(response.Profile.ToByteArray()); if (!response.Profile.Protection?.Enabled ?? true) { - Options.AuthToken = authToken; + await TokenProvider.SaveAsync(authToken); } return authToken; } @@ -60,8 +64,12 @@ public string SignIn(SignInRequest request) { } 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; } /// diff --git a/dotnet/Trinsic/CredentialsService.cs b/dotnet/Trinsic/CredentialsService.cs index 1f1afac73..4c677b7eb 100644 --- a/dotnet/Trinsic/CredentialsService.cs +++ b/dotnet/Trinsic/CredentialsService.cs @@ -17,6 +17,10 @@ public CredentialsService(ServiceOptions options) public CredentialsService() { Client = new(Channel); } + + internal CredentialsService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + Client = new(Channel); + } private VerifiableCredential.VerifiableCredentialClient Client { get; } diff --git a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs index 2c033999a..b96362ee1 100644 --- a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs +++ b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs @@ -1,3 +1,5 @@ +using System; +using Microsoft.Extensions.DependencyInjection; using Trinsic.Sdk.Options.V1; namespace Trinsic.Services.Common.V1; @@ -6,4 +8,20 @@ public static class ServiceOptionsExtensions { public static string FormatUrl(this ServiceOptions options) => $"{(options.ServerUseTls ? "https" : "http")}://{options.ServerEndpoint}:{options.ServerPort}"; +} + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddTrinsic(this IServiceCollection services, Action? configure = default) { + + services.Configure(configure); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + return services; + } } \ No newline at end of file diff --git a/dotnet/Trinsic/ProviderService.cs b/dotnet/Trinsic/ProviderService.cs index fa5597a6b..7f6d168db 100644 --- a/dotnet/Trinsic/ProviderService.cs +++ b/dotnet/Trinsic/ProviderService.cs @@ -16,6 +16,10 @@ public ProviderService(ServiceOptions options) public ProviderService() { Client = new(Channel); } + + internal ProviderService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + Client = new(Channel); + } private Provider.ProviderClient Client { get; } diff --git a/dotnet/Trinsic/ServiceBase.cs b/dotnet/Trinsic/ServiceBase.cs index f994daefe..d45cfd71a 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,23 +14,32 @@ 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 readonly ITokenProvider TokenProvider; - protected internal ServiceBase() { - Options = new(); - EnsureOptionDefaults(); - Channel = CreateChannel(Options); - } + protected internal ServiceBase() : this(new()) { } protected internal ServiceBase(ServiceOptions options) { Options = options; EnsureOptionDefaults(); 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() { @@ -64,18 +74,19 @@ 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,11 +98,12 @@ 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)} 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..f21698e63 --- /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); + } +} \ No newline at end of file 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..efc53dadb --- /dev/null +++ b/dotnet/Trinsic/Storage/ITokenProvider.cs @@ -0,0 +1,22 @@ +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..48647447c --- /dev/null +++ b/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs @@ -0,0 +1,61 @@ + +#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 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.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..69fae2f33 100644 --- a/dotnet/Trinsic/TemplateService.cs +++ b/dotnet/Trinsic/TemplateService.cs @@ -1,8 +1,5 @@ using System.Threading.Tasks; -using Grpc.Net.Client; using Trinsic.Sdk.Options.V1; -using Trinsic.Services.Account.V1; -using Trinsic.Services.Common.V1; using Trinsic.Services.VerifiableCredentials.Templates.V1; namespace Trinsic; @@ -20,6 +17,10 @@ public TemplateService(ServiceOptions options) public TemplateService() { Client = new(Channel); } + + internal TemplateService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + Client = new(Channel); + } private CredentialTemplates.CredentialTemplatesClient Client { get; set; } diff --git a/dotnet/Trinsic/Trinsic.csproj b/dotnet/Trinsic/Trinsic.csproj index 7d4cefd8d..cda295f05 100644 --- a/dotnet/Trinsic/Trinsic.csproj +++ b/dotnet/Trinsic/Trinsic.csproj @@ -30,10 +30,11 @@ - + + none @@ -42,6 +43,9 @@ <_Parameter1>Tests + + <_Parameter1>Trinsic.Browser + diff --git a/dotnet/Trinsic/TrustRegistryService.cs b/dotnet/Trinsic/TrustRegistryService.cs index a3a61f81b..c20eb207e 100644 --- a/dotnet/Trinsic/TrustRegistryService.cs +++ b/dotnet/Trinsic/TrustRegistryService.cs @@ -1,9 +1,7 @@ using System; using System.Threading.Tasks; using Grpc.Core; -using Grpc.Net.Client; using Trinsic.Sdk.Options.V1; -using Trinsic.Services.Account.V1; using Trinsic.Services.Common.V1; using Trinsic.Services.TrustRegistry.V1; @@ -19,6 +17,10 @@ public TrustRegistryService(ServiceOptions options) public TrustRegistryService() { Client = new(Channel); } + + internal TrustRegistryService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + Client = new(Channel); + } private TrustRegistry.TrustRegistryClient Client { get; } diff --git a/dotnet/Trinsic/WalletService.cs b/dotnet/Trinsic/WalletService.cs index aa187a94d..ebbc1370b 100644 --- a/dotnet/Trinsic/WalletService.cs +++ b/dotnet/Trinsic/WalletService.cs @@ -14,6 +14,10 @@ public WalletService(ServiceOptions options) public WalletService() { Client = new(Channel); } + + internal WalletService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + Client = new(Channel); + } private UniversalWallet.UniversalWalletClient Client { get; } diff --git a/dotnet/TrinsicSdk.sln b/dotnet/TrinsicSdk.sln index 598105346..93f5201c6 100644 --- a/dotnet/TrinsicSdk.sln +++ b/dotnet/TrinsicSdk.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trinsic", "Trinsic\Trinsic. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{8132C26B-F80A-49EC-933E-DAA7C77235F0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trinsic.Browser", "Trinsic.Browser\Trinsic.Browser.csproj", "{85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,5 +46,17 @@ Global {8132C26B-F80A-49EC-933E-DAA7C77235F0}.Release|x64.Build.0 = Release|Any CPU {8132C26B-F80A-49EC-933E-DAA7C77235F0}.Release|x86.ActiveCfg = Release|Any CPU {8132C26B-F80A-49EC-933E-DAA7C77235F0}.Release|x86.Build.0 = Release|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Debug|x64.ActiveCfg = Debug|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Debug|x64.Build.0 = Debug|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Debug|x86.ActiveCfg = Debug|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Debug|x86.Build.0 = Debug|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Release|Any CPU.Build.0 = Release|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Release|x64.ActiveCfg = Release|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Release|x64.Build.0 = Release|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Release|x86.ActiveCfg = Release|Any CPU + {85F0B4B0-17B7-4F9A-BA22-C588EAD1CBE2}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal From cc55181d7387bc3c27ae5aeefe13a3818d55490a Mon Sep 17 00:00:00 2001 From: Tomislav Markovski Date: Thu, 17 Mar 2022 11:40:59 -0400 Subject: [PATCH 2/6] Host tests --- dotnet/Tests/HostTests.cs | 31 +++++++++++++++++++ dotnet/Tests/Tests.csproj | 1 + .../Extensions/ServiceOptionsExtensions.cs | 4 +-- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 dotnet/Tests/HostTests.cs diff --git a/dotnet/Tests/HostTests.cs b/dotnet/Tests/HostTests.cs new file mode 100644 index 000000000..7ad99e3d1 --- /dev/null +++ b/dotnet/Tests/HostTests.cs @@ -0,0 +1,31 @@ +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 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.GetService(); + + providerService.Should().NotBeNull(); + accountService.Should().NotBeNull(); + + await host.StopAsync(); + } +} diff --git a/dotnet/Tests/Tests.csproj b/dotnet/Tests/Tests.csproj index f5e11665d..2f628cccb 100644 --- a/dotnet/Tests/Tests.csproj +++ b/dotnet/Tests/Tests.csproj @@ -11,6 +11,7 @@ + diff --git a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs index b96362ee1..9b2195e0c 100644 --- a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs +++ b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs @@ -12,9 +12,9 @@ public static string FormatUrl(this ServiceOptions options) => public static class ServiceCollectionExtensions { - public static IServiceCollection AddTrinsic(this IServiceCollection services, Action? configure = default) { + public static IServiceCollection AddTrinsic(this IServiceCollection services) { - services.Configure(configure); + // services.Configure(configure); services.AddSingleton(); services.AddSingleton(); From d8c858c52a3ab0e7035466c06c30623d8f4b9c84 Mon Sep 17 00:00:00 2001 From: Tomislav Markovski Date: Thu, 17 Mar 2022 20:02:44 -0400 Subject: [PATCH 3/6] Add extension methods --- dotnet/Tests/HostTests.cs | 45 ++++++++++++++++-- dotnet/Trinsic/AccountService.cs | 6 +++ dotnet/Trinsic/CredentialsService.cs | 6 +++ .../Extensions/ServiceOptionsExtensions.cs | 46 +++++++++++++++---- dotnet/Trinsic/ProviderService.cs | 6 +++ dotnet/Trinsic/ServiceBase.cs | 12 ++--- dotnet/Trinsic/TemplateService.cs | 6 +++ dotnet/Trinsic/TrustRegistryService.cs | 8 +++- dotnet/Trinsic/WalletService.cs | 8 +++- 9 files changed, 123 insertions(+), 20 deletions(-) diff --git a/dotnet/Tests/HostTests.cs b/dotnet/Tests/HostTests.cs index 7ad99e3d1..92c9d9396 100644 --- a/dotnet/Tests/HostTests.cs +++ b/dotnet/Tests/HostTests.cs @@ -10,7 +10,7 @@ namespace Tests; public class HostTests { - [Fact(DisplayName = "Test service host")] + [Fact(DisplayName = "Test default service host")] public async Task TestGenericHost() { var host = Host .CreateDefaultBuilder() @@ -21,11 +21,50 @@ public async Task TestGenericHost() { await host.StartAsync(); var providerService = host.Services.GetService(); - var accountService = 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(); } -} +} \ No newline at end of file diff --git a/dotnet/Trinsic/AccountService.cs b/dotnet/Trinsic/AccountService.cs index d7ef6c8d5..7e9adf5ae 100644 --- a/dotnet/Trinsic/AccountService.cs +++ b/dotnet/Trinsic/AccountService.cs @@ -1,6 +1,7 @@ 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; @@ -27,6 +28,11 @@ internal AccountService(ITokenProvider tokenProvider) : base(new(), tokenProvide Client = new(Channel); } + internal AccountService(ITokenProvider tokenProvider, IOptions options) + : base(options.Value, tokenProvider) { + Client = new(Channel); + } + /// /// Gets the underlying grpc client /// diff --git a/dotnet/Trinsic/CredentialsService.cs b/dotnet/Trinsic/CredentialsService.cs index 4c677b7eb..c58260194 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; @@ -21,6 +22,11 @@ public CredentialsService() { 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; } diff --git a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs index 9b2195e0c..a14897a45 100644 --- a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs +++ b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs @@ -1,5 +1,7 @@ using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using Trinsic.Sdk.Options.V1; namespace Trinsic.Services.Common.V1; @@ -10,18 +12,44 @@ public static string FormatUrl(this ServiceOptions options) => $"{(options.ServerUseTls ? "https" : "http")}://{options.ServerEndpoint}:{options.ServerPort}"; } +[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] public static class ServiceCollectionExtensions { - public static IServiceCollection AddTrinsic(this IServiceCollection services) { - - // services.Configure(configure); + public static IServiceCollection AddTrinsic(this IServiceCollection services, Action configure) { + services.Configure(configure); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + return AddTrinsic(services); + } + + /// + /// Registers Trinsic SDK services and dependencies + /// + /// + /// + public static IServiceCollection AddTrinsic(this IServiceCollection services) { +#if __IOS__ + 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; } } \ No newline at end of file diff --git a/dotnet/Trinsic/ProviderService.cs b/dotnet/Trinsic/ProviderService.cs index 7f6d168db..6ba4bfb2d 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; @@ -20,6 +21,11 @@ public ProviderService() { 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; } diff --git a/dotnet/Trinsic/ServiceBase.cs b/dotnet/Trinsic/ServiceBase.cs index d45cfd71a..6ae6a1fd1 100644 --- a/dotnet/Trinsic/ServiceBase.cs +++ b/dotnet/Trinsic/ServiceBase.cs @@ -17,19 +17,19 @@ 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"; + internal const string DefaultEcosystem = "default"; + internal const bool DefaultServerUseTls = true; + internal const int DefaultServerPort = 443; + internal const string DefaultServerEndpoint = "prod.trinsic.cloud"; - protected readonly ITokenProvider TokenProvider; + 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; diff --git a/dotnet/Trinsic/TemplateService.cs b/dotnet/Trinsic/TemplateService.cs index 69fae2f33..7f486afee 100644 --- a/dotnet/Trinsic/TemplateService.cs +++ b/dotnet/Trinsic/TemplateService.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Microsoft.Extensions.Options; using Trinsic.Sdk.Options.V1; using Trinsic.Services.VerifiableCredentials.Templates.V1; @@ -21,6 +22,11 @@ public TemplateService() { 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; set; } diff --git a/dotnet/Trinsic/TrustRegistryService.cs b/dotnet/Trinsic/TrustRegistryService.cs index c20eb207e..6a886f48d 100644 --- a/dotnet/Trinsic/TrustRegistryService.cs +++ b/dotnet/Trinsic/TrustRegistryService.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Grpc.Core; +using Microsoft.Extensions.Options; using Trinsic.Sdk.Options.V1; using Trinsic.Services.Common.V1; using Trinsic.Services.TrustRegistry.V1; @@ -18,7 +19,12 @@ public TrustRegistryService() { Client = new(Channel); } - internal TrustRegistryService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + 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); } diff --git a/dotnet/Trinsic/WalletService.cs b/dotnet/Trinsic/WalletService.cs index ebbc1370b..861d1fb20 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,7 +16,12 @@ public WalletService() { Client = new(Channel); } - internal WalletService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { + 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); } From a933f8ce4cfb94219ca57919bfa49df20dd24bdf Mon Sep 17 00:00:00 2001 From: Tomislav Markovski Date: Fri, 18 Mar 2022 09:11:44 -0400 Subject: [PATCH 4/6] Remove Browser project --- .github/workflows/build-dotnet.yml | 2 +- dotnet/Tests/HostTests.cs | 1 - dotnet/Trinsic.Browser/Extensions.cs | 29 --------- dotnet/Trinsic.Browser/Trinsic.Browser.csproj | 20 ------- dotnet/Trinsic/AccountService.cs | 3 +- .../Extensions/ServiceCollectionExtensions.cs | 59 +++++++++++++++++++ .../Extensions/ServiceOptionsExtensions.cs | 46 --------------- .../Storage}/BrowserTokenProvider.cs | 9 ++- dotnet/Trinsic/TemplateService.cs | 2 +- dotnet/Trinsic/Trinsic.csproj | 1 + dotnet/Trinsic/Trinsic.xml | 15 +++++ dotnet/TrinsicSdk.sln | 14 ----- 12 files changed, 85 insertions(+), 116 deletions(-) delete mode 100644 dotnet/Trinsic.Browser/Extensions.cs delete mode 100644 dotnet/Trinsic.Browser/Trinsic.Browser.csproj create mode 100644 dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs rename dotnet/{Trinsic.Browser => Trinsic/Storage}/BrowserTokenProvider.cs (89%) 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/Tests/HostTests.cs b/dotnet/Tests/HostTests.cs index 92c9d9396..711677a90 100644 --- a/dotnet/Tests/HostTests.cs +++ b/dotnet/Tests/HostTests.cs @@ -47,7 +47,6 @@ public async Task TestConfiguredGenericHost() { options.ServerEndpoint = "example.com"; options.ServerPort = 42; options.ServerUseTls = true; - ; }); }).Build(); diff --git a/dotnet/Trinsic.Browser/Extensions.cs b/dotnet/Trinsic.Browser/Extensions.cs deleted file mode 100644 index 72c224967..000000000 --- a/dotnet/Trinsic.Browser/Extensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Trinsic.Browser; -using Trinsic.Sdk.Options.V1; - -namespace Trinsic; - -public static class Extensions -{ - /// - /// Add Trinsic SDK services and dependencies - /// - /// - /// - /// - public static IServiceCollection AddTrinsicBrowser(this IServiceCollection services, Action? configure = default) { - - services.Configure(configure); - - services.AddSingleton(); - services.AddSingleton(provider => new(provider.GetRequiredService())); - services.AddSingleton(provider => new(provider.GetRequiredService())); - services.AddSingleton(provider => new(provider.GetRequiredService())); - services.AddSingleton(provider => new(provider.GetRequiredService())); - ; - services.AddSingleton(provider => new(provider.GetRequiredService())); - services.AddSingleton(provider => new(provider.GetRequiredService())); - return services; - } -} diff --git a/dotnet/Trinsic.Browser/Trinsic.Browser.csproj b/dotnet/Trinsic.Browser/Trinsic.Browser.csproj deleted file mode 100644 index 086074382..000000000 --- a/dotnet/Trinsic.Browser/Trinsic.Browser.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - net6.0 - enable - enable - - false - $(DefineConstants);__BROWSER__ - - - - - - - - - - - diff --git a/dotnet/Trinsic/AccountService.cs b/dotnet/Trinsic/AccountService.cs index 7e9adf5ae..dac51ea7a 100644 --- a/dotnet/Trinsic/AccountService.cs +++ b/dotnet/Trinsic/AccountService.cs @@ -6,7 +6,6 @@ using Okapi.Security.V1; using Trinsic.Sdk.Options.V1; using Trinsic.Services.Account.V1; -using AccountServiceClient = Trinsic.Services.Account.V1.Account.AccountClient; namespace Trinsic; @@ -36,7 +35,7 @@ internal AccountService(ITokenProvider tokenProvider, IOptions o /// /// 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 diff --git a/dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs b/dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..eb00accb7 --- /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 a14897a45..2c033999a 100644 --- a/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs +++ b/dotnet/Trinsic/Extensions/ServiceOptionsExtensions.cs @@ -1,7 +1,3 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Trinsic.Sdk.Options.V1; namespace Trinsic.Services.Common.V1; @@ -10,46 +6,4 @@ public static class ServiceOptionsExtensions { public static string FormatUrl(this ServiceOptions options) => $"{(options.ServerUseTls ? "https" : "http")}://{options.ServerEndpoint}:{options.ServerPort}"; -} - -[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] -public static class ServiceCollectionExtensions -{ - 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(); -#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; - } } \ No newline at end of file diff --git a/dotnet/Trinsic.Browser/BrowserTokenProvider.cs b/dotnet/Trinsic/Storage/BrowserTokenProvider.cs similarity index 89% rename from dotnet/Trinsic.Browser/BrowserTokenProvider.cs rename to dotnet/Trinsic/Storage/BrowserTokenProvider.cs index 9095c8a65..175d012fe 100644 --- a/dotnet/Trinsic.Browser/BrowserTokenProvider.cs +++ b/dotnet/Trinsic/Storage/BrowserTokenProvider.cs @@ -1,7 +1,11 @@ -using Microsoft.JSInterop; +#if __BROWSER__ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.JSInterop; using Microsoft.JSInterop.WebAssembly; -namespace Trinsic.Browser; +namespace Trinsic; public class BrowserTokenProvider : ITokenProvider { @@ -28,3 +32,4 @@ public void Save(string authToken, string name = TokenDefaults.Name) { throw new NotImplementedException("sync method not supported, please use async overload instead"); } } +#endif \ No newline at end of file diff --git a/dotnet/Trinsic/TemplateService.cs b/dotnet/Trinsic/TemplateService.cs index 7f486afee..4f0d5011e 100644 --- a/dotnet/Trinsic/TemplateService.cs +++ b/dotnet/Trinsic/TemplateService.cs @@ -28,7 +28,7 @@ internal TemplateService(ITokenProvider tokenProvider, IOptions Client = new(Channel); } - private CredentialTemplates.CredentialTemplatesClient Client { get; set; } + private CredentialTemplates.CredentialTemplatesClient Client { get; } /// /// Create new credential template with the given parameters diff --git a/dotnet/Trinsic/Trinsic.csproj b/dotnet/Trinsic/Trinsic.csproj index cda295f05..af3e85e97 100644 --- a/dotnet/Trinsic/Trinsic.csproj +++ b/dotnet/Trinsic/Trinsic.csproj @@ -14,6 +14,7 @@ + - - 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 index 711677a90..45da8500c 100644 --- a/dotnet/Tests/HostTests.cs +++ b/dotnet/Tests/HostTests.cs @@ -66,4 +66,4 @@ public async Task TestConfiguredGenericHost() { await host.StopAsync(); } -} \ No newline at end of file +} 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 2f628cccb..c47f1af61 100644 --- a/dotnet/Tests/Tests.csproj +++ b/dotnet/Tests/Tests.csproj @@ -10,10 +10,10 @@ 4 - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -28,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 dac51ea7a..1efd4e4e5 100644 --- a/dotnet/Trinsic/AccountService.cs +++ b/dotnet/Trinsic/AccountService.cs @@ -27,7 +27,7 @@ internal AccountService(ITokenProvider tokenProvider) : base(new(), tokenProvide Client = new(Channel); } - internal AccountService(ITokenProvider tokenProvider, IOptions options) + internal AccountService(ITokenProvider tokenProvider, IOptions options) : base(options.Value, tokenProvider) { Client = new(Channel); } @@ -44,16 +44,12 @@ internal AccountService(ITokenProvider tokenProvider, IOptions o /// /// 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) { - await TokenProvider.SaveAsync(authToken); - } + + if (!response.Profile.Protection?.Enabled ?? true) await TokenProvider.SaveAsync(authToken); return authToken; } @@ -64,16 +60,12 @@ 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); - + var authToken = Convert.ToBase64String(response.Profile.ToByteArray()); - - if (!response.Profile.Protection?.Enabled ?? true) { - TokenProvider.Save(authToken); - } + + if (!response.Profile.Protection?.Enabled ?? true) TokenProvider.Save(authToken); return authToken; } @@ -163,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 c58260194..35aa581e1 100644 --- a/dotnet/Trinsic/CredentialsService.cs +++ b/dotnet/Trinsic/CredentialsService.cs @@ -18,12 +18,12 @@ public CredentialsService(ServiceOptions options) public CredentialsService() { Client = new(Channel); } - + internal CredentialsService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { Client = new(Channel); } - - internal CredentialsService(ITokenProvider tokenProvider, IOptions options) + + internal CredentialsService(ITokenProvider tokenProvider, IOptions options) : base(options.Value, tokenProvider) { Client = new(Channel); } @@ -36,16 +36,12 @@ internal CredentialsService(ITokenProvider tokenProvider, IOptions /// 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)); } @@ -96,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; } @@ -135,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}"); } @@ -153,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 index eb00accb7..d0b859ce2 100644 --- a/dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs +++ b/dotnet/Trinsic/Extensions/ServiceCollectionExtensions.cs @@ -22,7 +22,7 @@ public static IServiceCollection AddTrinsic(this IServiceCollection services, Ac return AddTrinsic(services); } - + /// /// Registers Trinsic SDK services and dependencies /// 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 6ba4bfb2d..8f58ca2dc 100644 --- a/dotnet/Trinsic/ProviderService.cs +++ b/dotnet/Trinsic/ProviderService.cs @@ -17,12 +17,12 @@ public ProviderService(ServiceOptions options) public ProviderService() { Client = new(Channel); } - + internal ProviderService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { Client = new(Channel); } - - internal ProviderService(ITokenProvider tokenProvider, IOptions options) + + internal ProviderService(ITokenProvider tokenProvider, IOptions options) : base(options.Value, tokenProvider) { Client = new(Channel); } @@ -81,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); } @@ -99,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); } @@ -128,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 6ae6a1fd1..ed74d4250 100644 --- a/dotnet/Trinsic/ServiceBase.cs +++ b/dotnet/Trinsic/ServiceBase.cs @@ -23,7 +23,7 @@ public abstract class ServiceBase internal const string DefaultServerEndpoint = "prod.trinsic.cloud"; protected internal readonly ITokenProvider TokenProvider; - + protected internal ServiceBase() : this(new()) { } protected internal ServiceBase(ServiceOptions options) { @@ -43,18 +43,10 @@ protected internal ServiceBase(ServiceOptions options, ITokenProvider tokenProvi } 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) { @@ -82,9 +74,7 @@ private static GrpcChannel CreateChannel(ServiceOptions options) { /// protected async Task BuildMetadataAsync(IMessage request) { var authToken = string.IsNullOrWhiteSpace(Options.AuthToken) ? TokenProvider.Get() : Options.AuthToken; - if (authToken is null) { - throw new("Cannot call authenticated endpoint before signing in"); - } + if (authToken is null) throw new("Cannot call authenticated endpoint before signing in"); var profile = AccountProfile.Parser.ParseFrom(Convert.FromBase64String(authToken)); @@ -99,9 +89,7 @@ protected async Task BuildMetadataAsync(IMessage request) { /// protected Metadata BuildMetadata(IMessage request) { var authToken = string.IsNullOrWhiteSpace(Options.AuthToken) ? TokenProvider.Get() : Options.AuthToken; - if (authToken is null) { - throw new("Cannot call authenticated endpoint before signing in"); - } + if (authToken is null) throw new("Cannot call authenticated endpoint before signing in"); var profile = AccountProfile.Parser.ParseFrom(Convert.FromBase64String(authToken)); @@ -109,4 +97,4 @@ protected Metadata BuildMetadata(IMessage request) { {"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 index 175d012fe..89b1738a1 100644 --- a/dotnet/Trinsic/Storage/BrowserTokenProvider.cs +++ b/dotnet/Trinsic/Storage/BrowserTokenProvider.cs @@ -32,4 +32,4 @@ public void Save(string authToken, string name = TokenDefaults.Name) { throw new NotImplementedException("sync method not supported, please use async overload instead"); } } -#endif \ No newline at end of file +#endif diff --git a/dotnet/Trinsic/Storage/FileTokenProvider.cs b/dotnet/Trinsic/Storage/FileTokenProvider.cs index f21698e63..f3ceb235e 100644 --- a/dotnet/Trinsic/Storage/FileTokenProvider.cs +++ b/dotnet/Trinsic/Storage/FileTokenProvider.cs @@ -8,9 +8,9 @@ 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) { @@ -55,9 +55,9 @@ public void Save(string authToken, string name = TokenDefaults.Name) { var filename = Path.Combine(rootPath, Vendor, name); Directory.CreateDirectory(Path.Combine(rootPath, Vendor)); - + _cachedToken = authToken; File.WriteAllText(filename, authToken); } -} \ No newline at end of file +} diff --git a/dotnet/Trinsic/Storage/ITokenProvider.cs b/dotnet/Trinsic/Storage/ITokenProvider.cs index efc53dadb..0339387c1 100644 --- a/dotnet/Trinsic/Storage/ITokenProvider.cs +++ b/dotnet/Trinsic/Storage/ITokenProvider.cs @@ -9,7 +9,6 @@ internal class TokenDefaults { internal const string Name = "dotnet.authtoken"; } - public interface ITokenProvider { Task GetAsync(string name = TokenDefaults.Name, CancellationToken cancellationToken = default); diff --git a/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs b/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs index 48647447c..6e4887e43 100644 --- a/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs +++ b/dotnet/Trinsic/Storage/KeyChainTokenProvider.cs @@ -1,4 +1,3 @@ - #if __IOS__ using System.Threading.Tasks; @@ -14,7 +13,7 @@ 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); } @@ -35,7 +34,7 @@ public void Save(string authToken, string name = "default") { var rec = new SecRecord(SecKind.GenericPassword) { Generic = NSData.FromString(name) }; - _ = SecKeyChain.QueryAsRecord(rec, out SecStatusCode res); + _ = SecKeyChain.QueryAsRecord(rec, out var res); if (res != SecStatusCode.Success) { var s = new SecRecord(SecKind.GenericPassword) { Label = $"Account Profile: {name}", @@ -48,9 +47,7 @@ public void Save(string authToken, string name = "default") { }; var err = SecKeyChain.Add(s); - if (err != SecStatusCode.Success) { - throw new($"error saving token: {err:G}"); - } + if (err != SecStatusCode.Success) throw new($"error saving token: {err:G}"); } else { throw new("Profile already exists"); diff --git a/dotnet/Trinsic/TemplateService.cs b/dotnet/Trinsic/TemplateService.cs index 4f0d5011e..9c568e3b3 100644 --- a/dotnet/Trinsic/TemplateService.cs +++ b/dotnet/Trinsic/TemplateService.cs @@ -18,12 +18,12 @@ public TemplateService(ServiceOptions options) public TemplateService() { Client = new(Channel); } - + internal TemplateService(ITokenProvider tokenProvider) : base(new(), tokenProvider) { Client = new(Channel); } - - internal TemplateService(ITokenProvider tokenProvider, IOptions options) + + internal TemplateService(ITokenProvider tokenProvider, IOptions options) : base(options.Value, tokenProvider) { Client = new(Channel); } @@ -55,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. @@ -71,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)); } @@ -103,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 af3e85e97..1db5451c5 100644 --- a/dotnet/Trinsic/Trinsic.csproj +++ b/dotnet/Trinsic/Trinsic.csproj @@ -13,10 +13,10 @@ - - + + - + - <_BuiltProjectOutputGroupOutputIntermediate Remove="$(OutDir)$(_DeploymentTargetApplicationManifestFileName)" /> - + <_BuiltProjectOutputGroupOutputIntermediate Remove="$(OutDir)$(_DeploymentTargetApplicationManifestFileName)"/> + - + - - - + + + none @@ -52,18 +52,18 @@ - - - - - + + + + + - - + + - + diff --git a/dotnet/Trinsic/TrustRegistryService.cs b/dotnet/Trinsic/TrustRegistryService.cs index 6a886f48d..7998dcc8c 100644 --- a/dotnet/Trinsic/TrustRegistryService.cs +++ b/dotnet/Trinsic/TrustRegistryService.cs @@ -18,12 +18,11 @@ public TrustRegistryService(ServiceOptions options) public TrustRegistryService() { Client = new(Channel); } - - internal TrustRegistryService(ITokenProvider tokenProvider) - : this(tokenProvider, Microsoft.Extensions.Options.Options.Create(new ServiceOptions())) { - } - - internal TrustRegistryService(ITokenProvider tokenProvider, IOptions options) + + 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); } @@ -40,9 +39,7 @@ internal TrustRegistryService(ITokenProvider tokenProvider, IOptionsThe 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() { @@ -54,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, @@ -81,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) { @@ -108,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) { @@ -152,7 +139,7 @@ public async Task CheckVerifierStatusAsync(CheckVerifierStat return response.Status; } - + public RegistrationStatus CheckVerifierStatus(CheckVerifierStatusRequest request) { return Client.CheckVerifierStatus(request, BuildMetadata(request)).Status; } @@ -183,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 861d1fb20..7f018b125 100644 --- a/dotnet/Trinsic/WalletService.cs +++ b/dotnet/Trinsic/WalletService.cs @@ -15,12 +15,11 @@ public WalletService(ServiceOptions options) public WalletService() { Client = new(Channel); } - - internal WalletService(ITokenProvider tokenProvider) - : this(tokenProvider, Microsoft.Extensions.Options.Options.Create(new ServiceOptions())) { - } - - internal WalletService(ITokenProvider tokenProvider, IOptions options) + + 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); } @@ -35,9 +34,8 @@ internal WalletService(ITokenProvider tokenProvider, IOptions op /// 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; } @@ -50,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; } @@ -64,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; } @@ -76,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; } From 68f29be9c7edf7cd3e8c83ba1eccf4b2060385fc Mon Sep 17 00:00:00 2001 From: Tomislav Markovski Date: Fri, 18 Mar 2022 09:43:20 -0400 Subject: [PATCH 6/6] Update default tests to staging --- node/.env | 2 +- node/test/TestData.ts | 2 +- web/test/env.js | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) 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");