Skip to content

Commit 95ac9c2

Browse files
authored
[dotnet] Experimental platform-specific token provider with dependency injection support (#492)
* Experimental token provider implementation * Host tests * Add extension methods * Remove Browser project * Cleanup * Update default tests to staging
1 parent 34d38b5 commit 95ac9c2

29 files changed

+554
-324
lines changed

.github/workflows/build-dotnet.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- run: |
3535
dotnet workload install ios
3636
dotnet restore
37-
dotnet build -c Release /p:IsBrowser=true ./Trinsic
37+
dotnet build -c Release -f net6.0 -p:IsBrowser=true ./Trinsic
3838
dotnet build -c Release
3939
dotnet test -c Release -v n
4040
working-directory: ./dotnet

dotnet/.editorconfig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
[*]
32
charset = utf-8
43
end_of_line = lf
@@ -10,7 +9,7 @@ indent_size = 4
109
# Microsoft .NET properties
1110
csharp_new_line_before_catch = false
1211
csharp_new_line_before_members_in_object_initializers = false
13-
csharp_new_line_before_open_brace = accessors,control_blocks,events,indexers,properties,types
12+
csharp_new_line_before_open_brace = accessors, control_blocks, events, indexers, properties, types
1413
csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion
1514
csharp_style_var_elsewhere = true:suggestion
1615
csharp_style_var_for_built_in_types = true:suggestion

dotnet/Directory.Build.props

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
<Project>
2-
<!-- Set common properties regarding assembly information and nuget packages -->
3-
<PropertyGroup>
4-
<Authors>Trinsic Engineering Team</Authors>
5-
<Company>Trinsic</Company>
6-
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
7-
<PackageProjectUrl>https://github.com/trinsic-id/sdk</PackageProjectUrl>
8-
<PackageTags>Trinsic</PackageTags>
9-
<Product>Trinsic SDK for NET</Product>
10-
<RepositoryUrl>https://github.com/trinsic-id/sdk.git</RepositoryUrl>
11-
<RepositoryType>git</RepositoryType>
12-
<Version>1.0.0</Version>
13-
<IncludeSymbols>true</IncludeSymbols>
14-
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
15-
</PropertyGroup>
16-
<!-- Common compile parameters -->
17-
<PropertyGroup>
18-
<!-- We use full (Windows PDBs) until cross platform support for source link will get better -->
19-
<DebugType>full</DebugType>
20-
<LangVersion>latest</LangVersion>
21-
<NoWarn>$(NoWarn);1591</NoWarn>
22-
<Nullable>enable</Nullable>
23-
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
24-
</PropertyGroup>
2+
<!-- Set common properties regarding assembly information and nuget packages -->
3+
<PropertyGroup>
4+
<Authors>Trinsic Engineering Team</Authors>
5+
<Company>Trinsic</Company>
6+
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
7+
<PackageProjectUrl>https://github.com/trinsic-id/sdk</PackageProjectUrl>
8+
<PackageTags>Trinsic</PackageTags>
9+
<Product>Trinsic SDK for NET</Product>
10+
<RepositoryUrl>https://github.com/trinsic-id/sdk.git</RepositoryUrl>
11+
<RepositoryType>git</RepositoryType>
12+
<Version>1.0.0</Version>
13+
<IncludeSymbols>true</IncludeSymbols>
14+
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
15+
</PropertyGroup>
16+
<!-- Common compile parameters -->
17+
<PropertyGroup>
18+
<!-- We use full (Windows PDBs) until cross platform support for source link will get better -->
19+
<DebugType>full</DebugType>
20+
<LangVersion>latest</LangVersion>
21+
<NoWarn>$(NoWarn);1591</NoWarn>
22+
<Nullable>enable</Nullable>
23+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
24+
</PropertyGroup>
2525
</Project>

dotnet/Tests/HostTests.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using System.Threading.Tasks;
2+
using FluentAssertions;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Hosting;
5+
using Trinsic;
6+
using Trinsic.Services.Common.V1;
7+
using Xunit;
8+
9+
namespace Tests;
10+
11+
public class HostTests
12+
{
13+
[Fact(DisplayName = "Test default service host")]
14+
public async Task TestGenericHost() {
15+
var host = Host
16+
.CreateDefaultBuilder()
17+
.ConfigureServices(services => {
18+
services.AddTrinsic();
19+
}).Build();
20+
21+
await host.StartAsync();
22+
23+
var providerService = host.Services.GetService<ProviderService>();
24+
var accountService = host.Services.GetRequiredService<AccountService>();
25+
26+
providerService.Should().NotBeNull();
27+
accountService.Should().NotBeNull();
28+
29+
accountService.Options.ServerEndpoint.Should().Be(ServiceBase.DefaultServerEndpoint);
30+
accountService.Options.ServerPort.Should().Be(ServiceBase.DefaultServerPort);
31+
accountService.Options.ServerUseTls.Should().Be(ServiceBase.DefaultServerUseTls);
32+
accountService.Options.DefaultEcosystem.Should().Be(ServiceBase.DefaultEcosystem);
33+
accountService.Options.AuthToken.Should().Be(string.Empty);
34+
accountService.TokenProvider.Should().BeOfType<FileTokenProvider>();
35+
36+
await host.StopAsync();
37+
}
38+
39+
[Fact(DisplayName = "Test configured service host")]
40+
public async Task TestConfiguredGenericHost() {
41+
var host = Host
42+
.CreateDefaultBuilder()
43+
.ConfigureServices(services => {
44+
services.AddTrinsic(options => {
45+
options.AuthToken = "auth";
46+
options.DefaultEcosystem = "eco";
47+
options.ServerEndpoint = "example.com";
48+
options.ServerPort = 42;
49+
options.ServerUseTls = true;
50+
});
51+
}).Build();
52+
53+
await host.StartAsync();
54+
55+
var providerService = host.Services.GetService<ProviderService>();
56+
var accountService = host.Services.GetRequiredService<AccountService>();
57+
58+
providerService.Should().NotBeNull();
59+
accountService.Should().NotBeNull();
60+
61+
accountService.Options.ServerEndpoint.Should().Be("example.com");
62+
accountService.Options.ServerPort.Should().Be(42);
63+
accountService.Options.ServerUseTls.Should().BeTrue();
64+
accountService.Options.DefaultEcosystem.Should().Be("eco");
65+
accountService.Options.AuthToken.Should().Be("auth");
66+
67+
await host.StopAsync();
68+
}
69+
}

dotnet/Tests/Tests.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using Trinsic.Services.VerifiableCredentials.V1;
2121
using FieldType = Trinsic.Services.VerifiableCredentials.Templates.V1.FieldType;
2222
using JsonSerializer = System.Text.Json.JsonSerializer;
23+
2324
#pragma warning disable CS0618
2425

2526
namespace Tests;
@@ -32,9 +33,9 @@ public class Tests
3233
const int DefaultPort = 5000;
3334
const bool DefaultUseTls = false;
3435
#else
35-
const string DefaultEndpoint = "staging-internal.trinsic.cloud";
36-
const int DefaultPort = 443;
37-
const bool DefaultUseTls = true;
36+
private const string DefaultEndpoint = "staging-internal.trinsic.cloud";
37+
private const int DefaultPort = 443;
38+
private const bool DefaultUseTls = true;
3839
#endif
3940

4041
private readonly ITestOutputHelper _testOutputHelper;
@@ -67,9 +68,9 @@ public async Task TestWalletService() {
6768
// SETUP ACTORS
6869
// Create 3 different profiles for each participant in the scenario
6970
// setupActors() {
70-
var allison = await accountService.SignInAsync(new SignInRequest {EcosystemId = ecosystemId});
71-
var clinic = await accountService.SignInAsync(new SignInRequest {EcosystemId = ecosystemId});
72-
var airline = await accountService.SignInAsync(new SignInRequest {EcosystemId = ecosystemId});
71+
var allison = await accountService.SignInAsync(new() {EcosystemId = ecosystemId});
72+
var clinic = await accountService.SignInAsync(new() {EcosystemId = ecosystemId});
73+
var airline = await accountService.SignInAsync(new() {EcosystemId = ecosystemId});
7374
// }
7475

7576
accountService.Options.AuthToken = clinic;
@@ -251,7 +252,7 @@ public async Task TestInvitationIdSet() {
251252
invitationResponse.Should().NotBeNull();
252253
invitationResponse.InvitationCode.Should().NotBeEmpty();
253254

254-
await Assert.ThrowsAsync<Exception>(async () => await providerService.InvitationStatusAsync(new InvitationStatusRequest()));
255+
await Assert.ThrowsAsync<Exception>(async () => await providerService.InvitationStatusAsync(new()));
255256
}
256257

257258
[Fact(Skip = "Ecosystem support not complete yet")]
@@ -263,7 +264,7 @@ public async Task TestInviteParticipant() {
263264
var response = await myProviderService.InviteParticipantAsync(invite);
264265
Assert.NotNull(response);
265266

266-
var statusResponse = await myProviderService.InvitationStatusAsync(new InvitationStatusRequest {InvitationId = response.InvitationId});
267+
var statusResponse = await myProviderService.InvitationStatusAsync(new() {InvitationId = response.InvitationId});
267268
Assert.NotNull(statusResponse);
268269
}
269270

@@ -352,12 +353,11 @@ public async Task DemoTemplatesWithIssuance() {
352353
}
353354
}
354355
}
355-
356356
public static class Extensions
357357
{
358358
public static ServiceOptions CloneWithAuthToken(this ServiceOptions options, string authToken) {
359359
var cloned = options.Clone();
360360
cloned.AuthToken = authToken;
361361
return cloned;
362362
}
363-
}
363+
}

dotnet/Tests/Tests.csproj

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
<WarningLevel>4</WarningLevel>
1111
</PropertyGroup>
1212
<ItemGroup>
13-
<PackageReference Include="FluentAssertions" Version="6.2.0" />
14-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
15-
<PackageReference Include="xunit" Version="2.4.1" />
13+
<PackageReference Include="FluentAssertions" Version="6.2.0"/>
14+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1"/>
15+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
16+
<PackageReference Include="xunit" Version="2.4.1"/>
1617
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
1718
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1819
<PrivateAssets>all</PrivateAssets>
@@ -27,16 +28,16 @@
2728
</PackageReference>
2829
</ItemGroup>
2930
<ItemGroup>
30-
<ProjectReference Include="..\Trinsic\Trinsic.csproj" />
31+
<ProjectReference Include="..\Trinsic\Trinsic.csproj"/>
3132
</ItemGroup>
3233
<ItemGroup>
33-
<None Include="..\..\devops\testdata\vaccination-certificate-unsigned.jsonld">
34-
<Link>TestData/vaccination-certificate-unsigned.jsonld</Link>
35-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
36-
</None>
37-
<None Include="..\..\devops\testdata\vaccination-certificate-frame.jsonld">
38-
<Link>TestData/vaccination-certificate-frame.jsonld</Link>
39-
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
40-
</None>
34+
<None Include="..\..\devops\testdata\vaccination-certificate-unsigned.jsonld">
35+
<Link>TestData/vaccination-certificate-unsigned.jsonld</Link>
36+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
37+
</None>
38+
<None Include="..\..\devops\testdata\vaccination-certificate-frame.jsonld">
39+
<Link>TestData/vaccination-certificate-frame.jsonld</Link>
40+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
41+
</None>
4142
</ItemGroup>
4243
</Project>

dotnet/Trinsic/AccountService.cs

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using System;
22
using System.Threading.Tasks;
33
using Google.Protobuf;
4+
using Microsoft.Extensions.Options;
45
using Okapi.Security;
56
using Okapi.Security.V1;
67
using Trinsic.Sdk.Options.V1;
78
using Trinsic.Services.Account.V1;
8-
using AccountServiceClient = Trinsic.Services.Account.V1.Account.AccountClient;
99

1010
namespace Trinsic;
1111

@@ -22,11 +22,20 @@ public AccountService(ServiceOptions options)
2222
public AccountService() {
2323
Client = new(Channel);
2424
}
25-
25+
26+
internal AccountService(ITokenProvider tokenProvider) : base(new(), tokenProvider) {
27+
Client = new(Channel);
28+
}
29+
30+
internal AccountService(ITokenProvider tokenProvider, IOptions<ServiceOptions> options)
31+
: base(options.Value, tokenProvider) {
32+
Client = new(Channel);
33+
}
34+
2635
/// <summary>
2736
/// Gets the underlying grpc client
2837
/// </summary>
29-
public AccountServiceClient Client { get; }
38+
private Account.AccountClient Client { get; }
3039

3140
/// <summary>
3241
/// Perform a sign-in to obtain an account profile. If the <see cref="AccountDetails" /> are
@@ -35,16 +44,12 @@ public AccountService() {
3544
/// <param name="request"></param>
3645
/// <returns></returns>
3746
public async Task<string> SignInAsync(SignInRequest request) {
38-
if (string.IsNullOrWhiteSpace(request.EcosystemId)) {
39-
request.EcosystemId = Options.DefaultEcosystem;
40-
}
47+
if (string.IsNullOrWhiteSpace(request.EcosystemId)) request.EcosystemId = Options.DefaultEcosystem;
4148
var response = await Client.SignInAsync(request);
4249

4350
var authToken = Convert.ToBase64String(response.Profile.ToByteArray());
44-
45-
if (!response.Profile.Protection?.Enabled ?? true) {
46-
Options.AuthToken = authToken;
47-
}
51+
52+
if (!response.Profile.Protection?.Enabled ?? true) await TokenProvider.SaveAsync(authToken);
4853
return authToken;
4954
}
5055

@@ -55,13 +60,13 @@ public async Task<string> SignInAsync(SignInRequest request) {
5560
/// <param name="request"></param>
5661
/// <returns></returns>
5762
public string SignIn(SignInRequest request) {
58-
if (string.IsNullOrWhiteSpace(request.EcosystemId)) {
59-
request.EcosystemId = Options.DefaultEcosystem;
60-
}
63+
if (string.IsNullOrWhiteSpace(request.EcosystemId)) request.EcosystemId = Options.DefaultEcosystem;
6164
var response = Client.SignIn(request);
62-
63-
Options.AuthToken = Convert.ToBase64String(response.Profile.ToByteArray());
64-
return Options.AuthToken;
65+
66+
var authToken = Convert.ToBase64String(response.Profile.ToByteArray());
67+
68+
if (!response.Profile.Protection?.Enabled ?? true) TokenProvider.Save(authToken);
69+
return authToken;
6570
}
6671

6772
/// <summary>
@@ -150,4 +155,4 @@ public RevokeDeviceResponse RevokeDevice() {
150155
RevokeDeviceRequest request = new();
151156
return Client.RevokeDevice(request, BuildMetadata(request));
152157
}
153-
}
158+
}

0 commit comments

Comments
 (0)