Skip to content

Commit

Permalink
Enable nullable context in Crypter.API; code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Edwards committed Dec 3, 2023
1 parent b0781bf commit 60d3f67
Show file tree
Hide file tree
Showing 15 changed files with 74 additions and 36 deletions.
11 changes: 5 additions & 6 deletions Crypter.API/Attributes/MaybeAuthorizeAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,17 @@
using EasyMonads;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;

namespace Crypter.API.Attributes;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
internal class MaybeAuthorizeAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
string authorization = context.HttpContext.Request.Headers.Authorization;
bool authorizationProvided = !string.IsNullOrEmpty(authorization);

if (authorizationProvided)
string? authorization = context.HttpContext.Request.Headers.Authorization;
if (!string.IsNullOrEmpty(authorization))
{
string[] authorizationParts = authorization.Split(' ');
if (authorizationParts.Length != 2 || authorizationParts[0].ToLower() != "bearer")
Expand All @@ -51,7 +50,7 @@ public void OnAuthorization(AuthorizationFilterContext context)
}

ITokenService tokenService =
(ITokenService)context.HttpContext.RequestServices.GetService(typeof(ITokenService));
(ITokenService)context.HttpContext.RequestServices.GetRequiredService(typeof(ITokenService));
Maybe<ClaimsPrincipal> maybeClaims = tokenService.ValidateToken(authorizationParts[1]);

maybeClaims.IfSome(x => context.HttpContext.User = x);
Expand Down
10 changes: 5 additions & 5 deletions Crypter.API/Configuration/SwaggerConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static class SwaggerConfiguration
{
internal static void AddSwaggerGenOptions(this SwaggerGenOptions options)
{
OpenApiSecurityScheme securityDefinition = new()
OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme
{
Name = "Bearer",
BearerFormat = "JWT",
Expand All @@ -45,18 +45,18 @@ internal static void AddSwaggerGenOptions(this SwaggerGenOptions options)
Type = SecuritySchemeType.Http
};

OpenApiSecurityScheme securityScheme = new()
OpenApiSecurityScheme securityScheme = new OpenApiSecurityScheme
{
Reference = new OpenApiReference()
Reference = new OpenApiReference
{
Id = "jwt_auth",
Type = ReferenceType.SecurityScheme
}
};

OpenApiSecurityRequirement securityRequirements = new()
OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement
{
{ securityScheme, Array.Empty<string>() },
{ securityScheme, Array.Empty<string>() }
};

options.AddSecurityDefinition("jwt_auth", securityDefinition);
Expand Down
8 changes: 4 additions & 4 deletions Crypter.API/Contracts/ModelBinders/FormDataJsonBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public Task BindModelAsync(ModelBindingContext bindingContext)
throw new ArgumentNullException(nameof(bindingContext));
}

var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
string modelName = bindingContext.ModelName;
ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

if (valueProviderResult == ValueProviderResult.None)
{
Expand All @@ -29,15 +29,15 @@ public Task BindModelAsync(ModelBindingContext bindingContext)

bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

var value = valueProviderResult.FirstValue;
string? value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value))
{
return Task.CompletedTask;
}

try
{
var result = JsonSerializer.Deserialize(value, bindingContext.ModelType);
object? result = JsonSerializer.Deserialize(value, bindingContext.ModelType);
bindingContext.Result = ModelBindingResult.Success(result);
}
catch (Exception)
Expand Down
4 changes: 2 additions & 2 deletions Crypter.API/Contracts/UploadFileTransferReceipt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace Crypter.API.Contracts;
public class UploadFileTransferReceipt
{
[ModelBinder(BinderType = typeof(FormDataJsonBinder))]
public UploadFileTransferRequest Data { get; set; }
public UploadFileTransferRequest? Data { get; }

public IFormFile Ciphertext { get; set; }
public IFormFile? Ciphertext { get; }
}
4 changes: 2 additions & 2 deletions Crypter.API/Contracts/UploadMessageTransferReceipt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace Crypter.API.Contracts;
public class UploadMessageTransferReceipt
{
[ModelBinder(BinderType = typeof(FormDataJsonBinder))]
public UploadMessageTransferRequest Data { get; set; }
public UploadMessageTransferRequest? Data { get; }

public IFormFile Ciphertext { get; set; }
public IFormFile? Ciphertext { get; }
}
2 changes: 1 addition & 1 deletion Crypter.API/Controllers/FileTransferController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task<IActionResult> UploadFileTransferAsync([FromQuery] string user
Maybe<string> maybeUsername = string.IsNullOrEmpty(username)
? Maybe<string>.None
: username;
await using Stream ciphertextStream = request.Ciphertext.OpenReadStream();
await using Stream? ciphertextStream = request.Ciphertext?.OpenReadStream();

return await TransferUploadService
.UploadFileTransferAsync(PossibleUserId, maybeUsername, request.Data, ciphertextStream)
Expand Down
2 changes: 1 addition & 1 deletion Crypter.API/Controllers/MessageTransferController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task<IActionResult> UploadMessageTransferAsync([FromQuery] string u
Maybe<string> maybeUsername = string.IsNullOrEmpty(username)
? Maybe<string>.None
: username;
await using Stream ciphertextStream = request.Ciphertext.OpenReadStream();
await using Stream? ciphertextStream = request.Ciphertext?.OpenReadStream();

return await TransferUploadService
.UploadMessageTransferAsync(PossibleUserId, maybeUsername, request.Data, ciphertextStream)
Expand Down
2 changes: 1 addition & 1 deletion Crypter.API/Controllers/UserAuthenticationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ or RegistrationError.InvalidEmailAddress
};
#pragma warning restore CS8524
}

return await _userAuthenticationService.RegisterAsync(request)
.MatchAsync(
MakeErrorResponse,
Expand Down
2 changes: 1 addition & 1 deletion Crypter.API/Controllers/UserKeyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ IActionResult MakeErrorResponse(InsertKeyPairError error)
return error switch
{
InsertKeyPairError.UnknownError => MakeErrorResponseBase(HttpStatusCode.InternalServerError, error),
InsertKeyPairError.KeyPairAlreadyExists => MakeErrorResponseBase(HttpStatusCode.Conflict, error),
InsertKeyPairError.KeyPairAlreadyExists => MakeErrorResponseBase(HttpStatusCode.Conflict, error)
};
#pragma warning restore CS8524
}
Expand Down
6 changes: 2 additions & 4 deletions Crypter.API/Controllers/UserRecoveryController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,8 @@ public IActionResult SendRecoveryEmail([FromQuery] string emailAddress)
_hangfireBackgroundService.SendRecoveryEmailAsync(validEmailAddress.Value));
return Accepted();
}
else
{
return MakeErrorResponseBase(HttpStatusCode.BadRequest, SendRecoveryEmailError.InvalidEmailAddress);
}

return MakeErrorResponseBase(HttpStatusCode.BadRequest, SendRecoveryEmailError.InvalidEmailAddress);
}

[HttpPost]
Expand Down
2 changes: 1 addition & 1 deletion Crypter.API/Crypter.API.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>disable</Nullable>
<Nullable>enable</Nullable>
<ImplicitUsings>disable</ImplicitUsings>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* Contact the current copyright holder to discuss commercial license options.
*/

using System;
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;

namespace Crypter.API.MetadataProviders;
Expand Down
8 changes: 5 additions & 3 deletions Crypter.API/Methods/HeadersParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@
*/

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;

namespace Crypter.API.Methods;

public class HeadersParser
public static class HeadersParser
{
public static string GetUserAgent(IHeaderDictionary headers)
{
headers.TryGetValue("User-Agent", out var someUserAgent);
return someUserAgent.ToString() ?? "Unknown device";
return headers.TryGetValue("User-Agent", out StringValues userAgent)
? userAgent.ToString()
: "Unknown device";
}
}
13 changes: 8 additions & 5 deletions Crypter.API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
using System.Linq;
using System.Net;
using Crypter.API.Configuration;
using Crypter.API.MetadataProviders;
using Crypter.API.Middleware;
using Crypter.Common.Contracts;
using Crypter.Core;
using Crypter.Core.Exceptions;
using Crypter.Core.Identity;
using Crypter.Core.Models;
using Crypter.Core.Settings;
Expand All @@ -46,10 +48,10 @@

TokenSettings tokenSettings = builder.Configuration
.GetSection("TokenSettings")
.Get<TokenSettings>();
.Get<TokenSettings>() ?? throw new ConfigurationException("TokenSettings not found");

string hangfireConnectionString = builder.Configuration
.GetConnectionString("HangfireConnection");
.GetConnectionString("HangfireConnection") ?? throw new ConfigurationException("HangfireConnection not found");

builder.Services.AddCrypterCore(
builder.Configuration
Expand Down Expand Up @@ -89,7 +91,8 @@
ErrorResponse errorResponse = new ErrorResponse((int)HttpStatusCode.BadRequest, errors);
return new BadRequestObjectResult(errorResponse);
};
});
})
.AddMvcOptions(options => options.ModelMetadataDetailsProviders.Add(new EmptyStringMetaDataProvider()));

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(SwaggerConfiguration.AddSwaggerGenOptions);
Expand All @@ -115,7 +118,7 @@
{
CorsSettings corsSettings = app.Configuration
.GetSection("CorsSettings")
.Get<CorsSettings>();
.Get<CorsSettings>() ?? throw new ConfigurationException("CorsSettings not found");
app.UseCors(x =>
{
x.AllowAnyMethod();
Expand All @@ -126,7 +129,7 @@

DatabaseSettings dbSettings = app.Configuration
.GetSection("DatabaseSettings")
.Get<DatabaseSettings>();
.Get<DatabaseSettings>() ?? throw new ConfigurationException("DatabaseSettings not found");
await app.MigrateDatabaseAsync(dbSettings);

app.UseHttpsRedirection();
Expand Down
35 changes: 35 additions & 0 deletions Crypter.Core/Exceptions/ConfigurationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2023 Crypter File Transfer
*
* This file is part of the Crypter file transfer project.
*
* Crypter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Crypter source code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* You can be released from the requirements of the aforementioned license
* by purchasing a commercial license. Buying such a license is mandatory
* as soon as you develop commercial activities involving the Crypter source
* code without disclosing the source code of your own applications.
*
* Contact the current copyright holder to discuss commercial license options.
*/

using System;

namespace Crypter.Core.Exceptions;

public class ConfigurationException : Exception
{
public ConfigurationException(string message) : base(message)
{ }
}

0 comments on commit 60d3f67

Please sign in to comment.