Skip to content

Commit

Permalink
Merge pull request #531 from Crypter-File-Transfer/stable
Browse files Browse the repository at this point in the history
Merge 'stable' to 'main'
  • Loading branch information
Jack-Edwards authored May 31, 2023
2 parents 8a4c4a8 + f37f4b8 commit 058fe13
Show file tree
Hide file tree
Showing 72 changed files with 711 additions and 414 deletions.
2 changes: 1 addition & 1 deletion Crypter.API.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ RUN dotnet-references fix --entry-point ./Crypter.sln --working-directory ./ --r
RUN dotnet restore Crypter.API --runtime linux-x64

COPY ./ ./
RUN dotnet publish Crypter.API --configuration release --no-self-contained --output /app/
RUN dotnet publish Crypter.API --configuration release --no-self-contained /p:TreatWarningsAsErrors=true /warnaserror --output /app/
RUN dotnet-ef migrations bundle --project Crypter.Core --startup-project Crypter.API --configuration release --no-build --target-runtime linux-x64 --output /app/efbundle --verbose

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS runtime
Expand Down
3 changes: 2 additions & 1 deletion Crypter.API/Controllers/UserKeyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ IActionResult MakeErrorResponse(InsertMasterKeyError error)
{
InsertMasterKeyError.UnknownError => MakeErrorResponseBase(HttpStatusCode.InternalServerError, error),
InsertMasterKeyError.Conflict => MakeErrorResponseBase(HttpStatusCode.Conflict, error),
InsertMasterKeyError.InvalidCredentials => MakeErrorResponseBase(HttpStatusCode.BadRequest, error)
InsertMasterKeyError.InvalidPassword
or InsertMasterKeyError.InvalidMasterKey => MakeErrorResponseBase(HttpStatusCode.BadRequest, error)
};
#pragma warning restore CS8524
}
Expand Down
3 changes: 2 additions & 1 deletion Crypter.API/Controllers/UserRecoveryController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ IActionResult MakeErrorResponse(SubmitRecoveryError error)
SubmitRecoveryError.PasswordHashFailure
or SubmitRecoveryError.UnknownError => MakeErrorResponseBase(HttpStatusCode.InternalServerError, error),
SubmitRecoveryError.InvalidUsername
or SubmitRecoveryError.WrongRecoveryKey => MakeErrorResponseBase(HttpStatusCode.BadRequest, error),
or SubmitRecoveryError.WrongRecoveryKey
or SubmitRecoveryError.InvalidMasterKey => MakeErrorResponseBase(HttpStatusCode.BadRequest, error),
SubmitRecoveryError.RecoveryNotFound => MakeErrorResponseBase(HttpStatusCode.NotFound, error)
};
#pragma warning restore CS8524
Expand Down
11 changes: 6 additions & 5 deletions Crypter.API/Crypter.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
<TargetFramework>net7.0</TargetFramework>
<Nullable>disable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(RunConfiguration)' == 'crypterAPI' " />
<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Crypter.Test" />
Expand All @@ -17,12 +18,12 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.5" />
Expand Down
37 changes: 19 additions & 18 deletions Crypter.Benchmarks/Crypter.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Crypter.Common.Client\Crypter.Common.Client.csproj" />
<ProjectReference Include="..\Crypter.Core\Crypter.Core.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Crypter.Common.Client\Crypter.Common.Client.csproj" />
<ProjectReference Include="..\Crypter.Core\Crypter.Core.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="Assets\WindowsCodecsRaw.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="Assets\WindowsCodecsRaw.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
19 changes: 10 additions & 9 deletions Crypter.Common.Client/Crypter.Common.Client.csproj
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>disable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Crypter.Common\Crypter.Common.csproj" />
<ProjectReference Include="..\Crypter.Crypto.Common\Crypter.Crypto.Common.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Crypter.Common\Crypter.Common.csproj" />
<ProjectReference Include="..\Crypter.Crypto.Common\Crypter.Crypto.Common.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ public CrypterAuthenticatedHttpClient(HttpClient httpClient, ITokenRepository to
public async Task<Maybe<TResponse>> GetMaybeAsync<TResponse>(string uri)
where TResponse : class
{
var request = MakeRequestMessageFactory(HttpMethod.Get, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, false);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Get, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, false);
return await DeserializeMaybeResponseAsync<TResponse>(response);
}

Expand All @@ -87,46 +87,49 @@ public Task<Either<ErrorResponse, TResponse>> GetEitherAsync<TResponse>(string u
public async Task<Either<ErrorResponse, TResponse>> GetEitherAsync<TResponse>(string uri, bool useRefreshToken = false)
where TResponse : class
{
var request = MakeRequestMessageFactory(HttpMethod.Get, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, useRefreshToken);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Get, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, useRefreshToken);
return await DeserializeResponseAsync<TResponse>(response);
}

public async Task<Either<ErrorResponse, Unit>> GetEitherUnitResponseAsync(string uri)
{
var request = MakeRequestMessageFactory(HttpMethod.Get, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, false);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Get, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, false);
return await DeserializeEitherUnitResponseAsync(response);
}

public async Task<Either<ErrorResponse, StreamDownloadResponse>> GetStreamResponseAsync(string uri)
{
var request = MakeRequestMessageFactory(HttpMethod.Get, uri);
HttpResponseMessage response = await SendWithAuthenticationAsync(request, false);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Get, uri);

// Do not dispose of the HttpResponseMessage here.
// Callers need to read the contained Stream.
HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, false);
return await GetStreamResponseAsync(response);
}

public async Task<Either<ErrorResponse, TResponse>> PutEitherAsync<TRequest, TResponse>(string uri, TRequest body, bool useRefreshToken = false)
where TRequest : class
{
var request = MakeRequestMessageFactory(HttpMethod.Put, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, useRefreshToken);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Put, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, useRefreshToken);
return await DeserializeResponseAsync<TResponse>(response);
}

public async Task<Either<ErrorResponse, Unit>> PutEitherUnitResponseAsync<TRequest>(string uri, TRequest body, bool useRefreshToken = false)
where TRequest : class
{
var request = MakeRequestMessageFactory(HttpMethod.Put, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, useRefreshToken);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Put, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, useRefreshToken);
return await DeserializeEitherUnitResponseAsync(response);
}

public async Task<Either<ErrorResponse, TResponse>> PostEitherAsync<TResponse>(string uri, bool useRefreshToken = false)
where TResponse : class
{
var request = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, useRefreshToken);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, useRefreshToken);
return await DeserializeResponseAsync<TResponse>(response);
}

Expand All @@ -141,16 +144,16 @@ public async Task<Either<ErrorResponse, TResponse>> PostEitherAsync<TRequest, TR
where TResponse : class
where TRequest : class
{
var request = MakeRequestMessageFactory(HttpMethod.Post, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, false);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Post, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, false);
return await DeserializeResponseAsync<TResponse>(response);
}

public async Task<Maybe<Unit>> PostMaybeUnitResponseAsync(string uri)
{
var request = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, false);
return DeserializeMaybeUnitResponseAsync(response);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, false);
return DeserializeMaybeUnitResponse(response);
}

public Task<Either<ErrorResponse, Unit>> PostEitherUnitResponseAsync(string uri)
Expand All @@ -160,8 +163,8 @@ public Task<Either<ErrorResponse, Unit>> PostEitherUnitResponseAsync(string uri)

public async Task<Either<ErrorResponse, Unit>> PostEitherUnitResponseAsync(string uri, bool useRefreshToken = false)
{
var request = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, useRefreshToken);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, useRefreshToken);
return await DeserializeEitherUnitResponseAsync(response);
}

Expand All @@ -173,32 +176,32 @@ public Task<Either<ErrorResponse, Unit>> PostEitherUnitResponseAsync<TRequest>(s

public async Task<Either<ErrorResponse, Unit>> PostUnitResponseAsync<TRequest>(string uri, bool useRefreshToken = false)
{
var request = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, useRefreshToken);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Post, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, useRefreshToken);
return await DeserializeEitherUnitResponseAsync(response);
}

public async Task<Either<ErrorResponse, Unit>> PostEitherUnitResponseAsync<TRequest>(string uri, TRequest body, bool useRefreshToken = false)
where TRequest : class
{
var request = MakeRequestMessageFactory(HttpMethod.Post, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, useRefreshToken);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Post, uri, body);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, useRefreshToken);
return await DeserializeEitherUnitResponseAsync(response);
}

public async Task<Maybe<Unit>> DeleteUnitResponseAsync(string uri)
{
var request = MakeRequestMessageFactory(HttpMethod.Delete, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(request, false);
var requestFactory = MakeRequestMessageFactory(HttpMethod.Delete, uri);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, false);
return response.IsSuccessStatusCode
? Unit.Default
: Maybe<Unit>.None;
}

public async Task<Either<ErrorResponse, TResponse>> SendAsync<TResponse>(HttpRequestMessage requestMessage)
public async Task<Either<ErrorResponse, TResponse>> SendAsync<TResponse>(Func<HttpRequestMessage> requestFactory)
where TResponse : class
{
using HttpResponseMessage response = await SendWithAuthenticationAsync(() => requestMessage, false);
using HttpResponseMessage response = await SendWithAuthenticationAsync(requestFactory, false);
return await DeserializeResponseAsync<TResponse>(response);
}

Expand All @@ -224,9 +227,10 @@ private async Task<HttpResponseMessage> SendWithAuthenticationAsync(Func<HttpReq
_requestSemaphore.Release();
}

var initialRequest = requestFactory();
using HttpRequestMessage initialRequest = requestFactory();
await AttachTokenAsync(initialRequest, useRefreshToken);
HttpResponseMessage initialAttempt = await _httpClient.SendAsync(initialRequest, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);

if (initialAttempt.StatusCode != HttpStatusCode.Unauthorized || useRefreshToken)
{
return initialAttempt;
Expand All @@ -236,15 +240,15 @@ private async Task<HttpResponseMessage> SendWithAuthenticationAsync(Func<HttpReq
await _requestSemaphore.WaitAsync().ConfigureAwait(false);
try
{
var retryRequest = requestFactory();
var refreshAndRetry = from refreshResponse in _crypterApiClient.UserAuthentication.RefreshSessionAsync()
from unit0 in Either<RefreshError, Unit>.FromRightAsync(_tokenRepository.StoreAuthenticationTokenAsync(refreshResponse.AuthenticationToken))
from unit1 in Either<RefreshError, Unit>.FromRightAsync(_tokenRepository.StoreRefreshTokenAsync(refreshResponse.RefreshToken, refreshResponse.RefreshTokenType))
from unit2 in Either<RefreshError, Unit>.FromRightAsync(AttachTokenAsync(retryRequest, false))
from secondAttempt in Either<RefreshError, HttpResponseMessage>.FromRightAsync(_httpClient.SendAsync(retryRequest, HttpCompletionOption.ResponseHeadersRead))
select secondAttempt;

return await refreshAndRetry.MatchAsync(
using HttpRequestMessage retryRequest = requestFactory();
var refreshAndRetry = await (from refreshResponse in _crypterApiClient.UserAuthentication.RefreshSessionAsync()
from unit0 in Either<RefreshError, Unit>.FromRightAsync(_tokenRepository.StoreAuthenticationTokenAsync(refreshResponse.AuthenticationToken))
from unit1 in Either<RefreshError, Unit>.FromRightAsync(_tokenRepository.StoreRefreshTokenAsync(refreshResponse.RefreshToken, refreshResponse.RefreshTokenType))
from unit2 in Either<RefreshError, Unit>.FromRightAsync(AttachTokenAsync(retryRequest, false))
from secondAttempt in Either<RefreshError, HttpResponseMessage>.FromRightAsync(_httpClient.SendAsync(retryRequest, HttpCompletionOption.ResponseHeadersRead))
select secondAttempt);

return refreshAndRetry.Match(
initialAttempt,
right => right);
}
Expand All @@ -255,7 +259,7 @@ from secondAttempt in Either<RefreshError, HttpResponseMessage>.FromRightAsync(_
}
}

private static Maybe<Unit> DeserializeMaybeUnitResponseAsync(HttpResponseMessage response)
private static Maybe<Unit> DeserializeMaybeUnitResponse(HttpResponseMessage response)
{
return response.IsSuccessStatusCode
? Unit.Default
Expand Down Expand Up @@ -310,12 +314,18 @@ private async Task<Either<ErrorResponse, StreamDownloadResponse>> GetStreamRespo
}

Stream stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
if (!response.IsSuccessStatusCode)

if (response.IsSuccessStatusCode)
{
return await JsonSerializer.DeserializeAsync<ErrorResponse>(stream, _jsonSerializerOptions).ConfigureAwait(false);
// Do not dispose of the Stream here. The caller needs to read it.
return new StreamDownloadResponse(stream, response.Content.Headers.ContentLength!.Value);
}
else
{
ErrorResponse errorResponse = await JsonSerializer.DeserializeAsync<ErrorResponse>(stream, _jsonSerializerOptions).ConfigureAwait(false);
stream.Dispose();
return errorResponse;
}

return new StreamDownloadResponse(stream, response.Content.Headers.ContentLength!.Value);
}

private async Task<Unit> AttachTokenAsync(HttpRequestMessage request, bool useRefreshToken = false)
Expand Down
Loading

0 comments on commit 058fe13

Please sign in to comment.