Another round of cleanup and beautification

This commit is contained in:
2023-08-19 23:22:44 -04:00
parent 1a25e62fa4
commit 6ac566f9aa
28 changed files with 337 additions and 338 deletions

View File

@ -24,7 +24,7 @@ file_header_template = unset
# this. and Me. preferences # this. and Me. preferences
dotnet_style_qualification_for_event = false:error dotnet_style_qualification_for_event = false:error
dotnet_style_qualification_for_field = false:error dotnet_style_qualification_for_field = false
dotnet_style_qualification_for_method = false:error dotnet_style_qualification_for_method = false:error
dotnet_style_qualification_for_property = false:error dotnet_style_qualification_for_property = false:error
@ -64,7 +64,7 @@ dotnet_style_prefer_simplified_interpolation = true
dotnet_style_readonly_field = true:error dotnet_style_readonly_field = true:error
# Parameter preferences # Parameter preferences
dotnet_code_quality_unused_parameters = all:error dotnet_code_quality__parameters = all:error
# Suppression preferences # Suppression preferences
dotnet_remove_unnecessary_suppression_exclusions = none dotnet_remove_unnecessary_suppression_exclusions = none
@ -127,8 +127,8 @@ csharp_style_prefer_range_operator = true:error
csharp_style_prefer_tuple_swap = true csharp_style_prefer_tuple_swap = true
csharp_style_prefer_utf8_string_literals = true csharp_style_prefer_utf8_string_literals = true
csharp_style_throw_expression = true:error csharp_style_throw_expression = true:error
csharp_style_unused_value_assignment_preference = unused_local_variable:error csharp_style__value_assignment_preference = _local_variable:error
csharp_style_unused_value_expression_statement_preference = unused_local_variable:error csharp_style__value_expression_statement_preference = discard_variable:error
# 'using' directive preferences # 'using' directive preferences
csharp_using_directive_placement = outside_namespace:error csharp_using_directive_placement = outside_namespace:error

View File

@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Reflection; using System.Reflection;
@ -25,35 +26,31 @@ namespace IO.Swagger.Attributes
{ {
object args = null; object args = null;
if (context.ActionArguments.ContainsKey(parameter.Name)) if (context.ActionArguments.ContainsKey(parameter.Name))
{
args = context.ActionArguments[parameter.Name]; args = context.ActionArguments[parameter.Name];
}
ValidateAttributes(parameter, args, context.ModelState); ValidateAttributes(parameter, args, context.ModelState);
} }
} }
if (!context.ModelState.IsValid) if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(context.ModelState); context.Result = new BadRequestObjectResult(context.ModelState);
} }
}
/// <summary>
/// Validates the attributes.
/// </summary>
/// <param name="parameter">The parameter.</param>
/// <param name="args">The arguments.</param>
/// <param name="modelState">State of the model.</param>
private static void ValidateAttributes(ParameterInfo parameter, object args, ModelStateDictionary modelState) private static void ValidateAttributes(ParameterInfo parameter, object args, ModelStateDictionary modelState)
{ {
foreach (CustomAttributeData attributeData in parameter.CustomAttributes) foreach (CustomAttributeData attributeData in parameter.CustomAttributes)
{ {
System.Attribute attributeInstance = parameter.GetCustomAttribute(attributeData.AttributeType); Attribute attributeInstance = parameter.GetCustomAttribute(attributeData.AttributeType);
if (attributeInstance is ValidationAttribute validationAttribute) if (attributeInstance is ValidationAttribute validationAttribute && !validationAttribute.IsValid(args))
{
bool isValid = validationAttribute.IsValid(args);
if (!isValid)
{
modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name)); modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name));
} }
} }
} }
} }
}
}

View File

@ -9,6 +9,7 @@
*/ */
using AutoMapper; using AutoMapper;
using IO.Swagger.Attributes; using IO.Swagger.Attributes;
using IO.Swagger.Models.db;
using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.RequestDto;
using IO.Swagger.Models.ResponseDto; using IO.Swagger.Models.ResponseDto;
using IO.Swagger.Repositories; using IO.Swagger.Repositories;
@ -16,17 +17,15 @@ using IO.Swagger.Security;
using IO.Swagger.Services; using IO.Swagger.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Annotations;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IO.Swagger.Controllers namespace IO.Swagger.Controllers
{ {
/// <summary> /// <summary>
/// /// The controller for handling all auth requests
/// </summary> /// </summary>
[ApiController] [ApiController]
public class AuthApiController : ControllerBase public class AuthApiController : ControllerBase
@ -36,12 +35,18 @@ namespace IO.Swagger.Controllers
private readonly IMapper mapper; private readonly IMapper mapper;
/// <summary> /// <summary>
/// The controller for the authotization endpoints /// Initializes a new instance of the <see cref="AuthApiController"/> class.
/// </summary> /// </summary>
/// <param name="repository"></param> /// <param name="repository">The repository.</param>
/// <param name="jwt"></param> /// <param name="jwt">The JWT.</param>
/// <param name="mapper"></param> /// <param name="mapper">The mapper.</param>
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="System.ArgumentNullException">
/// repository
/// or
/// jwt
/// or
/// mapper
/// </exception>
public AuthApiController(IUserRepository repository, JwtService jwt, IMapper mapper) public AuthApiController(IUserRepository repository, JwtService jwt, IMapper mapper)
{ {
this.repository = repository ?? throw new ArgumentNullException(nameof(repository)); this.repository = repository ?? throw new ArgumentNullException(nameof(repository));
@ -56,16 +61,14 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpGet] [HttpGet]
[Route("/v1/api/auth/details")] [Route("/v1/api/auth/details")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("GetUserDetails")] [SwaggerOperation("GetUserDetails")]
[ProducesResponseType(typeof(UserDto), 200)] [ProducesResponseType(typeof(UserDto), 200)]
public virtual async Task<IActionResult> GetUserDetails() public virtual async Task<IActionResult> GetUserDetails()
{ {
string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; int userId = (int) HttpContext.Items["userId"];
if (!int.TryParse(userIdString, out int userId)) User user = await repository.RetrieveUser(userId);
return Unauthorized();
Models.db.User user = await repository.RetrieveUser(userId);
return Ok(mapper.Map<UserDto>(user)); return Ok(mapper.Map<UserDto>(user));
} }
@ -81,13 +84,11 @@ namespace IO.Swagger.Controllers
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("LoginUser")] [SwaggerOperation("LoginUser")]
[ProducesResponseType(typeof(TokenDto), 200)] [ProducesResponseType(typeof(TokenDto), 200)]
[ProducesResponseType(typeof(IEnumerable<string>), 400)] [ProducesResponseType(typeof(ModelStateDictionary), 400)]
public virtual async Task<IActionResult> LoginUser([FromBody] AuthLoginBody body) public virtual async Task<IActionResult> LoginUser([FromBody] AuthLoginBody body)
{ {
if (!ModelState.IsValid) User user = await repository.LoginUser(body);
return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))); return user == null ? Unauthorized() : Ok(new TokenDto(jwt.GenerateJwt(user.Id)));
Models.db.User user = await repository.LoginUser(body);
return user == null ? Unauthorized() : Ok(new TokenDto { Token = jwt.GenerateJwt(user.Id) });
} }
/// <summary> /// <summary>
@ -100,17 +101,13 @@ namespace IO.Swagger.Controllers
[HttpPost] [HttpPost]
[Route("/v1/api/auth/register")] [Route("/v1/api/auth/register")]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("RegisterUser")] [SwaggerOperation("RegisterUser")]
[ProducesResponseType(typeof(TokenDto), 200)] [ProducesResponseType(typeof(TokenDto), 200)]
[ProducesResponseType(typeof(IEnumerable<string>), 400)] [ProducesResponseType(typeof(ModelStateDictionary), 400)]
public async Task<IActionResult> RegisterUser([FromBody] AuthRegisterBody body) public async Task<IActionResult> RegisterUser([FromBody] AuthRegisterBody body)
{ {
if (!ModelState.IsValid) User user = await repository.RegisterUser(body);
return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))); return user == null ? StatusCode(409) : Ok(new TokenDto(jwt.GenerateJwt(user.Id)));
Models.db.User user = await repository.RegisterUser(body);
return user == null ? StatusCode(409) : Ok(new TokenDto { Token = jwt.GenerateJwt(user.Id) });
} }
} }
} }

View File

@ -9,17 +9,18 @@
*/ */
using AutoMapper; using AutoMapper;
using IO.Swagger.Attributes; using IO.Swagger.Attributes;
using IO.Swagger.Models.db;
using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.RequestDto;
using IO.Swagger.Models.ResponseDto; using IO.Swagger.Models.ResponseDto;
using IO.Swagger.Repositories; using IO.Swagger.Repositories;
using IO.Swagger.Security; using IO.Swagger.Security;
using IO.Swagger.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Annotations;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IO.Swagger.Controllers namespace IO.Swagger.Controllers
@ -59,7 +60,7 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpPost] [HttpPost]
[Route("/v1/api/currency/addAsset")] [Route("/v1/api/currency/addAsset")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("AddDigitalAssetToCollection")] [SwaggerOperation("AddDigitalAssetToCollection")]
public virtual IActionResult AddDigitalAssetToCollection([FromBody] CurrencyAddAssetBody body) public virtual IActionResult AddDigitalAssetToCollection([FromBody] CurrencyAddAssetBody body)
@ -85,7 +86,7 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpPost] [HttpPost]
[Route("/v1/api/currency/createCollection")] [Route("/v1/api/currency/createCollection")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("CreateAssetCollection")] [SwaggerOperation("CreateAssetCollection")]
public virtual IActionResult CreateAssetCollection([FromBody] CurrencyCreateCollectionBody body) public virtual IActionResult CreateAssetCollection([FromBody] CurrencyCreateCollectionBody body)
@ -112,19 +113,13 @@ namespace IO.Swagger.Controllers
/// <response code="422">Unprocessable Content</response> /// <response code="422">Unprocessable Content</response>
[HttpPost] [HttpPost]
[Route("/v1/api/currency/create")] [Route("/v1/api/currency/create")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("CreateCurrency")] [SwaggerOperation("CreateCurrency")]
[ProducesResponseType(typeof(IEnumerable<string>), 400)] [ProducesResponseType(typeof(ModelStateDictionary), 400)]
public virtual async Task<IActionResult> CreateCurrency([FromBody] CurrencyCreateBody body) public virtual async Task<IActionResult> CreateCurrency([FromBody] CurrencyCreateBody body)
{ {
string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; int userId = (int) HttpContext.Items["userId"];
if (!int.TryParse(userIdString, out int userId))
return Unauthorized();
if (!ModelState.IsValid)
return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)));
bool createdCurr = await repo.CreateCurrency(body, userId); bool createdCurr = await repo.CreateCurrency(body, userId);
return createdCurr ? StatusCode(201) : StatusCode(422); return createdCurr ? StatusCode(201) : StatusCode(422);
} }
@ -139,18 +134,13 @@ namespace IO.Swagger.Controllers
/// <response code="409">Conflict - User is not owner or currency does not exist</response> /// <response code="409">Conflict - User is not owner or currency does not exist</response>
[HttpPost] [HttpPost]
[Route("/v1/api/currency/mint")] [Route("/v1/api/currency/mint")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("MintCurrency")] [SwaggerOperation("MintCurrency")]
[ProducesResponseType(typeof(IEnumerable<string>), 400)] [ProducesResponseType(typeof(ModelStateDictionary), 400)]
public virtual async Task<IActionResult> MintCurrency([FromBody] CurrencyMintBody body) public virtual async Task<IActionResult> MintCurrency([FromBody] CurrencyMintBody body)
{ {
string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; int userId = (int) HttpContext.Items["userId"];
if (!int.TryParse(userIdString, out int userId))
return Unauthorized();
if (!ModelState.IsValid)
return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)));
bool minted = await repo.MintCurrency(body, userId); bool minted = await repo.MintCurrency(body, userId);
return minted ? Ok() : StatusCode(409); return minted ? Ok() : StatusCode(409);
} }
@ -162,19 +152,17 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpGet] [HttpGet]
[Route("/v1/api/currency/getAll")] [Route("/v1/api/currency/getAll")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("GetAllCurrencies")] [SwaggerOperation("GetAllCurrencies")]
[ProducesResponseType(typeof(IEnumerable<CurrencyInfoDto>), 200)] [ProducesResponseType(typeof(IEnumerable<CurrencyInfoDto>), 200)]
public virtual async Task<IActionResult> GetAllCurrencies() public virtual async Task<IActionResult> GetAllCurrencies()
{ {
string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; int userId = (int) HttpContext.Items["userId"];
if (!int.TryParse(userIdString, out int userId))
return Unauthorized();
List<Models.db.Currency> rawCurrencies = await repo.GetAllCurrencies(); List<Currency> rawCurrencies = await repo.GetAllCurrencies();
List<CurrencyInfoDto> res = new(); List<CurrencyInfoDto> res = new();
foreach (Models.db.Currency raw in rawCurrencies) foreach (Currency raw in rawCurrencies)
{ {
CurrencyInfoDto c = mapper.Map<CurrencyInfoDto>(raw); CurrencyInfoDto c = mapper.Map<CurrencyInfoDto>(raw);
c.IsOwner = raw.UserId == userId; c.IsOwner = raw.UserId == userId;

View File

@ -9,17 +9,19 @@
*/ */
using AutoMapper; using AutoMapper;
using IO.Swagger.Attributes; using IO.Swagger.Attributes;
using IO.Swagger.Models.db;
using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.RequestDto;
using IO.Swagger.Models.ResponseDto; using IO.Swagger.Models.ResponseDto;
using IO.Swagger.Repositories; using IO.Swagger.Repositories;
using IO.Swagger.Security; using IO.Swagger.Security;
using IO.Swagger.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Swashbuckle.AspNetCore.Annotations; using Swashbuckle.AspNetCore.Annotations;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IO.Swagger.Controllers namespace IO.Swagger.Controllers
@ -56,17 +58,15 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpGet] [HttpGet]
[Route("/v1/api/wallet/balances")] [Route("/v1/api/wallet/balances")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("GetUserBalances")] [SwaggerOperation("GetUserBalances")]
[ProducesResponseType(typeof(IEnumerable<WalletBalanceDto>), 200)] [ProducesResponseType(typeof(IEnumerable<WalletBalanceDto>), 200)]
public virtual async Task<IActionResult> GetUserBalances() public virtual async Task<IActionResult> GetUserBalances()
{ {
string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; int userId = (int) HttpContext.Items["userId"];
if (!int.TryParse(userIdString, out int userId))
return Unauthorized();
List<Tuple<Models.db.Currency, float>> balances = await transactionRepository.GetBalancesForUser(userId); List<Tuple<Currency, float>> balances = await transactionRepository.GetBalancesForUser(userId);
IEnumerable<WalletBalanceDto> res = balances.Select(t => new WalletBalanceDto IEnumerable<WalletBalanceDto> res = balances.Select(t => new WalletBalanceDto
{ {
Currency = mapper.Map<CurrencyDto>(t.Item1), Currency = mapper.Map<CurrencyDto>(t.Item1),
@ -82,17 +82,14 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpGet] [HttpGet]
[Route("/v1/api/wallet/transactions")] [Route("/v1/api/wallet/transactions")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("GetUserTransactions")] [SwaggerOperation("GetUserTransactions")]
[ProducesResponseType(typeof(IEnumerable<TransactionDto>), 200)] [ProducesResponseType(typeof(IEnumerable<TransactionDto>), 200)]
public virtual async Task<IActionResult> GetUserTransactions() public virtual async Task<IActionResult> GetUserTransactions()
{ {
string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; int userId = (int) HttpContext.Items["userId"];
if (!int.TryParse(userIdString, out int userId)) List<Transaction> transactions = await transactionRepository.GetTransactionsForUser(userId);
return Unauthorized();
List<Models.db.Transaction> transactions = await transactionRepository.GetTransactionsForUser(userId);
return Ok(transactions.Select(mapper.Map<TransactionDto>)); return Ok(transactions.Select(mapper.Map<TransactionDto>));
} }
@ -105,7 +102,7 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpPost] [HttpPost]
[Route("/v1/api/wallet/transferDigital")] [Route("/v1/api/wallet/transferDigital")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("TransferDigitalAsset")] [SwaggerOperation("TransferDigitalAsset")]
public virtual IActionResult TransferDigitalAsset([FromBody] WalletTransferDigitalBody body) public virtual IActionResult TransferDigitalAsset([FromBody] WalletTransferDigitalBody body)
@ -131,19 +128,14 @@ namespace IO.Swagger.Controllers
/// <response code="401">Unauthorized</response> /// <response code="401">Unauthorized</response>
[HttpPost] [HttpPost]
[Route("/v1/api/wallet/transferPhysical")] [Route("/v1/api/wallet/transferPhysical")]
[Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] [Authorize(AuthenticationSchemes = JwtService.SchemeName)]
[ValidateModelState] [ValidateModelState]
[SwaggerOperation("TransferPhysicalCurrency")] [SwaggerOperation("TransferPhysicalCurrency")]
[ProducesResponseType(typeof(IEnumerable<string>), 400)] [ProducesResponseType(typeof(ModelStateDictionary), 400)]
[ProducesResponseType(typeof(TransactionReturnCode), 409)] [ProducesResponseType(typeof(TransactionReturnCode), 409)]
public virtual async Task<IActionResult> TransferPhysicalCurrency([FromBody] WalletTransferPhysicalBody body) public virtual async Task<IActionResult> TransferPhysicalCurrency([FromBody] WalletTransferPhysicalBody body)
{ {
string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; int userId = (int) HttpContext.Items["userId"];
if (!int.TryParse(userIdString, out int userId))
return Unauthorized();
if (!ModelState.IsValid)
return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage)));
TransactionReturnCode transactionResult = await transactionRepository.TransferPhysical(body, userId); TransactionReturnCode transactionResult = await transactionRepository.TransferPhysical(body, userId);
return transactionResult == TransactionReturnCode.Success ? Ok() : StatusCode(409, (int) transactionResult); return transactionResult == TransactionReturnCode.Success ? Ok() : StatusCode(409, (int) transactionResult);
} }

View File

@ -1,5 +1,6 @@
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -34,17 +35,17 @@ namespace IO.Swagger.Filters
{ {
swaggerDoc.Servers.Add(new OpenApiServer() { Url = BasePath }); swaggerDoc.Servers.Add(new OpenApiServer() { Url = BasePath });
System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, OpenApiPathItem>> pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(BasePath)).ToList(); List<KeyValuePair<string, OpenApiPathItem>> pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(BasePath)).ToList();
foreach (System.Collections.Generic.KeyValuePair<string, OpenApiPathItem> path in pathsToModify) foreach (KeyValuePair<string, OpenApiPathItem> path in pathsToModify)
{
if (path.Key.StartsWith(BasePath))
{ {
if (!path.Key.StartsWith(BasePath))
continue;
string newKey = Regex.Replace(path.Key, $"^{BasePath}", string.Empty); string newKey = Regex.Replace(path.Key, $"^{BasePath}", string.Empty);
bool unused = swaggerDoc.Paths.Remove(path.Key); _ = swaggerDoc.Paths.Remove(path.Key);
swaggerDoc.Paths.Add(newKey, path.Value); swaggerDoc.Paths.Add(newKey, path.Value);
} }
} }
} }
} }
}

View File

@ -1,8 +1,11 @@
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Linq; using System.Linq;
using System.Reflection;
namespace IO.Swagger.Filters namespace IO.Swagger.Filters
{ {
@ -18,18 +21,18 @@ namespace IO.Swagger.Filters
/// <param name="context">OperationFilterContext</param> /// <param name="context">OperationFilterContext</param>
public void Apply(OpenApiOperation operation, OperationFilterContext context) public void Apply(OpenApiOperation operation, OperationFilterContext context)
{ {
System.Collections.Generic.IList<Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription> pars = context.ApiDescription.ParameterDescriptions; IList<ApiParameterDescription> pars = context.ApiDescription.ParameterDescriptions;
foreach (Microsoft.AspNetCore.Mvc.ApiExplorer.ApiParameterDescription par in pars) foreach (ApiParameterDescription par in pars)
{ {
OpenApiParameter swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name); OpenApiParameter swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name);
System.Collections.Generic.IEnumerable<System.Reflection.CustomAttributeData> attributes = ((ControllerParameterDescriptor) par.ParameterDescriptor).ParameterInfo.CustomAttributes; IEnumerable<CustomAttributeData> attributes = ((ControllerParameterDescriptor) par.ParameterDescriptor).ParameterInfo.CustomAttributes;
if (attributes != null && attributes.Any() && swaggerParam != null) if (attributes != null && attributes.Any() && swaggerParam != null)
{ {
// Required - [Required] // Required - [Required]
System.Reflection.CustomAttributeData requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute)); CustomAttributeData requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute));
if (requiredAttr != null) if (requiredAttr != null)
{ {
swaggerParam.Required = true; swaggerParam.Required = true;
@ -47,25 +50,25 @@ namespace IO.Swagger.Filters
} }
// String Length [StringLength] // String Length [StringLength]
int? minLenght = null, maxLength = null; int? minLength = null, maxLength = null;
System.Reflection.CustomAttributeData stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute)); CustomAttributeData stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute));
if (stringLengthAttr != null) if (stringLengthAttr != null)
{ {
if (stringLengthAttr.NamedArguments.Count == 1) if (stringLengthAttr.NamedArguments.Count == 1)
{ {
minLenght = (int) stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value; minLength = (int) stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value;
} }
maxLength = (int) stringLengthAttr.ConstructorArguments[0].Value; maxLength = (int) stringLengthAttr.ConstructorArguments[0].Value;
} }
System.Reflection.CustomAttributeData minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute)); CustomAttributeData minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute));
if (minLengthAttr != null) if (minLengthAttr != null)
{ {
minLenght = (int) minLengthAttr.ConstructorArguments[0].Value; minLength = (int) minLengthAttr.ConstructorArguments[0].Value;
} }
System.Reflection.CustomAttributeData maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute)); CustomAttributeData maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute));
if (maxLengthAttr != null) if (maxLengthAttr != null)
{ {
maxLength = (int) maxLengthAttr.ConstructorArguments[0].Value; maxLength = (int) maxLengthAttr.ConstructorArguments[0].Value;
@ -73,12 +76,12 @@ namespace IO.Swagger.Filters
if (swaggerParam is not null) if (swaggerParam is not null)
{ {
swaggerParam.Schema.MinLength = minLenght; swaggerParam.Schema.MinLength = minLength;
swaggerParam.Schema.MaxLength = maxLength; swaggerParam.Schema.MaxLength = maxLength;
} }
// Range [Range] // Range [Range]
System.Reflection.CustomAttributeData rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute)); CustomAttributeData rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute));
if (rangeAttr != null) if (rangeAttr != null)
{ {
int rangeMin = (int) rangeAttr.ConstructorArguments[0].Value; int rangeMin = (int) rangeAttr.ConstructorArguments[0].Value;

View File

@ -8,7 +8,7 @@ namespace IO.Swagger.Migrations
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
var unused = migrationBuilder.CreateTable( _ = migrationBuilder.CreateTable(
name: "Users", name: "Users",
columns: table => new columns: table => new
{ {
@ -27,7 +27,7 @@ namespace IO.Swagger.Migrations
/// <inheritdoc /> /// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.DropTableOperation> unused = migrationBuilder.DropTable( _ = migrationBuilder.DropTable(
name: "Users"); name: "Users");
} }
} }

View File

@ -8,11 +8,11 @@ namespace IO.Swagger.Migrations
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.DropColumnOperation> unused2 = migrationBuilder.DropColumn( _ = migrationBuilder.DropColumn(
name: "Username", name: "Username",
table: "Users"); table: "Users");
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AlterColumnOperation> unused1 = migrationBuilder.AlterColumn<string>( _ = migrationBuilder.AlterColumn<string>(
name: "LastName", name: "LastName",
table: "Users", table: "Users",
type: "nvarchar(32)", type: "nvarchar(32)",
@ -22,7 +22,7 @@ namespace IO.Swagger.Migrations
oldType: "nvarchar(max)", oldType: "nvarchar(max)",
oldNullable: true); oldNullable: true);
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AlterColumnOperation> unused = migrationBuilder.AlterColumn<string>( _ = migrationBuilder.AlterColumn<string>(
name: "FirstName", name: "FirstName",
table: "Users", table: "Users",
type: "nvarchar(32)", type: "nvarchar(32)",
@ -36,7 +36,7 @@ namespace IO.Swagger.Migrations
/// <inheritdoc /> /// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AlterColumnOperation> unused2 = migrationBuilder.AlterColumn<string>( _ = migrationBuilder.AlterColumn<string>(
name: "LastName", name: "LastName",
table: "Users", table: "Users",
type: "nvarchar(max)", type: "nvarchar(max)",
@ -46,7 +46,7 @@ namespace IO.Swagger.Migrations
oldMaxLength: 32, oldMaxLength: 32,
oldNullable: true); oldNullable: true);
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AlterColumnOperation> unused1 = migrationBuilder.AlterColumn<string>( _ = migrationBuilder.AlterColumn<string>(
name: "FirstName", name: "FirstName",
table: "Users", table: "Users",
type: "nvarchar(max)", type: "nvarchar(max)",
@ -56,7 +56,7 @@ namespace IO.Swagger.Migrations
oldMaxLength: 32, oldMaxLength: 32,
oldNullable: true); oldNullable: true);
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AddColumnOperation> unused = migrationBuilder.AddColumn<string>( _ = migrationBuilder.AddColumn<string>(
name: "Username", name: "Username",
table: "Users", table: "Users",
type: "nvarchar(max)", type: "nvarchar(max)",

View File

@ -9,7 +9,7 @@ namespace IO.Swagger.Migrations
/// <inheritdoc /> /// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
var unused11 = migrationBuilder.CreateTable( _ = migrationBuilder.CreateTable(
name: "Currencies", name: "Currencies",
columns: table => new columns: table => new
{ {
@ -21,15 +21,15 @@ namespace IO.Swagger.Migrations
}, },
constraints: table => constraints: table =>
{ {
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AddPrimaryKeyOperation> unused10 = table.PrimaryKey("PK_Currencies", x => x.CurrencyId); _ = table.PrimaryKey("PK_Currencies", x => x.CurrencyId);
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AddForeignKeyOperation> unused9 = table.ForeignKey( _ = table.ForeignKey(
name: "FK_Currencies_Users_UserId", name: "FK_Currencies_Users_UserId",
column: x => x.UserId, column: x => x.UserId,
principalTable: "Users", principalTable: "Users",
principalColumn: "Id"); principalColumn: "Id");
}); });
var unused8 = migrationBuilder.CreateTable( _ = migrationBuilder.CreateTable(
name: "Transactions", name: "Transactions",
columns: table => new columns: table => new
{ {
@ -44,40 +44,40 @@ namespace IO.Swagger.Migrations
}, },
constraints: table => constraints: table =>
{ {
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AddPrimaryKeyOperation> unused7 = table.PrimaryKey("PK_Transactions", x => x.TransactionId); _ = table.PrimaryKey("PK_Transactions", x => x.TransactionId);
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AddForeignKeyOperation> unused6 = table.ForeignKey( _ = table.ForeignKey(
name: "FK_Transactions_Currencies_CurrencyId", name: "FK_Transactions_Currencies_CurrencyId",
column: x => x.CurrencyId, column: x => x.CurrencyId,
principalTable: "Currencies", principalTable: "Currencies",
principalColumn: "CurrencyId"); principalColumn: "CurrencyId");
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AddForeignKeyOperation> unused5 = table.ForeignKey( _ = table.ForeignKey(
name: "FK_Transactions_Users_FromUserId", name: "FK_Transactions_Users_FromUserId",
column: x => x.FromUserId, column: x => x.FromUserId,
principalTable: "Users", principalTable: "Users",
principalColumn: "Id"); principalColumn: "Id");
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.AddForeignKeyOperation> unused4 = table.ForeignKey( _ = table.ForeignKey(
name: "FK_Transactions_Users_ToUserId", name: "FK_Transactions_Users_ToUserId",
column: x => x.ToUserId, column: x => x.ToUserId,
principalTable: "Users", principalTable: "Users",
principalColumn: "Id"); principalColumn: "Id");
}); });
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.CreateIndexOperation> unused3 = migrationBuilder.CreateIndex( _ = migrationBuilder.CreateIndex(
name: "IX_Currencies_UserId", name: "IX_Currencies_UserId",
table: "Currencies", table: "Currencies",
column: "UserId"); column: "UserId");
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.CreateIndexOperation> unused2 = migrationBuilder.CreateIndex( _ = migrationBuilder.CreateIndex(
name: "IX_Transactions_CurrencyId", name: "IX_Transactions_CurrencyId",
table: "Transactions", table: "Transactions",
column: "CurrencyId"); column: "CurrencyId");
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.CreateIndexOperation> unused1 = migrationBuilder.CreateIndex( _ = migrationBuilder.CreateIndex(
name: "IX_Transactions_FromUserId", name: "IX_Transactions_FromUserId",
table: "Transactions", table: "Transactions",
column: "FromUserId"); column: "FromUserId");
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.CreateIndexOperation> unused = migrationBuilder.CreateIndex( _ = migrationBuilder.CreateIndex(
name: "IX_Transactions_ToUserId", name: "IX_Transactions_ToUserId",
table: "Transactions", table: "Transactions",
column: "ToUserId"); column: "ToUserId");
@ -86,10 +86,10 @@ namespace IO.Swagger.Migrations
/// <inheritdoc /> /// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.DropTableOperation> unused1 = migrationBuilder.DropTable( _ = migrationBuilder.DropTable(
name: "Transactions"); name: "Transactions");
Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder<Microsoft.EntityFrameworkCore.Migrations.Operations.DropTableOperation> unused = migrationBuilder.DropTable( _ = migrationBuilder.DropTable(
name: "Currencies"); name: "Currencies");
} }
} }

View File

@ -9,13 +9,14 @@
*/ */
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
namespace IO.Swagger.Models.RequestDto namespace IO.Swagger.Models.RequestDto
{ {
/// <summary> /// <summary>
/// /// The DTO used for logging into the service
/// </summary> /// </summary>
[DataContract] [DataContract]
public partial class AuthLoginBody : IEquatable<AuthLoginBody> public partial class AuthLoginBody : IEquatable<AuthLoginBody>
@ -25,6 +26,8 @@ namespace IO.Swagger.Models.RequestDto
/// </summary> /// </summary>
[DataMember(Name = "email")] [DataMember(Name = "email")]
[EmailAddress(ErrorMessage = "Invalid email format.")]
[Required]
public string Email { get; set; } public string Email { get; set; }
/// <summary> /// <summary>
@ -32,6 +35,8 @@ namespace IO.Swagger.Models.RequestDto
/// </summary> /// </summary>
[DataMember(Name = "password")] [DataMember(Name = "password")]
[StringLength(32, MinimumLength = 8)]
[Required]
public string Password { get; set; } public string Password { get; set; }
/// <summary> /// <summary>
@ -40,11 +45,11 @@ namespace IO.Swagger.Models.RequestDto
/// <returns>String presentation of the object</returns> /// <returns>String presentation of the object</returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new StringBuilder()
StringBuilder unused3 = sb.Append("class AuthLoginBody {\n"); .Append("class AuthLoginBody {\n")
StringBuilder unused2 = sb.Append(" Email: ").Append(Email).Append('\n'); .Append(" Email: ").Append(Email).Append('\n')
StringBuilder unused1 = sb.Append(" Password: ").Append(Password).Append('\n'); .Append(" Password: ").Append(Password).Append('\n')
StringBuilder unused = sb.Append("}\n"); .Append("}\n");
return sb.ToString(); return sb.ToString();
} }

View File

@ -16,7 +16,7 @@ using System.Text;
namespace IO.Swagger.Models.RequestDto namespace IO.Swagger.Models.RequestDto
{ {
/// <summary> /// <summary>
/// /// The DTO used for registering with the service
/// </summary> /// </summary>
[DataContract] [DataContract]
public partial class AuthRegisterBody : IEquatable<AuthRegisterBody> public partial class AuthRegisterBody : IEquatable<AuthRegisterBody>
@ -24,7 +24,6 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets FirstName /// Gets or Sets FirstName
/// </summary> /// </summary>
[StringLength(32, MinimumLength = 3)] [StringLength(32, MinimumLength = 3)]
[DataMember(Name = "firstName")] [DataMember(Name = "firstName")]
[Required] [Required]
@ -33,7 +32,6 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets LastName /// Gets or Sets LastName
/// </summary> /// </summary>
[StringLength(32, MinimumLength = 3)] [StringLength(32, MinimumLength = 3)]
[DataMember(Name = "lastName")] [DataMember(Name = "lastName")]
[Required] [Required]
@ -42,7 +40,6 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets Email /// Gets or Sets Email
/// </summary> /// </summary>
[DataMember(Name = "email")] [DataMember(Name = "email")]
[EmailAddress(ErrorMessage = "Invalid email format.")] [EmailAddress(ErrorMessage = "Invalid email format.")]
[Required] [Required]
@ -64,12 +61,12 @@ namespace IO.Swagger.Models.RequestDto
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new();
StringBuilder unused5 = sb.Append("class AuthRegisterBody {\n"); _ = sb.Append("class AuthRegisterBody {\n");
StringBuilder unused4 = sb.Append(" FirstName: ").Append(FirstName).Append('\n'); _ = sb.Append(" FirstName: ").Append(FirstName).Append('\n');
StringBuilder unused3 = sb.Append(" LastName: ").Append(LastName).Append('\n'); _ = sb.Append(" LastName: ").Append(LastName).Append('\n');
StringBuilder unused2 = sb.Append(" Email: ").Append(Email).Append('\n'); _ = sb.Append(" Email: ").Append(Email).Append('\n');
StringBuilder unused1 = sb.Append(" Password: ").Append(Password).Append('\n'); _ = sb.Append(" Password: ").Append(Password).Append('\n');
StringBuilder unused = sb.Append("}\n"); _ = sb.Append("}\n");
return sb.ToString(); return sb.ToString();
} }

View File

@ -16,7 +16,7 @@ using System.Text;
namespace IO.Swagger.Models.RequestDto namespace IO.Swagger.Models.RequestDto
{ {
/// <summary> /// <summary>
/// /// The DTO used for creating an NFT
/// </summary> /// </summary>
[DataContract] [DataContract]
public partial class CurrencyAddAssetBody : IEquatable<CurrencyAddAssetBody> public partial class CurrencyAddAssetBody : IEquatable<CurrencyAddAssetBody>
@ -24,16 +24,16 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets CollectionId /// Gets or Sets CollectionId
/// </summary> /// </summary>
[DataMember(Name = "collectionId")] [DataMember(Name = "collectionId")]
public int? CollectionId { get; set; } [Required]
public int CollectionId { get; set; }
/// <summary> /// <summary>
/// Gets or Sets AssetName /// Gets or Sets AssetName
/// </summary> /// </summary>
[StringLength(32, MinimumLength = 1)] [StringLength(32, MinimumLength = 1)]
[DataMember(Name = "assetName")] [DataMember(Name = "assetName")]
[Required]
public string AssetName { get; set; } public string AssetName { get; set; }
/// <summary> /// <summary>
@ -41,6 +41,7 @@ namespace IO.Swagger.Models.RequestDto
/// </summary> /// </summary>
[RegularExpression("/^(https?|ftp)://[^\\s/$.?#].[^\\s]*$/")] [RegularExpression("/^(https?|ftp)://[^\\s/$.?#].[^\\s]*$/")]
[DataMember(Name = "assetLink")] [DataMember(Name = "assetLink")]
[Required]
public string AssetLink { get; set; } public string AssetLink { get; set; }
/// <summary> /// <summary>
@ -49,12 +50,12 @@ namespace IO.Swagger.Models.RequestDto
/// <returns>String presentation of the object</returns> /// <returns>String presentation of the object</returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new StringBuilder()
StringBuilder unused4 = sb.Append("class CurrencyAddAssetBody {\n"); .Append("class CurrencyAddAssetBody {\n")
StringBuilder unused3 = sb.Append(" CollectionId: ").Append(CollectionId).Append('\n'); .Append(" CollectionId: ").Append(CollectionId).Append('\n')
StringBuilder unused2 = sb.Append(" AssetName: ").Append(AssetName).Append('\n'); .Append(" AssetName: ").Append(AssetName).Append('\n')
StringBuilder unused1 = sb.Append(" AssetLink: ").Append(AssetLink).Append('\n'); .Append(" AssetLink: ").Append(AssetLink).Append('\n')
StringBuilder unused = sb.Append("}\n"); .Append("}\n");
return sb.ToString(); return sb.ToString();
} }
@ -88,8 +89,7 @@ namespace IO.Swagger.Models.RequestDto
&& (ReferenceEquals(this, other) && (ReferenceEquals(this, other)
|| (( || ((
CollectionId == other.CollectionId || CollectionId == other.CollectionId ||
(CollectionId != null && CollectionId.Equals(other.CollectionId)
CollectionId.Equals(other.CollectionId))
) && ) &&
( (
AssetName == other.AssetName || AssetName == other.AssetName ||
@ -113,7 +113,6 @@ namespace IO.Swagger.Models.RequestDto
{ {
int hashCode = 41; int hashCode = 41;
// Suitable nullity checks etc, of course :) // Suitable nullity checks etc, of course :)
if (CollectionId != null)
hashCode = (hashCode * 59) + CollectionId.GetHashCode(); hashCode = (hashCode * 59) + CollectionId.GetHashCode();
if (AssetName != null) if (AssetName != null)
hashCode = (hashCode * 59) + AssetName.GetHashCode(); hashCode = (hashCode * 59) + AssetName.GetHashCode();

View File

@ -16,7 +16,7 @@ using System.Text;
namespace IO.Swagger.Models.RequestDto namespace IO.Swagger.Models.RequestDto
{ {
/// <summary> /// <summary>
/// /// The DTO used for creating a currency
/// </summary> /// </summary>
[DataContract] [DataContract]
public partial class CurrencyCreateBody : IEquatable<CurrencyCreateBody> public partial class CurrencyCreateBody : IEquatable<CurrencyCreateBody>
@ -24,7 +24,6 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets Name /// Gets or Sets Name
/// </summary> /// </summary>
[StringLength(32, MinimumLength = 1)] [StringLength(32, MinimumLength = 1)]
[DataMember(Name = "name")] [DataMember(Name = "name")]
public string Name { get; set; } public string Name { get; set; }
@ -32,7 +31,6 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets Symbol /// Gets or Sets Symbol
/// </summary> /// </summary>
[StringLength(4, MinimumLength = 1)] [StringLength(4, MinimumLength = 1)]
[DataMember(Name = "symbol")] [DataMember(Name = "symbol")]
public string Symbol { get; set; } public string Symbol { get; set; }
@ -43,11 +41,11 @@ namespace IO.Swagger.Models.RequestDto
/// <returns>String presentation of the object</returns> /// <returns>String presentation of the object</returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new StringBuilder()
StringBuilder unused3 = sb.Append("class CurrencyCreateBody {\n"); .Append("class CurrencyCreateBody {\n")
StringBuilder unused2 = sb.Append(" Name: ").Append(Name).Append('\n'); .Append(" Name: ").Append(Name).Append('\n')
StringBuilder unused1 = sb.Append(" Symbol: ").Append(Symbol).Append('\n'); .Append(" Symbol: ").Append(Symbol).Append('\n')
StringBuilder unused = sb.Append("}\n"); .Append("}\n");
return sb.ToString(); return sb.ToString();
} }

View File

@ -9,13 +9,14 @@
*/ */
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
namespace IO.Swagger.Models.RequestDto namespace IO.Swagger.Models.RequestDto
{ {
/// <summary> /// <summary>
/// /// The DTO used for creating an NFT collection
/// </summary> /// </summary>
[DataContract] [DataContract]
public partial class CurrencyCreateCollectionBody : IEquatable<CurrencyCreateCollectionBody> public partial class CurrencyCreateCollectionBody : IEquatable<CurrencyCreateCollectionBody>
@ -23,8 +24,9 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets CollectionName /// Gets or Sets CollectionName
/// </summary> /// </summary>
[DataMember(Name = "collectionName")] [DataMember(Name = "collectionName")]
[Required]
[StringLength(32, MinimumLength = 4)]
public string CollectionName { get; set; } public string CollectionName { get; set; }
/// <summary> /// <summary>
@ -33,10 +35,10 @@ namespace IO.Swagger.Models.RequestDto
/// <returns>String presentation of the object</returns> /// <returns>String presentation of the object</returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new StringBuilder()
StringBuilder unused2 = sb.Append("class CurrencyCreateCollectionBody {\n"); .Append("class CurrencyCreateCollectionBody {\n")
StringBuilder unused1 = sb.Append(" CollectionName: ").Append(CollectionName).Append('\n'); .Append(" CollectionName: ").Append(CollectionName).Append('\n')
StringBuilder unused = sb.Append("}\n"); .Append("}\n");
return sb.ToString(); return sb.ToString();
} }
@ -82,7 +84,6 @@ namespace IO.Swagger.Models.RequestDto
unchecked // Overflow is fine, just wrap unchecked // Overflow is fine, just wrap
{ {
int hashCode = 41; int hashCode = 41;
// Suitable nullity checks etc, of course :)
if (CollectionName != null) if (CollectionName != null)
hashCode = (hashCode * 59) + CollectionName.GetHashCode(); hashCode = (hashCode * 59) + CollectionName.GetHashCode();
return hashCode; return hashCode;

View File

@ -16,7 +16,7 @@ using System.Text;
namespace IO.Swagger.Models.RequestDto namespace IO.Swagger.Models.RequestDto
{ {
/// <summary> /// <summary>
/// /// The DTO for minting an existing currency
/// </summary> /// </summary>
[DataContract] [DataContract]
public partial class CurrencyMintBody : IEquatable<CurrencyMintBody> public partial class CurrencyMintBody : IEquatable<CurrencyMintBody>
@ -24,7 +24,6 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets CurrencyId /// Gets or Sets CurrencyId
/// </summary> /// </summary>
[DataMember(Name = "currencyId")] [DataMember(Name = "currencyId")]
[Required] [Required]
public int CurrencyId { get; set; } public int CurrencyId { get; set; }
@ -32,9 +31,9 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets Amount /// Gets or Sets Amount
/// </summary> /// </summary>
[Required] [Required]
[DataMember(Name = "amount")] [DataMember(Name = "amount")]
[Range(0.1, float.MaxValue, ErrorMessage = "Please enter a valid amount to mint")]
public float Amount { get; set; } public float Amount { get; set; }
/// <summary> /// <summary>
@ -43,11 +42,11 @@ namespace IO.Swagger.Models.RequestDto
/// <returns>String presentation of the object</returns> /// <returns>String presentation of the object</returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new StringBuilder()
StringBuilder unused3 = sb.Append("class CurrencyMintBody {\n"); .Append("class CurrencyMintBody {\n")
StringBuilder unused2 = sb.Append(" CurrencyId: ").Append(CurrencyId).Append('\n'); .Append(" CurrencyId: ").Append(CurrencyId).Append('\n')
StringBuilder unused1 = sb.Append(" Amount: ").Append(Amount).Append('\n'); .Append(" Amount: ").Append(Amount).Append('\n')
StringBuilder unused = sb.Append("}\n"); .Append("}\n");
return sb.ToString(); return sb.ToString();
} }

View File

@ -9,6 +9,7 @@
*/ */
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
@ -23,16 +24,15 @@ namespace IO.Swagger.Models.RequestDto
/// <summary> /// <summary>
/// Gets or Sets Email /// Gets or Sets Email
/// </summary> /// </summary>
[DataMember(Name = "email")] [DataMember(Name = "email")]
[EmailAddress]
public string Email { get; set; } public string Email { get; set; }
/// <summary> /// <summary>
/// Gets or Sets AssetId /// Gets or Sets AssetId
/// </summary> /// </summary>
[DataMember(Name = "assetId")] [DataMember(Name = "assetId")]
public int? AssetId { get; set; } public int AssetId { get; set; }
/// <summary> /// <summary>
/// Returns the string presentation of the object /// Returns the string presentation of the object
@ -40,11 +40,11 @@ namespace IO.Swagger.Models.RequestDto
/// <returns>String presentation of the object</returns> /// <returns>String presentation of the object</returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new StringBuilder()
StringBuilder unused3 = sb.Append("class WalletTransferDigitalBody {\n"); .Append("class WalletTransferDigitalBody {\n")
StringBuilder unused2 = sb.Append(" Email: ").Append(Email).Append('\n'); .Append(" Email: ").Append(Email).Append('\n')
StringBuilder unused1 = sb.Append(" AssetId: ").Append(AssetId).Append('\n'); .Append(" AssetId: ").Append(AssetId).Append('\n')
StringBuilder unused = sb.Append("}\n"); .Append("}\n");
return sb.ToString(); return sb.ToString();
} }
@ -83,8 +83,7 @@ namespace IO.Swagger.Models.RequestDto
) && ) &&
( (
AssetId == other.AssetId || AssetId == other.AssetId ||
(AssetId != null && AssetId.Equals(other.AssetId)
AssetId.Equals(other.AssetId))
))); )));
} }
@ -97,10 +96,8 @@ namespace IO.Swagger.Models.RequestDto
unchecked // Overflow is fine, just wrap unchecked // Overflow is fine, just wrap
{ {
int hashCode = 41; int hashCode = 41;
// Suitable nullity checks etc, of course :)
if (Email != null) if (Email != null)
hashCode = (hashCode * 59) + Email.GetHashCode(); hashCode = (hashCode * 59) + Email.GetHashCode();
if (AssetId != null)
hashCode = (hashCode * 59) + AssetId.GetHashCode(); hashCode = (hashCode * 59) + AssetId.GetHashCode();
return hashCode; return hashCode;
} }

View File

@ -59,12 +59,12 @@ namespace IO.Swagger.Models.RequestDto
/// <returns>String presentation of the object</returns> /// <returns>String presentation of the object</returns>
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new(); StringBuilder sb = new StringBuilder()
StringBuilder unused4 = sb.Append("class WalletTransferPhysicalBody {\n"); .Append("class WalletTransferPhysicalBody {\n")
StringBuilder unused3 = sb.Append(" DestUserEmail: ").Append(DestUserEmail).Append('\n'); .Append(" DestUserEmail: ").Append(DestUserEmail).Append('\n')
StringBuilder unused2 = sb.Append(" Amount: ").Append(Amount).Append('\n'); .Append(" Amount: ").Append(Amount).Append('\n')
StringBuilder unused1 = sb.Append(" CurrencyId: ").Append(CurrencyId).Append('\n'); .Append(" CurrencyId: ").Append(CurrencyId).Append('\n')
StringBuilder unused = sb.Append("}\n"); .Append("}\n");
return sb.ToString(); return sb.ToString();
} }

View File

@ -1,10 +1,22 @@
namespace IO.Swagger.Models.ResponseDto using System;
namespace IO.Swagger.Models.ResponseDto
{ {
/// <summary> /// <summary>
/// The DTO returned when a JWT is requested /// The DTO returned when a JWT is requested
/// </summary> /// </summary>
public class TokenDto public class TokenDto
{ {
/// <summary>
/// Initializes a new instance of the <see cref="TokenDto"/> class.
/// </summary>
/// <param name="token">The token.</param>
/// <exception cref="ArgumentNullException">token</exception>
public TokenDto(string token)
{
Token = token ?? throw new ArgumentNullException(nameof(token));
}
/// <summary> /// <summary>
/// Gets or sets the valid JWT that can be used for accessing other API routes. /// Gets or sets the valid JWT that can be used for accessing other API routes.
/// </summary> /// </summary>

View File

@ -1,4 +1,7 @@
namespace IO.Swagger.Models.ResponseDto using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
namespace IO.Swagger.Models.ResponseDto
{ {
/// <summary> /// <summary>
/// The dto for returning user information /// The dto for returning user information
@ -11,6 +14,9 @@
/// <value> /// <value>
/// The email. /// The email.
/// </value> /// </value>
[DataMember(Name = "email")]
[EmailAddress(ErrorMessage = "Invalid email format.")]
[Required]
public string Email { get; set; } public string Email { get; set; }
/// <summary> /// <summary>
/// Gets or sets the first name of the user. /// Gets or sets the first name of the user.
@ -18,6 +24,9 @@
/// <value> /// <value>
/// The first name. /// The first name.
/// </value> /// </value>
[StringLength(32, MinimumLength = 3)]
[DataMember(Name = "firstName")]
[Required]
public string FirstName { get; set; } public string FirstName { get; set; }
/// <summary> /// <summary>
/// Gets or sets the last name of the user. /// Gets or sets the last name of the user.
@ -25,6 +34,9 @@
/// <value> /// <value>
/// The last name. /// The last name.
/// </value> /// </value>
[StringLength(32, MinimumLength = 3)]
[DataMember(Name = "lastName")]
[Required]
public string LastName { get; set; } public string LastName { get; set; }
} }
} }

View File

@ -2,6 +2,7 @@
using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.RequestDto;
using IO.Swagger.Services; using IO.Swagger.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -40,7 +41,7 @@ namespace IO.Swagger.Repositories
if (await context.Currencies.AnyAsync(c => c.Symbol == request.Symbol || c.Name.ToLower() == request.Name.ToLower())) if (await context.Currencies.AnyAsync(c => c.Symbol == request.Symbol || c.Name.ToLower() == request.Name.ToLower()))
return false; return false;
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<Currency> unused = await context.Currencies.AddAsync(new Currency _ = await context.Currencies.AddAsync(new Currency
{ {
Name = request.Name, Name = request.Name,
Symbol = request.Symbol, Symbol = request.Symbol,
@ -57,7 +58,7 @@ namespace IO.Swagger.Repositories
if (!existsAndIsOwner) if (!existsAndIsOwner)
return false; return false;
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<Transaction> unused = await context.Transactions.AddAsync(new Transaction _ = await context.Transactions.AddAsync(new Transaction
{ {
Amount = request.Amount, Amount = request.Amount,
CurrencyId = request.CurrencyId, CurrencyId = request.CurrencyId,

View File

@ -2,6 +2,7 @@
using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.RequestDto;
using IO.Swagger.Services; using IO.Swagger.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -12,7 +13,7 @@ namespace IO.Swagger.Repositories
/// <summary> /// <summary>
/// The EF implementation of this interface /// The EF implementation of this interface
/// </summary> /// </summary>
/// <seealso cref="IO.Swagger.Repositories.ITransactionRepository" /> /// <seealso cref="ITransactionRepository" />
public class TransactionRepository : ITransactionRepository public class TransactionRepository : ITransactionRepository
{ {
private readonly BankDbContext context; private readonly BankDbContext context;
@ -20,7 +21,7 @@ namespace IO.Swagger.Repositories
/// Initializes a new instance of the <see cref="TransactionRepository"/> class. /// Initializes a new instance of the <see cref="TransactionRepository"/> class.
/// </summary> /// </summary>
/// <param name="context">The context.</param> /// <param name="context">The context.</param>
/// <exception cref="System.ArgumentNullException">context</exception> /// <exception cref="ArgumentNullException">context</exception>
public TransactionRepository(BankDbContext context) public TransactionRepository(BankDbContext context)
{ {
this.context = context ?? throw new ArgumentNullException(nameof(context)); this.context = context ?? throw new ArgumentNullException(nameof(context));
@ -77,7 +78,7 @@ namespace IO.Swagger.Repositories
if (balance == null || balance.Item2 < request.Amount) if (balance == null || balance.Item2 < request.Amount)
return TransactionReturnCode.InsufficientFunds; return TransactionReturnCode.InsufficientFunds;
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<Transaction> unused = await context.Transactions.AddAsync(new Transaction _ = await context.Transactions.AddAsync(new Transaction
{ {
Amount = request.Amount, Amount = request.Amount,
CurrencyId = request.CurrencyId, CurrencyId = request.CurrencyId,

View File

@ -2,8 +2,10 @@
using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.RequestDto;
using IO.Swagger.Services; using IO.Swagger.Services;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System; using System;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace IO.Swagger.Repositories namespace IO.Swagger.Repositories
@ -11,7 +13,7 @@ namespace IO.Swagger.Repositories
/// <summary> /// <summary>
/// The EF implementation of this interface /// The EF implementation of this interface
/// </summary> /// </summary>
/// <seealso cref="IO.Swagger.Repositories.IUserRepository" /> /// <seealso cref="IUserRepository" />
public class UserRepository : IUserRepository public class UserRepository : IUserRepository
{ {
private readonly BankDbContext bankDbContext; private readonly BankDbContext bankDbContext;
@ -35,13 +37,8 @@ namespace IO.Swagger.Repositories
// Generate a random salt // Generate a random salt
byte[] saltBytes = RandomNumberGenerator.GetBytes(16); byte[] saltBytes = RandomNumberGenerator.GetBytes(16);
string salt = Convert.ToBase64String(saltBytes); string salt = Convert.ToBase64String(saltBytes);
// Hash the password along with the salt // Hash the password along with the salt
string password = request.Password; string hashedPassword = HashPassword(salt, request.Password);
string saltedPassword = password + salt;
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(saltedPassword);
byte[] hashedBytes = SHA256.HashData(passwordBytes);
string hashedPassword = Convert.ToBase64String(hashedBytes);
// Create and insert the user // Create and insert the user
User newUser = new() User newUser = new()
@ -53,8 +50,8 @@ namespace IO.Swagger.Repositories
LastName = request.LastName LastName = request.LastName
}; };
Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry<User> unused1 = await bankDbContext.Users.AddAsync(newUser); _ = await bankDbContext.Users.AddAsync(newUser);
int unused = await bankDbContext.SaveChangesAsync(); _ = await bankDbContext.SaveChangesAsync();
return newUser; return newUser;
} }
@ -66,12 +63,7 @@ namespace IO.Swagger.Repositories
if (user == null) if (user == null)
return null; return null;
// Hash the supplied password with the retrieved salt string hashedPassword = HashPassword(user.Salt, request.Password);
string password = request.Password;
string saltedPassword = password + user.Salt;
byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(saltedPassword);
byte[] hashedBytes = SHA256.HashData(passwordBytes);
string hashedPassword = Convert.ToBase64String(hashedBytes);
return hashedPassword != user.PasswordHash ? null : user; return hashedPassword != user.PasswordHash ? null : user;
} }
@ -80,5 +72,20 @@ namespace IO.Swagger.Repositories
{ {
return await bankDbContext.Users.FirstOrDefaultAsync(u => u.Id == userId); return await bankDbContext.Users.FirstOrDefaultAsync(u => u.Id == userId);
} }
/// <summary>
/// Hashes the password.
/// </summary>
/// <param name="salt">The salt to apply.</param>
/// <param name="password">The password to hash.</param>
/// <returns>The hashed and salted password</returns>
private static string HashPassword(string salt, string password)
{
string saltedPassword = password + salt;
byte[] passwordBytes = Encoding.UTF8.GetBytes(saltedPassword);
byte[] hashedBytes = SHA256.HashData(passwordBytes);
string hashedPassword = Convert.ToBase64String(hashedBytes);
return hashedPassword;
}
} }
} }

View File

@ -1,3 +1,4 @@
using IO.Swagger.Services;
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -17,20 +18,12 @@ namespace IO.Swagger.Security
/// </summary> /// </summary>
public class BearerAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions> public class BearerAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{ {
//TODO: Clean this up and use the service for it private readonly JwtService jwtService;
private readonly string secretKey;
private readonly byte[] secretBytes;
/// <summary>
/// scheme name for authentication handler.
/// </summary>
public const string SchemeName = "Bearer";
/// <inheritdoc/> /// <inheritdoc/>
public BearerAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) public BearerAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, JwtService jwtService) : base(options, logger, encoder, clock)
{ {
secretKey = Environment.GetEnvironmentVariable("JWT_SECRET_KEY"); this.jwtService = jwtService ?? throw new ArgumentNullException(nameof(jwtService));
secretBytes = Encoding.UTF8.GetBytes(secretKey);
} }
/// <summary> /// <summary>
@ -38,53 +31,9 @@ namespace IO.Swagger.Security
/// </summary> /// </summary>
protected override Task<AuthenticateResult> HandleAuthenticateAsync() protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{ {
return Task.Run(() => return Task.Run(() => Request.Headers.ContainsKey("Authorization")
{ ? jwtService.ValidateJwt(Request, Scheme.Name)
if (!Request.Headers.ContainsKey("Authorization")) : AuthenticateResult.Fail("Missing Authorization Header"));
{
return AuthenticateResult.Fail("Missing Authorization Header");
}
try
{
AuthenticationHeaderValue authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
JwtSecurityTokenHandler tokenHandler = new();
TokenValidationParameters validationParameters = new()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(secretBytes),
ValidateIssuer = false,
ValidateAudience = false
};
try
{
ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(authHeader.Parameter, validationParameters, out _);
Claim userIdClaim = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier);
if (userIdClaim != null && int.TryParse(userIdClaim.Value, out int userId))
{
Claim[] claims = new[] { new Claim(ClaimTypes.NameIdentifier, userId.ToString()) };
ClaimsIdentity identity = new(claims, SchemeName);
ClaimsPrincipal principal = new(identity);
AuthenticationTicket ticket = new(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
catch (Exception)
{
return AuthenticateResult.Fail("Invalid Auth Token");
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
return AuthenticateResult.Fail("Missing Authorization Header");
});
} }
} }
} }

View File

@ -1,12 +1,13 @@
using IO.Swagger.Models.db; using IO.Swagger.Models.db;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace IO.Swagger.Services namespace IO.Swagger.Services
{ {
/// <summary> /// <summary>
/// The EF DbContext that owns all connections and interactions /// The EF DbContext that owns all connections and interactions
/// </summary> /// </summary>
/// <seealso cref="Microsoft.EntityFrameworkCore.DbContext" /> /// <seealso cref="DbContext" />
public class BankDbContext : DbContext public class BankDbContext : DbContext
{ {
/// <inheritdoc/> /// <inheritdoc/>
@ -42,7 +43,7 @@ namespace IO.Swagger.Services
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
// currency -> user FK // currency -> user FK
Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder<User, Currency> unused3 = modelBuilder.Entity<User>() _ = modelBuilder.Entity<User>()
.HasMany(u => u.Currencies) .HasMany(u => u.Currencies)
.WithOne(c => c.User) .WithOne(c => c.User)
.HasForeignKey(c => c.UserId) .HasForeignKey(c => c.UserId)
@ -50,21 +51,21 @@ namespace IO.Swagger.Services
.OnDelete(DeleteBehavior.NoAction); .OnDelete(DeleteBehavior.NoAction);
// transaction -> from user // transaction -> from user
Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder<User, Transaction> unused2 = modelBuilder.Entity<User>() _ = modelBuilder.Entity<User>()
.HasMany(u => u.TransactionsFrom) .HasMany(u => u.TransactionsFrom)
.WithOne(t => t.FromUser) .WithOne(t => t.FromUser)
.HasForeignKey(t => t.FromUserId) .HasForeignKey(t => t.FromUserId)
.HasPrincipalKey(u => u.Id) .HasPrincipalKey(u => u.Id)
.OnDelete(DeleteBehavior.NoAction); .OnDelete(DeleteBehavior.NoAction);
// transaction -> to user // transaction -> to user
Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder<User, Transaction> unused1 = modelBuilder.Entity<User>() _ = modelBuilder.Entity<User>()
.HasMany(u => u.TransactionsTo) .HasMany(u => u.TransactionsTo)
.WithOne(t => t.ToUser) .WithOne(t => t.ToUser)
.HasForeignKey(t => t.ToUserId) .HasForeignKey(t => t.ToUserId)
.HasPrincipalKey(u => u.Id) .HasPrincipalKey(u => u.Id)
.OnDelete(DeleteBehavior.NoAction); .OnDelete(DeleteBehavior.NoAction);
// transaction -> currency // transaction -> currency
Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder<Currency, Transaction> unused = modelBuilder.Entity<Transaction>() _ = modelBuilder.Entity<Transaction>()
.HasOne(t => t.Currency) .HasOne(t => t.Currency)
.WithMany(c => c.Transactions) .WithMany(c => c.Transactions)
.HasForeignKey(t => t.CurrencyId) .HasForeignKey(t => t.CurrencyId)

View File

@ -1,6 +1,10 @@
using Microsoft.IdentityModel.Tokens; using Azure.Core;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using System; using System;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net.Http.Headers;
using System.Security.Claims; using System.Security.Claims;
using System.Text; using System.Text;
@ -14,6 +18,11 @@ namespace IO.Swagger.Services
private readonly string secretKey; private readonly string secretKey;
private readonly byte[] secretBytes; private readonly byte[] secretBytes;
/// <summary>
/// The scheme name for authorization headers
/// </summary>
public const string SchemeName = "Bearer";
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="JwtService"/> class. /// Initializes a new instance of the <see cref="JwtService"/> class.
/// </summary> /// </summary>
@ -46,5 +55,46 @@ namespace IO.Swagger.Services
SecurityToken token = tokenHandler.CreateToken(tokenDescriptor); SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token); return tokenHandler.WriteToken(token);
} }
/// <summary>
/// Validates the JWT.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="schemeName">Name of the scheme.</param>
/// <returns>The result of authenticating the JWT</returns>
public AuthenticateResult ValidateJwt(HttpRequest request, string schemeName)
{
AuthenticationHeaderValue authHeader = AuthenticationHeaderValue.Parse(request.Headers["Authorization"]);
JwtSecurityTokenHandler tokenHandler = new();
TokenValidationParameters validationParameters = new()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(secretBytes),
ValidateIssuer = false,
ValidateAudience = false
};
try
{
ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(authHeader.Parameter, validationParameters, out _);
Claim userIdClaim = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier);
if (userIdClaim != null && int.TryParse(userIdClaim.Value, out int userId))
{
request.HttpContext.Items.Add("userId", userId);
Claim[] claims = new[] { new Claim(ClaimTypes.NameIdentifier, userId.ToString()) };
ClaimsIdentity identity = new(claims, SchemeName);
ClaimsPrincipal principal = new(identity);
AuthenticationTicket ticket = new(principal, schemeName);
return AuthenticateResult.Success(ticket);
}
}
catch
{
return AuthenticateResult.Fail("Invalid Auth Token");
}
return AuthenticateResult.Fail("Invalid Auth Token");
}
} }
} }

View File

@ -16,11 +16,11 @@ namespace IO.Swagger.Services
/// </summary> /// </summary>
public MapperProfile() public MapperProfile()
{ {
IMappingExpression<User, UserDto> unused3 = CreateMap<User, UserDto>(); _ = CreateMap<User, UserDto>();
IMappingExpression<Currency, CurrencyDto> unused2 = CreateMap<Currency, CurrencyDto>(); _ = CreateMap<Currency, CurrencyDto>();
IMappingExpression<Transaction, TransactionDto> unused1 = CreateMap<Transaction, TransactionDto>(); _ = CreateMap<Transaction, TransactionDto>();
IMappingExpression<Currency, CurrencyInfoDto> unused = CreateMap<Currency, CurrencyInfoDto>().ForMember(ci => ci.AmountInCirculation, _ = CreateMap<Currency, CurrencyInfoDto>().ForMember(ci => ci.AmountInCirculation,
mapper => mapper.MapFrom(c => c.Transactions.Where(t => t.ToUserId == t.FromUserId).Sum(t => t.Amount))) mapper => mapper.MapFrom(c => c.Transactions.Where(t => t.ToUserId == t.FromUserId).Sum(t => t.Amount)))
.ForMember(ci => ci.CurrencyOwner, .ForMember(ci => ci.CurrencyOwner,
mapper => mapper.MapFrom(c => c.User)); mapper => mapper.MapFrom(c => c.User));

View File

@ -49,8 +49,7 @@ namespace IO.Swagger
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
// Add framework services. // Add framework services.
IMvcBuilder unused11 = services _ = services.AddMvc(options =>
.AddMvc(options =>
{ {
options.InputFormatters.RemoveType<Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter>(); options.InputFormatters.RemoveType<Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter>();
options.OutputFormatters.RemoveType<Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter>(); options.OutputFormatters.RemoveType<Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter>();
@ -62,11 +61,10 @@ namespace IO.Swagger
}) })
.AddXmlSerializerFormatters(); .AddXmlSerializerFormatters();
AuthenticationBuilder unused10 = services.AddAuthentication(BearerAuthenticationHandler.SchemeName) _ = services.AddAuthentication(JwtService.SchemeName)
.AddScheme<AuthenticationSchemeOptions, BearerAuthenticationHandler>(BearerAuthenticationHandler.SchemeName, null); .AddScheme<AuthenticationSchemeOptions, BearerAuthenticationHandler>(JwtService.SchemeName, null);
IServiceCollection unused9 = services _ = services.AddSwaggerGen(c =>
.AddSwaggerGen(c =>
{ {
c.SwaggerDoc("1.0.0", new OpenApiInfo c.SwaggerDoc("1.0.0", new OpenApiInfo
{ {
@ -118,30 +116,26 @@ namespace IO.Swagger
MapperConfiguration mapperConfig = new(mc => mc.AddProfile(new MapperProfile())); MapperConfiguration mapperConfig = new(mc => mc.AddProfile(new MapperProfile()));
// CORS sucks // CORS sucks
IServiceCollection unused8 = services.AddCors(opt => opt.AddDefaultPolicy(po => _ = services.AddCors(opt => opt.AddDefaultPolicy(po =>
{ {
Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder unused7 = po.AllowAnyHeader() _ = po.AllowAnyHeader()
.WithMethods("GET", "POST") .WithMethods("GET", "POST")
.SetIsOriginAllowedToAllowWildcardSubdomains(); .SetIsOriginAllowedToAllowWildcardSubdomains();
Microsoft.AspNetCore.Cors.Infrastructure.CorsPolicyBuilder unused6 = po.SetIsOriginAllowed((or) => or.Contains("localhost") || or.Contains("shrukanslab")); _ = po.SetIsOriginAllowed((or) => or.Contains("localhost") || or.Contains("shrukanslab"));
})); }));
//Datase connections //Datase connections
string connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION_STRING"); string connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION_STRING");
if (string.IsNullOrEmpty(connectionString)) if (string.IsNullOrEmpty(connectionString))
{
throw new Exception("Database connection string not found in environment variable."); throw new Exception("Database connection string not found in environment variable.");
}
// DI setup // DI setup
IServiceCollection unused5 = services.AddScoped<IUserRepository, UserRepository>(); _ = services.AddScoped<IUserRepository, UserRepository>();
IServiceCollection unused4 = services.AddScoped<ICurrencyRepository, CurrencyRepository>(); _ = services.AddScoped<ICurrencyRepository, CurrencyRepository>();
IServiceCollection unused3 = services.AddScoped<ITransactionRepository, TransactionRepository>(); _ = services.AddScoped<ITransactionRepository, TransactionRepository>();
IServiceCollection unused2 = services.AddDbContext<BankDbContext>(x => x.UseSqlServer(connectionString: connectionString)); _ = services.AddDbContext<BankDbContext>(x => x.UseSqlServer(connectionString));
IServiceCollection unused1 = services.AddSingleton<JwtService>(); _ = services.AddSingleton<JwtService>();
IMapper mapper = mapperConfig.CreateMapper(); _ = services.AddSingleton(mapperConfig.CreateMapper());
IServiceCollection unused = services.AddSingleton(mapper);
} }
/// <summary> /// <summary>
@ -153,32 +147,30 @@ namespace IO.Swagger
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, BankDbContext context) public void Configure(IApplicationBuilder app, IWebHostEnvironment env, BankDbContext context)
{ {
context.Database.Migrate(); context.Database.Migrate();
IApplicationBuilder unused8 = app.UseRouting(); _ = app.UseRouting();
IApplicationBuilder unused7 = app.UseCors(); _ = app.UseCors();
IApplicationBuilder unused6 = app.UseAuthorization(); _ = app.UseAuthorization();
IApplicationBuilder unused5 = app.UseSwagger(); _ = app.UseSwagger();
IApplicationBuilder unused4 = app.UseSwaggerUI(c => _ = app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/1.0.0/swagger.json", "T&J Central Bank API"));
//TODO: Either use the SwaggerGen generated Swagger contract (generated from C# classes)
c.SwaggerEndpoint("/swagger/1.0.0/swagger.json", "T&J Central Bank API"));
//TODO: Use Https Redirection //TODO: Use Https Redirection
// app.UseHttpsRedirection(); // app.UseHttpsRedirection();
IApplicationBuilder unused3 = app.UseEndpoints(endpoints => endpoints.MapControllers()); _ = app.UseEndpoints(endpoints => endpoints.MapControllers());
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
IApplicationBuilder unused2 = app.UseDeveloperExceptionPage(); _ = app.UseDeveloperExceptionPage();
} }
else else
{ {
//TODO: Enable production exception handling (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling) //TODO: Enable production exception handling (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling)
IApplicationBuilder unused1 = app.UseExceptionHandler("/Error"); _ = app.UseExceptionHandler("/Error");
IApplicationBuilder unused = app.UseHsts(); _ = app.UseHsts();
} }
} }
} }