Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setup Multi-Target for .NET Framework #8

Merged
merged 30 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ea73546
Setup Multi-Target for .NET Framework
justindbaur Aug 9, 2023
44a929b
Merge main
justindbaur Aug 9, 2023
3d7c513
Formatting
justindbaur Aug 9, 2023
31ef37c
Add Framework Build
justindbaur Aug 9, 2023
15b86f4
Move Package Push To Windows
justindbaur Aug 9, 2023
b9bb927
Added package:write to job
abergs Aug 9, 2023
72361fe
Added packages
abergs Aug 9, 2023
05edb90
trigger build
abergs Aug 9, 2023
68fb627
Tried from first step
abergs Aug 9, 2023
d550c96
Used windows syntax
abergs Aug 9, 2023
42d5021
Fix Branch Name
justindbaur Aug 9, 2023
6844481
Set Environment Differently
justindbaur Aug 9, 2023
4fbff45
Update Clean Branch Name Step
justindbaur Aug 9, 2023
7ee9b60
Another Try
justindbaur Aug 9, 2023
6fc99c9
Another Try
justindbaur Aug 9, 2023
b2f99a4
Move Clean to ubuntu job
justindbaur Aug 9, 2023
0bcd8cd
Use Expression
justindbaur Aug 9, 2023
b221eb5
Add More Accessible Constructor for non-DI
justindbaur Aug 9, 2023
18954eb
Formatting
justindbaur Aug 14, 2023
b9fb30d
Merge remote-tracking branch 'origin/main' into multi-target
justindbaur Aug 17, 2023
2b7d36b
Merge branch 'multi-target' of https://github.com/passwordless/passwo…
justindbaur Aug 17, 2023
72cb78d
Formatting
justindbaur Aug 17, 2023
6092233
Remove Sealed
justindbaur Aug 17, 2023
35e7d4f
Formatting
justindbaur Aug 18, 2023
8371f74
Use Dispose(bool) Pattern
justindbaur Aug 18, 2023
b94a090
Maybe get less changes
justindbaur Aug 18, 2023
7a8d5a4
Another Try
justindbaur Aug 18, 2023
78232c9
Back to CRLF
justindbaur Aug 18, 2023
5d580c8
Turn of grouping of namespaces
justindbaur Aug 18, 2023
7516747
Formatting and Bump Version
justindbaur Aug 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
363 changes: 363 additions & 0 deletions .editorconfig

Large diffs are not rendered by default.

59 changes: 49 additions & 10 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ permissions:
packages: write

jobs:
build:
build-dotnet:
runs-on: ubuntu-latest
# strategy:
# matrix:
# dotnet-version: [ '3.1.x', '6.0.x' ]
outputs:
clean_name: ${{steps.clean_branch_name.outputs.CLEAN_BRANCH_NAME}}

steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
Expand All @@ -33,13 +35,19 @@ jobs:
run: dotnet restore --locked-mode

- name: Build
run: dotnet build --verbosity minimal --no-restore
run: dotnet build -f net6.0 --verbosity minimal --no-restore

- name: Check Format
run: dotnet format --verify-no-changes --no-restore

- name: Test with the dotnet CLI
run: dotnet test --no-build --no-restore --logger "trx;LogFileName=pw-test-results.trx"
run: dotnet test --no-build --no-restore --framework net6.0 --logger "trx;LogFileName=pw-test-results.trx"

- id: clean_branch_name
name: Clean Branch Name
run: echo "CLEAN_BRANCH_NAME=${BRANCH_NAME/\//-}" >> "$GITHUB_OUTPUT"
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}

- name: Report test results
uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226 # v1.6.0
Expand All @@ -50,15 +58,46 @@ jobs:
reporter: dotnet-trx
fail-on-error: true

- name: Clean Branch Name
run: echo "CLEAN_BRANCH_NAME=${BRANCH_NAME/\//-}" >> $GITHUB_ENV
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
build-framework:
runs-on: windows-latest
needs: build-dotnet
steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
# - name: Setup dotnet
# uses: setup msbuild?
- name: Display dotnet version
run: |
dotnet --version
dotnet --info

- name: Install dependencies
run: dotnet restore --locked-mode

- name: Build
# Don't specify a framework here so we build both .NET and .NET Framework so we can pack both
run: dotnet build --verbosity minimal --no-restore

# Don't bother running formatting for this build

- name: Test with the dotnet CLI
# We will have already ran the tests on ubuntu, so only do .NET Framework ones here
run: dotnet test --no-build --no-restore --framework net462 --logger "trx;LogFileName=pw-framework-test-results.trx"

- name: Report test results
uses: dorny/test-reporter@c9b3d0e2bd2a4e96aaf424dbaa31c46b42318226 # v1.6.0
if: always()
with:
name: Test Results
path: "**/*-test-results.trx"
reporter: dotnet-trx
fail-on-error: true

- name: Pack NuGet Packages
run: dotnet pack --no-build --version-suffix "ci-${{ env.CLEAN_BRANCH_NAME }}-${{ github.run_id }}"

env:
CLEAN_BRANCH_NAME: ${{needs.build-dotnet.outputs.clean_name}}

- name: Publish NuGet Packages
run: dotnet nuget push **/*.nupkg --source https://nuget.pkg.github.com/passwordless/index.json --api-key ${GITHUB_TOKEN}
run: dotnet nuget push **/*.nupkg --source https://nuget.pkg.github.com/passwordless/index.json --api-key ${{env.GITHUB_TOKEN}}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 changes: 25 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project>
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
<PropertyGroup>
<TargetFrameworks>net6.0;net462</TargetFrameworks>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<PropertyGroup>
<PasswordlessMajorVersion>0</PasswordlessMajorVersion>
<PasswordlessMinorVersion>1</PasswordlessMinorVersion>
<PasswordlessPatchVersion>0</PasswordlessPatchVersion>
<PasswordlessMajorMinorVersion>$(PasswordlessMajorVersion).$(PasswordlessMinorVersion)</PasswordlessMajorMinorVersion>
<VersionPrefix>$(PasswordlessMajorMinorVersion).$(PasswordlessPatchVersion)</VersionPrefix>
</PropertyGroup>

<ItemGroup>
<!--
The .NET Framework target doesn't seem to like this implicit using so we
have to bring it in for each file, so might as well remove it for .NET targets too.
-->
<Using Remove="System.Net.Http" />
</ItemGroup>
</Project>
17 changes: 11 additions & 6 deletions Passwordless-dotnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdk.Tests", "tests\Sdk.Tests\Sdk.Tests.csproj", "{F64C850E-9923-43F1-BC84-432AFBBA4425}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdk.Tests", "tests\Sdk.Tests\Sdk.Tests.csproj", "{F64C850E-9923-43F1-BC84-432AFBBA4425}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdk", "src\Sdk\Sdk.csproj", "{A01503A8-6AB9-43A7-AC5A-4EAE091B07B6}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdk", "src\Sdk\Sdk.csproj", "{A01503A8-6AB9-43A7-AC5A-4EAE091B07B6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F239A76C-408E-4919-AB70-4499425E6F29}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F64C850E-9923-43F1-BC84-432AFBBA4425}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F64C850E-9923-43F1-BC84-432AFBBA4425}.Debug|Any CPU.Build.0 = Debug|Any CPU
Expand All @@ -25,6 +29,7 @@ Global
{A01503A8-6AB9-43A7-AC5A-4EAE091B07B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A01503A8-6AB9-43A7-AC5A-4EAE091B07B6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion src/Sdk/Base64Url.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static string Encode(ReadOnlySpan<byte> arg)
#if NET5_0_OR_GREATER
Convert.TryToBase64Chars(arg, array, out var charsWritten);
#elif NET462

var charsWritten = Convert.ToBase64CharArray(arg.ToArray(), 0, minimumLength, array, 0);
#endif
Span<char> span = array.AsSpan(0, charsWritten);

Expand Down
2 changes: 1 addition & 1 deletion src/Sdk/Models/PasswordlessUserSummary.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Passwordless.Net;
namespace Passwordless.Net;

public class PasswordlessUserSummary
{
Expand Down
91 changes: 70 additions & 21 deletions src/Sdk/Models/RegisterOptions.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,78 @@
namespace Passwordless.Net;

/// <summary>
///
/// </summary>
public class RegisterOptions
{
public
#if NET6_0_OR_GREATER
required
#endif
string UserId
{ get; set; }
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="username"></param>
public RegisterOptions(string userId, string username)
{
UserId = userId;
Username = username;
}

/// <summary>
/// A WebAuthn User Handle, which should be generated by your application.
/// This is used to identify your user (could be a database primary key ID or a guid).
/// Max. 64 bytes. Should not contain PII about the user.
/// </summary>
public string UserId { get; }

/// <summary>
/// A human-palatable identifier for a user account. It is intended only for display,
/// i.e., aiding the user in determining the difference between user accounts with
/// similar displayNames. Used in Browser UI's and never stored on the server.
/// </summary>
public string Username { get; }

/// <summary>
/// A human-palatable name for the account, which should be chosen by the user.
/// Used in Browser UI's and never stored on the server.
/// </summary>
public string? DisplayName { get; set; }

public
#if NET6_0_OR_GREATER
required
#endif
string Username
{ get; set; }

public string Attestation { get; set; }
public string AuthenticatorType { get; set; }
public bool Discoverable { get; set; }
public string UserVerification { get; set; }
public HashSet<string>? Aliases { get; set; }
public bool AliasHashing { get; set; }

public DateTime ExpiresAt { get; set; }
/// <summary>
/// WebAuthn attestation conveyance preference. Only "none" (default) is supported.
/// </summary>
public string? Attestation { get; set; }

/// <summary>
/// WebAuthn authenticator attachment modality. Can be "any" (default), "platform",
/// which triggers client device-specific options Windows Hello, FaceID, or TouchID,
/// or "cross-platform", which triggers roaming options like security keys.
/// </summary>
public string? AuthenticatorType { get; set; }

/// <summary>
/// If true, creates a client-side Discoverable Credential that allows sign in without needing a username.
/// </summary>
public bool? Discoverable { get; set; }

/// <summary>
/// Allows choosing preference for requiring User Verification
/// (biometrics, pin code etc) when authenticating Can be "preferred" (default), "required" or "discouraged".
/// </summary>
public string? UserVerification { get; set; }

/// <summary>
/// Timestamp (UTC) when the registration token should expire. By default, current time + 120 seconds.
/// </summary>
public DateTime? ExpiresAt { get; set; }

/// <summary>
/// A array of aliases for the userId, such as an email or username. Used to initiate a
/// signin on the client side with the signinWithAlias() method. An alias must be unique to the userId.
/// Defaults to an empty array [].
/// </summary>
public HashSet<string> Aliases { get; set; } = new HashSet<string>();

/// <summary>
/// Whether aliases should be hashed before being stored. Defaults to true.
/// </summary>
public bool? AliasHashing { get; set; }
}
1 change: 1 addition & 0 deletions src/Sdk/PasswordlessApiException.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net.Http;
using System.Text.Json.Serialization;

namespace Passwordless.Net;
Expand Down
34 changes: 32 additions & 2 deletions src/Sdk/PasswordlessClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
Expand All @@ -10,9 +11,10 @@ namespace Passwordless.Net;
/// <summary>
/// TODO: FILL IN
/// </summary>
[DebuggerDisplay("{DebuggerToString()}")]
public class PasswordlessClient : IPasswordlessClient
[DebuggerDisplay("{DebuggerToString(),nq}")]
public class PasswordlessClient : IPasswordlessClient, IDisposable
{
private readonly bool _needsDisposing;
private readonly HttpClient _client;

public static PasswordlessClient Create(PasswordlessOptions options, IHttpClientFactory factory)
Expand All @@ -23,8 +25,19 @@ public static PasswordlessClient Create(PasswordlessOptions options, IHttpClient
return new PasswordlessClient(client);
}

public PasswordlessClient(PasswordlessOptions passwordlessOptions)
{
_needsDisposing = true;
_client = new HttpClient
{
BaseAddress = new Uri(passwordlessOptions.ApiUrl),
};
_client.DefaultRequestHeaders.Add("ApiSecret", passwordlessOptions.ApiSecret);
}

public PasswordlessClient(HttpClient client)
{
_needsDisposing = false;
_client = client;
}

Expand Down Expand Up @@ -122,6 +135,23 @@ private string DebuggerToString()
return sb.ToString();
}

public void Dispose()
{
if (_needsDisposing)
{
Dispose(true);
GC.SuppressFinalize(this);
}
}

protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_client.Dispose();
}
}

public class ListResponse<T>
{
public List<T> Values { get; set; } = null!;
Expand Down
1 change: 1 addition & 0 deletions src/Sdk/PasswordlessDelegatingHandler.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net.Http;
using System.Net.Http.Json;
using Passwordless.Net.Helpers;

Expand Down
2 changes: 2 additions & 0 deletions src/Sdk/PasswordlessHttpRequestExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Net.Http;

namespace Passwordless.Net;

internal static class PasswordlessHttpRequestExtensions
Expand Down
6 changes: 0 additions & 6 deletions src/Sdk/Sdk.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- <TargetFrameworks>net7.0;net462</TargetFrameworks> -->
<TargetFramework>net7.0</TargetFramework> <!--Remove in favor of multitarget when framework is finished.-->
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Passwordless.Net</RootNamespace>
<AssemblyName>Passwordless.Net</AssemblyName>
<VersionPrefix>0.0.14</VersionPrefix>
<PackageId>Passwordless</PackageId>
<Authors>Bitwarden</Authors>
<RepositoryUrl>https://github.com/passwordless/passwordless-dotnet</RepositoryUrl>
Expand Down
1 change: 1 addition & 0 deletions src/Sdk/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net.Http;
using Microsoft.Extensions.Options;
using Passwordless.Net;

Expand Down
8 changes: 3 additions & 5 deletions tests/Sdk.Tests/PasswordlessClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Net.Http;
using Microsoft.Extensions.DependencyInjection;

namespace Passwordless.Net.Tests;
Expand Down Expand Up @@ -28,11 +29,8 @@ public PasswordlessClientTests()
[Fact(Skip = SkipReason)]
public async Task CreateRegisterToken_ThrowsExceptionWhenBad()
{
var exception = await Assert.ThrowsAnyAsync<HttpRequestException>(async () => await _sut.CreateRegisterTokenAsync(new RegisterOptions
{
UserId = null!,
Username = null!,
}));
var exception = await Assert.ThrowsAnyAsync<HttpRequestException>(
async () => await _sut.CreateRegisterTokenAsync(new RegisterOptions(null!, null!)));
}

[Fact(Skip = SkipReason)]
Expand Down
Loading
Loading