diff --git a/.editorconfig b/.editorconfig index 77ab070..bdb42b0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -24,7 +24,7 @@ file_header_template = unset # this. and Me. preferences 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_property = false:error @@ -64,7 +64,7 @@ dotnet_style_prefer_simplified_interpolation = true dotnet_style_readonly_field = true:error # Parameter preferences -dotnet_code_quality_unused_parameters = all:error +dotnet_code_quality__parameters = all:error # Suppression preferences 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_utf8_string_literals = true csharp_style_throw_expression = true:error -csharp_style_unused_value_assignment_preference = unused_local_variable:error -csharp_style_unused_value_expression_statement_preference = unused_local_variable:error +csharp_style__value_assignment_preference = _local_variable:error +csharp_style__value_expression_statement_preference = discard_variable:error # 'using' directive preferences csharp_using_directive_placement = outside_namespace:error diff --git a/src/IO.Swagger/Attributes/ValidateModelStateAttribute.cs b/src/IO.Swagger/Attributes/ValidateModelStateAttribute.cs index 63ab90e..2bcd7ac 100644 --- a/src/IO.Swagger/Attributes/ValidateModelStateAttribute.cs +++ b/src/IO.Swagger/Attributes/ValidateModelStateAttribute.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.ModelBinding; +using System; using System.ComponentModel.DataAnnotations; using System.Reflection; @@ -25,34 +26,30 @@ namespace IO.Swagger.Attributes { object args = null; if (context.ActionArguments.ContainsKey(parameter.Name)) - { args = context.ActionArguments[parameter.Name]; - } ValidateAttributes(parameter, args, context.ModelState); } } if (!context.ModelState.IsValid) - { context.Result = new BadRequestObjectResult(context.ModelState); - } } + /// + /// Validates the attributes. + /// + /// The parameter. + /// The arguments. + /// State of the model. private static void ValidateAttributes(ParameterInfo parameter, object args, ModelStateDictionary modelState) { foreach (CustomAttributeData attributeData in parameter.CustomAttributes) { - System.Attribute attributeInstance = parameter.GetCustomAttribute(attributeData.AttributeType); + Attribute attributeInstance = parameter.GetCustomAttribute(attributeData.AttributeType); - if (attributeInstance is ValidationAttribute validationAttribute) - { - bool isValid = validationAttribute.IsValid(args); - if (!isValid) - { - modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name)); - } - } + if (attributeInstance is ValidationAttribute validationAttribute && !validationAttribute.IsValid(args)) + modelState.AddModelError(parameter.Name, validationAttribute.FormatErrorMessage(parameter.Name)); } } } diff --git a/src/IO.Swagger/Controllers/AuthApi.cs b/src/IO.Swagger/Controllers/AuthApi.cs index cca73ab..4825f2e 100644 --- a/src/IO.Swagger/Controllers/AuthApi.cs +++ b/src/IO.Swagger/Controllers/AuthApi.cs @@ -9,6 +9,7 @@ */ using AutoMapper; using IO.Swagger.Attributes; +using IO.Swagger.Models.db; using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.ResponseDto; using IO.Swagger.Repositories; @@ -16,17 +17,15 @@ using IO.Swagger.Security; using IO.Swagger.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Swashbuckle.AspNetCore.Annotations; using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; using System.Threading.Tasks; namespace IO.Swagger.Controllers { /// - /// + /// The controller for handling all auth requests /// [ApiController] public class AuthApiController : ControllerBase @@ -36,12 +35,18 @@ namespace IO.Swagger.Controllers private readonly IMapper mapper; /// - /// The controller for the authotization endpoints + /// Initializes a new instance of the class. /// - /// - /// - /// - /// + /// The repository. + /// The JWT. + /// The mapper. + /// + /// repository + /// or + /// jwt + /// or + /// mapper + /// public AuthApiController(IUserRepository repository, JwtService jwt, IMapper mapper) { this.repository = repository ?? throw new ArgumentNullException(nameof(repository)); @@ -56,16 +61,14 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpGet] [Route("/v1/api/auth/details")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("GetUserDetails")] [ProducesResponseType(typeof(UserDto), 200)] public virtual async Task GetUserDetails() { - string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; - if (!int.TryParse(userIdString, out int userId)) - return Unauthorized(); - Models.db.User user = await repository.RetrieveUser(userId); + int userId = (int) HttpContext.Items["userId"]; + User user = await repository.RetrieveUser(userId); return Ok(mapper.Map(user)); } @@ -81,13 +84,11 @@ namespace IO.Swagger.Controllers [ValidateModelState] [SwaggerOperation("LoginUser")] [ProducesResponseType(typeof(TokenDto), 200)] - [ProducesResponseType(typeof(IEnumerable), 400)] + [ProducesResponseType(typeof(ModelStateDictionary), 400)] public virtual async Task LoginUser([FromBody] AuthLoginBody body) { - if (!ModelState.IsValid) - return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))); - Models.db.User user = await repository.LoginUser(body); - return user == null ? Unauthorized() : Ok(new TokenDto { Token = jwt.GenerateJwt(user.Id) }); + User user = await repository.LoginUser(body); + return user == null ? Unauthorized() : Ok(new TokenDto(jwt.GenerateJwt(user.Id))); } /// @@ -100,17 +101,13 @@ namespace IO.Swagger.Controllers [HttpPost] [Route("/v1/api/auth/register")] [ValidateModelState] - [SwaggerOperation("RegisterUser")] [ProducesResponseType(typeof(TokenDto), 200)] - [ProducesResponseType(typeof(IEnumerable), 400)] + [ProducesResponseType(typeof(ModelStateDictionary), 400)] public async Task RegisterUser([FromBody] AuthRegisterBody body) { - if (!ModelState.IsValid) - return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))); - - Models.db.User user = await repository.RegisterUser(body); - return user == null ? StatusCode(409) : Ok(new TokenDto { Token = jwt.GenerateJwt(user.Id) }); + User user = await repository.RegisterUser(body); + return user == null ? StatusCode(409) : Ok(new TokenDto(jwt.GenerateJwt(user.Id))); } } } diff --git a/src/IO.Swagger/Controllers/CurrencyApi.cs b/src/IO.Swagger/Controllers/CurrencyApi.cs index 44bbbfa..2a53103 100644 --- a/src/IO.Swagger/Controllers/CurrencyApi.cs +++ b/src/IO.Swagger/Controllers/CurrencyApi.cs @@ -9,17 +9,18 @@ */ using AutoMapper; using IO.Swagger.Attributes; +using IO.Swagger.Models.db; using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.ResponseDto; using IO.Swagger.Repositories; using IO.Swagger.Security; +using IO.Swagger.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Swashbuckle.AspNetCore.Annotations; using System; using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; using System.Threading.Tasks; namespace IO.Swagger.Controllers @@ -59,7 +60,7 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpPost] [Route("/v1/api/currency/addAsset")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("AddDigitalAssetToCollection")] public virtual IActionResult AddDigitalAssetToCollection([FromBody] CurrencyAddAssetBody body) @@ -85,7 +86,7 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpPost] [Route("/v1/api/currency/createCollection")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("CreateAssetCollection")] public virtual IActionResult CreateAssetCollection([FromBody] CurrencyCreateCollectionBody body) @@ -112,19 +113,13 @@ namespace IO.Swagger.Controllers /// Unprocessable Content [HttpPost] [Route("/v1/api/currency/create")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("CreateCurrency")] - [ProducesResponseType(typeof(IEnumerable), 400)] + [ProducesResponseType(typeof(ModelStateDictionary), 400)] public virtual async Task CreateCurrency([FromBody] CurrencyCreateBody body) { - string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; - if (!int.TryParse(userIdString, out int userId)) - return Unauthorized(); - - if (!ModelState.IsValid) - return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))); - + int userId = (int) HttpContext.Items["userId"]; bool createdCurr = await repo.CreateCurrency(body, userId); return createdCurr ? StatusCode(201) : StatusCode(422); } @@ -139,18 +134,13 @@ namespace IO.Swagger.Controllers /// Conflict - User is not owner or currency does not exist [HttpPost] [Route("/v1/api/currency/mint")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("MintCurrency")] - [ProducesResponseType(typeof(IEnumerable), 400)] + [ProducesResponseType(typeof(ModelStateDictionary), 400)] public virtual async Task MintCurrency([FromBody] CurrencyMintBody body) { - string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; - if (!int.TryParse(userIdString, out int userId)) - return Unauthorized(); - if (!ModelState.IsValid) - return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))); - + int userId = (int) HttpContext.Items["userId"]; bool minted = await repo.MintCurrency(body, userId); return minted ? Ok() : StatusCode(409); } @@ -162,19 +152,17 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpGet] [Route("/v1/api/currency/getAll")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("GetAllCurrencies")] [ProducesResponseType(typeof(IEnumerable), 200)] public virtual async Task GetAllCurrencies() { - string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; - if (!int.TryParse(userIdString, out int userId)) - return Unauthorized(); + int userId = (int) HttpContext.Items["userId"]; - List rawCurrencies = await repo.GetAllCurrencies(); + List rawCurrencies = await repo.GetAllCurrencies(); List res = new(); - foreach (Models.db.Currency raw in rawCurrencies) + foreach (Currency raw in rawCurrencies) { CurrencyInfoDto c = mapper.Map(raw); c.IsOwner = raw.UserId == userId; diff --git a/src/IO.Swagger/Controllers/WalletApi.cs b/src/IO.Swagger/Controllers/WalletApi.cs index ebc4556..c31ec8c 100644 --- a/src/IO.Swagger/Controllers/WalletApi.cs +++ b/src/IO.Swagger/Controllers/WalletApi.cs @@ -9,17 +9,19 @@ */ using AutoMapper; using IO.Swagger.Attributes; +using IO.Swagger.Models.db; using IO.Swagger.Models.RequestDto; using IO.Swagger.Models.ResponseDto; using IO.Swagger.Repositories; using IO.Swagger.Security; +using IO.Swagger.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Swashbuckle.AspNetCore.Annotations; using System; using System.Collections.Generic; using System.Linq; -using System.Security.Claims; using System.Threading.Tasks; namespace IO.Swagger.Controllers @@ -56,17 +58,15 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpGet] [Route("/v1/api/wallet/balances")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("GetUserBalances")] [ProducesResponseType(typeof(IEnumerable), 200)] public virtual async Task GetUserBalances() { - string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; - if (!int.TryParse(userIdString, out int userId)) - return Unauthorized(); + int userId = (int) HttpContext.Items["userId"]; - List> balances = await transactionRepository.GetBalancesForUser(userId); + List> balances = await transactionRepository.GetBalancesForUser(userId); IEnumerable res = balances.Select(t => new WalletBalanceDto { Currency = mapper.Map(t.Item1), @@ -82,17 +82,14 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpGet] [Route("/v1/api/wallet/transactions")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("GetUserTransactions")] [ProducesResponseType(typeof(IEnumerable), 200)] public virtual async Task GetUserTransactions() { - string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; - if (!int.TryParse(userIdString, out int userId)) - return Unauthorized(); - - List transactions = await transactionRepository.GetTransactionsForUser(userId); + int userId = (int) HttpContext.Items["userId"]; + List transactions = await transactionRepository.GetTransactionsForUser(userId); return Ok(transactions.Select(mapper.Map)); } @@ -105,7 +102,7 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpPost] [Route("/v1/api/wallet/transferDigital")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("TransferDigitalAsset")] public virtual IActionResult TransferDigitalAsset([FromBody] WalletTransferDigitalBody body) @@ -131,19 +128,14 @@ namespace IO.Swagger.Controllers /// Unauthorized [HttpPost] [Route("/v1/api/wallet/transferPhysical")] - [Authorize(AuthenticationSchemes = BearerAuthenticationHandler.SchemeName)] + [Authorize(AuthenticationSchemes = JwtService.SchemeName)] [ValidateModelState] [SwaggerOperation("TransferPhysicalCurrency")] - [ProducesResponseType(typeof(IEnumerable), 400)] + [ProducesResponseType(typeof(ModelStateDictionary), 400)] [ProducesResponseType(typeof(TransactionReturnCode), 409)] public virtual async Task TransferPhysicalCurrency([FromBody] WalletTransferPhysicalBody body) { - string userIdString = HttpContext.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value; - if (!int.TryParse(userIdString, out int userId)) - return Unauthorized(); - if (!ModelState.IsValid) - return BadRequest(ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage))); - + int userId = (int) HttpContext.Items["userId"]; TransactionReturnCode transactionResult = await transactionRepository.TransferPhysical(body, userId); return transactionResult == TransactionReturnCode.Success ? Ok() : StatusCode(409, (int) transactionResult); } diff --git a/src/IO.Swagger/Filters/BasePathFilter.cs b/src/IO.Swagger/Filters/BasePathFilter.cs index 96f76da..6712113 100644 --- a/src/IO.Swagger/Filters/BasePathFilter.cs +++ b/src/IO.Swagger/Filters/BasePathFilter.cs @@ -1,5 +1,6 @@ using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; @@ -34,16 +35,16 @@ namespace IO.Swagger.Filters { swaggerDoc.Servers.Add(new OpenApiServer() { Url = BasePath }); - System.Collections.Generic.List> pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(BasePath)).ToList(); + List> pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(BasePath)).ToList(); - foreach (System.Collections.Generic.KeyValuePair path in pathsToModify) + foreach (KeyValuePair path in pathsToModify) { - if (path.Key.StartsWith(BasePath)) - { - string newKey = Regex.Replace(path.Key, $"^{BasePath}", string.Empty); - bool unused = swaggerDoc.Paths.Remove(path.Key); - swaggerDoc.Paths.Add(newKey, path.Value); - } + if (!path.Key.StartsWith(BasePath)) + continue; + + string newKey = Regex.Replace(path.Key, $"^{BasePath}", string.Empty); + _ = swaggerDoc.Paths.Remove(path.Key); + swaggerDoc.Paths.Add(newKey, path.Value); } } } diff --git a/src/IO.Swagger/Filters/GeneratePathParamsValidationFilter.cs b/src/IO.Swagger/Filters/GeneratePathParamsValidationFilter.cs index 664e589..05323b0 100644 --- a/src/IO.Swagger/Filters/GeneratePathParamsValidationFilter.cs +++ b/src/IO.Swagger/Filters/GeneratePathParamsValidationFilter.cs @@ -1,8 +1,11 @@ +using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; +using System.Reflection; namespace IO.Swagger.Filters { @@ -18,18 +21,18 @@ namespace IO.Swagger.Filters /// OperationFilterContext public void Apply(OpenApiOperation operation, OperationFilterContext context) { - System.Collections.Generic.IList pars = context.ApiDescription.ParameterDescriptions; + IList 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); - System.Collections.Generic.IEnumerable attributes = ((ControllerParameterDescriptor) par.ParameterDescriptor).ParameterInfo.CustomAttributes; + IEnumerable attributes = ((ControllerParameterDescriptor) par.ParameterDescriptor).ParameterInfo.CustomAttributes; if (attributes != null && attributes.Any() && swaggerParam != null) { // 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) { swaggerParam.Required = true; @@ -47,25 +50,25 @@ namespace IO.Swagger.Filters } // String Length [StringLength] - int? minLenght = null, maxLength = null; - System.Reflection.CustomAttributeData stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute)); + int? minLength = null, maxLength = null; + CustomAttributeData stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute)); if (stringLengthAttr != null) { 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; } - System.Reflection.CustomAttributeData minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute)); + CustomAttributeData minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute)); 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) { maxLength = (int) maxLengthAttr.ConstructorArguments[0].Value; @@ -73,12 +76,12 @@ namespace IO.Swagger.Filters if (swaggerParam is not null) { - swaggerParam.Schema.MinLength = minLenght; + swaggerParam.Schema.MinLength = minLength; swaggerParam.Schema.MaxLength = maxLength; } // 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) { int rangeMin = (int) rangeAttr.ConstructorArguments[0].Value; diff --git a/src/IO.Swagger/Migrations/20230813022042_Initial creation.cs b/src/IO.Swagger/Migrations/20230813022042_Initial creation.cs index e500277..5842618 100644 --- a/src/IO.Swagger/Migrations/20230813022042_Initial creation.cs +++ b/src/IO.Swagger/Migrations/20230813022042_Initial creation.cs @@ -8,7 +8,7 @@ namespace IO.Swagger.Migrations /// protected override void Up(MigrationBuilder migrationBuilder) { - var unused = migrationBuilder.CreateTable( + _ = migrationBuilder.CreateTable( name: "Users", columns: table => new { @@ -27,7 +27,7 @@ namespace IO.Swagger.Migrations /// protected override void Down(MigrationBuilder migrationBuilder) { - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused = migrationBuilder.DropTable( + _ = migrationBuilder.DropTable( name: "Users"); } } diff --git a/src/IO.Swagger/Migrations/20230813022424_Change user table.cs b/src/IO.Swagger/Migrations/20230813022424_Change user table.cs index b23e1de..e755c41 100644 --- a/src/IO.Swagger/Migrations/20230813022424_Change user table.cs +++ b/src/IO.Swagger/Migrations/20230813022424_Change user table.cs @@ -8,11 +8,11 @@ namespace IO.Swagger.Migrations /// protected override void Up(MigrationBuilder migrationBuilder) { - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused2 = migrationBuilder.DropColumn( + _ = migrationBuilder.DropColumn( name: "Username", table: "Users"); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder unused1 = migrationBuilder.AlterColumn( + _ = migrationBuilder.AlterColumn( name: "LastName", table: "Users", type: "nvarchar(32)", @@ -22,7 +22,7 @@ namespace IO.Swagger.Migrations oldType: "nvarchar(max)", oldNullable: true); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder unused = migrationBuilder.AlterColumn( + _ = migrationBuilder.AlterColumn( name: "FirstName", table: "Users", type: "nvarchar(32)", @@ -36,7 +36,7 @@ namespace IO.Swagger.Migrations /// protected override void Down(MigrationBuilder migrationBuilder) { - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder unused2 = migrationBuilder.AlterColumn( + _ = migrationBuilder.AlterColumn( name: "LastName", table: "Users", type: "nvarchar(max)", @@ -46,7 +46,7 @@ namespace IO.Swagger.Migrations oldMaxLength: 32, oldNullable: true); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.AlterOperationBuilder unused1 = migrationBuilder.AlterColumn( + _ = migrationBuilder.AlterColumn( name: "FirstName", table: "Users", type: "nvarchar(max)", @@ -56,7 +56,7 @@ namespace IO.Swagger.Migrations oldMaxLength: 32, oldNullable: true); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused = migrationBuilder.AddColumn( + _ = migrationBuilder.AddColumn( name: "Username", table: "Users", type: "nvarchar(max)", diff --git a/src/IO.Swagger/Migrations/20230819185130_Started transactions and currencies.cs b/src/IO.Swagger/Migrations/20230819185130_Started transactions and currencies.cs index c9edc20..53b8a0a 100644 --- a/src/IO.Swagger/Migrations/20230819185130_Started transactions and currencies.cs +++ b/src/IO.Swagger/Migrations/20230819185130_Started transactions and currencies.cs @@ -9,7 +9,7 @@ namespace IO.Swagger.Migrations /// protected override void Up(MigrationBuilder migrationBuilder) { - var unused11 = migrationBuilder.CreateTable( + _ = migrationBuilder.CreateTable( name: "Currencies", columns: table => new { @@ -21,15 +21,15 @@ namespace IO.Swagger.Migrations }, constraints: table => { - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused10 = table.PrimaryKey("PK_Currencies", x => x.CurrencyId); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused9 = table.ForeignKey( + _ = table.PrimaryKey("PK_Currencies", x => x.CurrencyId); + _ = table.ForeignKey( name: "FK_Currencies_Users_UserId", column: x => x.UserId, principalTable: "Users", principalColumn: "Id"); }); - var unused8 = migrationBuilder.CreateTable( + _ = migrationBuilder.CreateTable( name: "Transactions", columns: table => new { @@ -44,40 +44,40 @@ namespace IO.Swagger.Migrations }, constraints: table => { - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused7 = table.PrimaryKey("PK_Transactions", x => x.TransactionId); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused6 = table.ForeignKey( + _ = table.PrimaryKey("PK_Transactions", x => x.TransactionId); + _ = table.ForeignKey( name: "FK_Transactions_Currencies_CurrencyId", column: x => x.CurrencyId, principalTable: "Currencies", principalColumn: "CurrencyId"); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused5 = table.ForeignKey( + _ = table.ForeignKey( name: "FK_Transactions_Users_FromUserId", column: x => x.FromUserId, principalTable: "Users", principalColumn: "Id"); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused4 = table.ForeignKey( + _ = table.ForeignKey( name: "FK_Transactions_Users_ToUserId", column: x => x.ToUserId, principalTable: "Users", principalColumn: "Id"); }); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused3 = migrationBuilder.CreateIndex( + _ = migrationBuilder.CreateIndex( name: "IX_Currencies_UserId", table: "Currencies", column: "UserId"); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused2 = migrationBuilder.CreateIndex( + _ = migrationBuilder.CreateIndex( name: "IX_Transactions_CurrencyId", table: "Transactions", column: "CurrencyId"); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused1 = migrationBuilder.CreateIndex( + _ = migrationBuilder.CreateIndex( name: "IX_Transactions_FromUserId", table: "Transactions", column: "FromUserId"); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused = migrationBuilder.CreateIndex( + _ = migrationBuilder.CreateIndex( name: "IX_Transactions_ToUserId", table: "Transactions", column: "ToUserId"); @@ -86,10 +86,10 @@ namespace IO.Swagger.Migrations /// protected override void Down(MigrationBuilder migrationBuilder) { - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused1 = migrationBuilder.DropTable( + _ = migrationBuilder.DropTable( name: "Transactions"); - Microsoft.EntityFrameworkCore.Migrations.Operations.Builders.OperationBuilder unused = migrationBuilder.DropTable( + _ = migrationBuilder.DropTable( name: "Currencies"); } } diff --git a/src/IO.Swagger/Models/RequestDto/AuthLoginBody.cs b/src/IO.Swagger/Models/RequestDto/AuthLoginBody.cs index ab1d96f..a83d11a 100644 --- a/src/IO.Swagger/Models/RequestDto/AuthLoginBody.cs +++ b/src/IO.Swagger/Models/RequestDto/AuthLoginBody.cs @@ -9,13 +9,14 @@ */ using Newtonsoft.Json; using System; +using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using System.Text; namespace IO.Swagger.Models.RequestDto { /// - /// + /// The DTO used for logging into the service /// [DataContract] public partial class AuthLoginBody : IEquatable @@ -25,6 +26,8 @@ namespace IO.Swagger.Models.RequestDto /// [DataMember(Name = "email")] + [EmailAddress(ErrorMessage = "Invalid email format.")] + [Required] public string Email { get; set; } /// @@ -32,6 +35,8 @@ namespace IO.Swagger.Models.RequestDto /// [DataMember(Name = "password")] + [StringLength(32, MinimumLength = 8)] + [Required] public string Password { get; set; } /// @@ -40,11 +45,11 @@ namespace IO.Swagger.Models.RequestDto /// String presentation of the object public override string ToString() { - StringBuilder sb = new(); - StringBuilder unused3 = sb.Append("class AuthLoginBody {\n"); - StringBuilder unused2 = sb.Append(" Email: ").Append(Email).Append('\n'); - StringBuilder unused1 = sb.Append(" Password: ").Append(Password).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + StringBuilder sb = new StringBuilder() + .Append("class AuthLoginBody {\n") + .Append(" Email: ").Append(Email).Append('\n') + .Append(" Password: ").Append(Password).Append('\n') + .Append("}\n"); return sb.ToString(); } diff --git a/src/IO.Swagger/Models/RequestDto/AuthRegisterBody.cs b/src/IO.Swagger/Models/RequestDto/AuthRegisterBody.cs index b14f2f3..e19c5b2 100644 --- a/src/IO.Swagger/Models/RequestDto/AuthRegisterBody.cs +++ b/src/IO.Swagger/Models/RequestDto/AuthRegisterBody.cs @@ -16,7 +16,7 @@ using System.Text; namespace IO.Swagger.Models.RequestDto { /// - /// + /// The DTO used for registering with the service /// [DataContract] public partial class AuthRegisterBody : IEquatable @@ -24,7 +24,6 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets FirstName /// - [StringLength(32, MinimumLength = 3)] [DataMember(Name = "firstName")] [Required] @@ -33,7 +32,6 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets LastName /// - [StringLength(32, MinimumLength = 3)] [DataMember(Name = "lastName")] [Required] @@ -42,7 +40,6 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets Email /// - [DataMember(Name = "email")] [EmailAddress(ErrorMessage = "Invalid email format.")] [Required] @@ -64,12 +61,12 @@ namespace IO.Swagger.Models.RequestDto public override string ToString() { StringBuilder sb = new(); - StringBuilder unused5 = sb.Append("class AuthRegisterBody {\n"); - StringBuilder unused4 = sb.Append(" FirstName: ").Append(FirstName).Append('\n'); - StringBuilder unused3 = sb.Append(" LastName: ").Append(LastName).Append('\n'); - StringBuilder unused2 = sb.Append(" Email: ").Append(Email).Append('\n'); - StringBuilder unused1 = sb.Append(" Password: ").Append(Password).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + _ = sb.Append("class AuthRegisterBody {\n"); + _ = sb.Append(" FirstName: ").Append(FirstName).Append('\n'); + _ = sb.Append(" LastName: ").Append(LastName).Append('\n'); + _ = sb.Append(" Email: ").Append(Email).Append('\n'); + _ = sb.Append(" Password: ").Append(Password).Append('\n'); + _ = sb.Append("}\n"); return sb.ToString(); } diff --git a/src/IO.Swagger/Models/RequestDto/CurrencyAddAssetBody.cs b/src/IO.Swagger/Models/RequestDto/CurrencyAddAssetBody.cs index 7470eed..2f12e66 100644 --- a/src/IO.Swagger/Models/RequestDto/CurrencyAddAssetBody.cs +++ b/src/IO.Swagger/Models/RequestDto/CurrencyAddAssetBody.cs @@ -16,7 +16,7 @@ using System.Text; namespace IO.Swagger.Models.RequestDto { /// - /// + /// The DTO used for creating an NFT /// [DataContract] public partial class CurrencyAddAssetBody : IEquatable @@ -24,16 +24,16 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets CollectionId /// - [DataMember(Name = "collectionId")] - public int? CollectionId { get; set; } + [Required] + public int CollectionId { get; set; } /// /// Gets or Sets AssetName /// - [StringLength(32, MinimumLength = 1)] [DataMember(Name = "assetName")] + [Required] public string AssetName { get; set; } /// @@ -41,6 +41,7 @@ namespace IO.Swagger.Models.RequestDto /// [RegularExpression("/^(https?|ftp)://[^\\s/$.?#].[^\\s]*$/")] [DataMember(Name = "assetLink")] + [Required] public string AssetLink { get; set; } /// @@ -49,12 +50,12 @@ namespace IO.Swagger.Models.RequestDto /// String presentation of the object public override string ToString() { - StringBuilder sb = new(); - StringBuilder unused4 = sb.Append("class CurrencyAddAssetBody {\n"); - StringBuilder unused3 = sb.Append(" CollectionId: ").Append(CollectionId).Append('\n'); - StringBuilder unused2 = sb.Append(" AssetName: ").Append(AssetName).Append('\n'); - StringBuilder unused1 = sb.Append(" AssetLink: ").Append(AssetLink).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + StringBuilder sb = new StringBuilder() + .Append("class CurrencyAddAssetBody {\n") + .Append(" CollectionId: ").Append(CollectionId).Append('\n') + .Append(" AssetName: ").Append(AssetName).Append('\n') + .Append(" AssetLink: ").Append(AssetLink).Append('\n') + .Append("}\n"); return sb.ToString(); } @@ -85,11 +86,10 @@ namespace IO.Swagger.Models.RequestDto public bool Equals(CurrencyAddAssetBody other) { return other is not null -&& (ReferenceEquals(this, other) -|| (( + && (ReferenceEquals(this, other) + || (( CollectionId == other.CollectionId || - (CollectionId != null && - CollectionId.Equals(other.CollectionId)) + CollectionId.Equals(other.CollectionId) ) && ( AssetName == other.AssetName || @@ -113,8 +113,7 @@ namespace IO.Swagger.Models.RequestDto { int hashCode = 41; // Suitable nullity checks etc, of course :) - if (CollectionId != null) - hashCode = (hashCode * 59) + CollectionId.GetHashCode(); + hashCode = (hashCode * 59) + CollectionId.GetHashCode(); if (AssetName != null) hashCode = (hashCode * 59) + AssetName.GetHashCode(); if (AssetLink != null) diff --git a/src/IO.Swagger/Models/RequestDto/CurrencyCreateBody.cs b/src/IO.Swagger/Models/RequestDto/CurrencyCreateBody.cs index 692c2d7..527da81 100644 --- a/src/IO.Swagger/Models/RequestDto/CurrencyCreateBody.cs +++ b/src/IO.Swagger/Models/RequestDto/CurrencyCreateBody.cs @@ -16,7 +16,7 @@ using System.Text; namespace IO.Swagger.Models.RequestDto { /// - /// + /// The DTO used for creating a currency /// [DataContract] public partial class CurrencyCreateBody : IEquatable @@ -24,7 +24,6 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets Name /// - [StringLength(32, MinimumLength = 1)] [DataMember(Name = "name")] public string Name { get; set; } @@ -32,7 +31,6 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets Symbol /// - [StringLength(4, MinimumLength = 1)] [DataMember(Name = "symbol")] public string Symbol { get; set; } @@ -43,11 +41,11 @@ namespace IO.Swagger.Models.RequestDto /// String presentation of the object public override string ToString() { - StringBuilder sb = new(); - StringBuilder unused3 = sb.Append("class CurrencyCreateBody {\n"); - StringBuilder unused2 = sb.Append(" Name: ").Append(Name).Append('\n'); - StringBuilder unused1 = sb.Append(" Symbol: ").Append(Symbol).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + StringBuilder sb = new StringBuilder() + .Append("class CurrencyCreateBody {\n") + .Append(" Name: ").Append(Name).Append('\n') + .Append(" Symbol: ").Append(Symbol).Append('\n') + .Append("}\n"); return sb.ToString(); } @@ -78,8 +76,8 @@ namespace IO.Swagger.Models.RequestDto public bool Equals(CurrencyCreateBody other) { return other is not null -&& (ReferenceEquals(this, other) -|| (( + && (ReferenceEquals(this, other) + || (( Name == other.Name || (Name != null && Name.Equals(other.Name)) diff --git a/src/IO.Swagger/Models/RequestDto/CurrencyCreateCollectionBody.cs b/src/IO.Swagger/Models/RequestDto/CurrencyCreateCollectionBody.cs index e9bc807..33fd424 100644 --- a/src/IO.Swagger/Models/RequestDto/CurrencyCreateCollectionBody.cs +++ b/src/IO.Swagger/Models/RequestDto/CurrencyCreateCollectionBody.cs @@ -9,13 +9,14 @@ */ using Newtonsoft.Json; using System; +using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using System.Text; namespace IO.Swagger.Models.RequestDto { /// - /// + /// The DTO used for creating an NFT collection /// [DataContract] public partial class CurrencyCreateCollectionBody : IEquatable @@ -23,8 +24,9 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets CollectionName /// - [DataMember(Name = "collectionName")] + [Required] + [StringLength(32, MinimumLength = 4)] public string CollectionName { get; set; } /// @@ -33,10 +35,10 @@ namespace IO.Swagger.Models.RequestDto /// String presentation of the object public override string ToString() { - StringBuilder sb = new(); - StringBuilder unused2 = sb.Append("class CurrencyCreateCollectionBody {\n"); - StringBuilder unused1 = sb.Append(" CollectionName: ").Append(CollectionName).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + StringBuilder sb = new StringBuilder() + .Append("class CurrencyCreateCollectionBody {\n") + .Append(" CollectionName: ").Append(CollectionName).Append('\n') + .Append("}\n"); return sb.ToString(); } @@ -67,8 +69,8 @@ namespace IO.Swagger.Models.RequestDto public bool Equals(CurrencyCreateCollectionBody other) { return other is not null -&& (ReferenceEquals(this, other) -|| CollectionName == other.CollectionName || + && (ReferenceEquals(this, other) + || CollectionName == other.CollectionName || (CollectionName != null && CollectionName.Equals(other.CollectionName))); } @@ -82,7 +84,6 @@ namespace IO.Swagger.Models.RequestDto unchecked // Overflow is fine, just wrap { int hashCode = 41; - // Suitable nullity checks etc, of course :) if (CollectionName != null) hashCode = (hashCode * 59) + CollectionName.GetHashCode(); return hashCode; diff --git a/src/IO.Swagger/Models/RequestDto/CurrencyMintBody.cs b/src/IO.Swagger/Models/RequestDto/CurrencyMintBody.cs index 6c4971f..36a8d6e 100644 --- a/src/IO.Swagger/Models/RequestDto/CurrencyMintBody.cs +++ b/src/IO.Swagger/Models/RequestDto/CurrencyMintBody.cs @@ -16,7 +16,7 @@ using System.Text; namespace IO.Swagger.Models.RequestDto { /// - /// + /// The DTO for minting an existing currency /// [DataContract] public partial class CurrencyMintBody : IEquatable @@ -24,7 +24,6 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets CurrencyId /// - [DataMember(Name = "currencyId")] [Required] public int CurrencyId { get; set; } @@ -32,9 +31,9 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets Amount /// - [Required] [DataMember(Name = "amount")] + [Range(0.1, float.MaxValue, ErrorMessage = "Please enter a valid amount to mint")] public float Amount { get; set; } /// @@ -43,11 +42,11 @@ namespace IO.Swagger.Models.RequestDto /// String presentation of the object public override string ToString() { - StringBuilder sb = new(); - StringBuilder unused3 = sb.Append("class CurrencyMintBody {\n"); - StringBuilder unused2 = sb.Append(" CurrencyId: ").Append(CurrencyId).Append('\n'); - StringBuilder unused1 = sb.Append(" Amount: ").Append(Amount).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + StringBuilder sb = new StringBuilder() + .Append("class CurrencyMintBody {\n") + .Append(" CurrencyId: ").Append(CurrencyId).Append('\n') + .Append(" Amount: ").Append(Amount).Append('\n') + .Append("}\n"); return sb.ToString(); } @@ -78,8 +77,8 @@ namespace IO.Swagger.Models.RequestDto public bool Equals(CurrencyMintBody other) { return other is not null -&& (ReferenceEquals(this, other) -|| (( + && (ReferenceEquals(this, other) + || (( CurrencyId == other.CurrencyId || CurrencyId.Equals(other.CurrencyId) ) && diff --git a/src/IO.Swagger/Models/RequestDto/WalletTransferDigitalBody.cs b/src/IO.Swagger/Models/RequestDto/WalletTransferDigitalBody.cs index a11fd92..e6e8aaf 100644 --- a/src/IO.Swagger/Models/RequestDto/WalletTransferDigitalBody.cs +++ b/src/IO.Swagger/Models/RequestDto/WalletTransferDigitalBody.cs @@ -9,6 +9,7 @@ */ using Newtonsoft.Json; using System; +using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using System.Text; @@ -23,16 +24,15 @@ namespace IO.Swagger.Models.RequestDto /// /// Gets or Sets Email /// - [DataMember(Name = "email")] + [EmailAddress] public string Email { get; set; } /// /// Gets or Sets AssetId /// - [DataMember(Name = "assetId")] - public int? AssetId { get; set; } + public int AssetId { get; set; } /// /// Returns the string presentation of the object @@ -40,11 +40,11 @@ namespace IO.Swagger.Models.RequestDto /// String presentation of the object public override string ToString() { - StringBuilder sb = new(); - StringBuilder unused3 = sb.Append("class WalletTransferDigitalBody {\n"); - StringBuilder unused2 = sb.Append(" Email: ").Append(Email).Append('\n'); - StringBuilder unused1 = sb.Append(" AssetId: ").Append(AssetId).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + StringBuilder sb = new StringBuilder() + .Append("class WalletTransferDigitalBody {\n") + .Append(" Email: ").Append(Email).Append('\n') + .Append(" AssetId: ").Append(AssetId).Append('\n') + .Append("}\n"); return sb.ToString(); } @@ -75,16 +75,15 @@ namespace IO.Swagger.Models.RequestDto public bool Equals(WalletTransferDigitalBody other) { return other is not null -&& (ReferenceEquals(this, other) -|| (( + && (ReferenceEquals(this, other) + || (( Email == other.Email || (Email != null && Email.Equals(other.Email)) ) && ( AssetId == other.AssetId || - (AssetId != null && - AssetId.Equals(other.AssetId)) + AssetId.Equals(other.AssetId) ))); } @@ -97,11 +96,9 @@ namespace IO.Swagger.Models.RequestDto unchecked // Overflow is fine, just wrap { int hashCode = 41; - // Suitable nullity checks etc, of course :) if (Email != null) hashCode = (hashCode * 59) + Email.GetHashCode(); - if (AssetId != null) - hashCode = (hashCode * 59) + AssetId.GetHashCode(); + hashCode = (hashCode * 59) + AssetId.GetHashCode(); return hashCode; } } diff --git a/src/IO.Swagger/Models/RequestDto/WalletTransferPhysicalBody.cs b/src/IO.Swagger/Models/RequestDto/WalletTransferPhysicalBody.cs index 872d52e..e4d1628 100644 --- a/src/IO.Swagger/Models/RequestDto/WalletTransferPhysicalBody.cs +++ b/src/IO.Swagger/Models/RequestDto/WalletTransferPhysicalBody.cs @@ -59,12 +59,12 @@ namespace IO.Swagger.Models.RequestDto /// String presentation of the object public override string ToString() { - StringBuilder sb = new(); - StringBuilder unused4 = sb.Append("class WalletTransferPhysicalBody {\n"); - StringBuilder unused3 = sb.Append(" DestUserEmail: ").Append(DestUserEmail).Append('\n'); - StringBuilder unused2 = sb.Append(" Amount: ").Append(Amount).Append('\n'); - StringBuilder unused1 = sb.Append(" CurrencyId: ").Append(CurrencyId).Append('\n'); - StringBuilder unused = sb.Append("}\n"); + StringBuilder sb = new StringBuilder() + .Append("class WalletTransferPhysicalBody {\n") + .Append(" DestUserEmail: ").Append(DestUserEmail).Append('\n') + .Append(" Amount: ").Append(Amount).Append('\n') + .Append(" CurrencyId: ").Append(CurrencyId).Append('\n') + .Append("}\n"); return sb.ToString(); } diff --git a/src/IO.Swagger/Models/ResponseDto/TokenDto.cs b/src/IO.Swagger/Models/ResponseDto/TokenDto.cs index 893e044..2da04f7 100644 --- a/src/IO.Swagger/Models/ResponseDto/TokenDto.cs +++ b/src/IO.Swagger/Models/ResponseDto/TokenDto.cs @@ -1,10 +1,22 @@ -namespace IO.Swagger.Models.ResponseDto +using System; + +namespace IO.Swagger.Models.ResponseDto { /// /// The DTO returned when a JWT is requested /// public class TokenDto { + /// + /// Initializes a new instance of the class. + /// + /// The token. + /// token + public TokenDto(string token) + { + Token = token ?? throw new ArgumentNullException(nameof(token)); + } + /// /// Gets or sets the valid JWT that can be used for accessing other API routes. /// diff --git a/src/IO.Swagger/Models/ResponseDto/UserDto.cs b/src/IO.Swagger/Models/ResponseDto/UserDto.cs index 4189554..db373c4 100644 --- a/src/IO.Swagger/Models/ResponseDto/UserDto.cs +++ b/src/IO.Swagger/Models/ResponseDto/UserDto.cs @@ -1,4 +1,7 @@ -namespace IO.Swagger.Models.ResponseDto +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace IO.Swagger.Models.ResponseDto { /// /// The dto for returning user information @@ -11,6 +14,9 @@ /// /// The email. /// + [DataMember(Name = "email")] + [EmailAddress(ErrorMessage = "Invalid email format.")] + [Required] public string Email { get; set; } /// /// Gets or sets the first name of the user. @@ -18,6 +24,9 @@ /// /// The first name. /// + [StringLength(32, MinimumLength = 3)] + [DataMember(Name = "firstName")] + [Required] public string FirstName { get; set; } /// /// Gets or sets the last name of the user. @@ -25,6 +34,9 @@ /// /// The last name. /// + [StringLength(32, MinimumLength = 3)] + [DataMember(Name = "lastName")] + [Required] public string LastName { get; set; } } } diff --git a/src/IO.Swagger/Repositories/CurrencyRepository.cs b/src/IO.Swagger/Repositories/CurrencyRepository.cs index e4d9f08..2fe21a3 100644 --- a/src/IO.Swagger/Repositories/CurrencyRepository.cs +++ b/src/IO.Swagger/Repositories/CurrencyRepository.cs @@ -2,6 +2,7 @@ using IO.Swagger.Models.RequestDto; using IO.Swagger.Services; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using System; using System.Collections.Generic; 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())) return false; - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry unused = await context.Currencies.AddAsync(new Currency + _ = await context.Currencies.AddAsync(new Currency { Name = request.Name, Symbol = request.Symbol, @@ -57,7 +58,7 @@ namespace IO.Swagger.Repositories if (!existsAndIsOwner) return false; - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry unused = await context.Transactions.AddAsync(new Transaction + _ = await context.Transactions.AddAsync(new Transaction { Amount = request.Amount, CurrencyId = request.CurrencyId, diff --git a/src/IO.Swagger/Repositories/TransactionRepository.cs b/src/IO.Swagger/Repositories/TransactionRepository.cs index a296840..551bc84 100644 --- a/src/IO.Swagger/Repositories/TransactionRepository.cs +++ b/src/IO.Swagger/Repositories/TransactionRepository.cs @@ -2,6 +2,7 @@ using IO.Swagger.Models.RequestDto; using IO.Swagger.Services; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using System; using System.Collections.Generic; using System.Linq; @@ -12,7 +13,7 @@ namespace IO.Swagger.Repositories /// /// The EF implementation of this interface /// - /// + /// public class TransactionRepository : ITransactionRepository { private readonly BankDbContext context; @@ -20,7 +21,7 @@ namespace IO.Swagger.Repositories /// Initializes a new instance of the class. /// /// The context. - /// context + /// context public TransactionRepository(BankDbContext context) { this.context = context ?? throw new ArgumentNullException(nameof(context)); @@ -77,7 +78,7 @@ namespace IO.Swagger.Repositories if (balance == null || balance.Item2 < request.Amount) return TransactionReturnCode.InsufficientFunds; - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry unused = await context.Transactions.AddAsync(new Transaction + _ = await context.Transactions.AddAsync(new Transaction { Amount = request.Amount, CurrencyId = request.CurrencyId, diff --git a/src/IO.Swagger/Repositories/UserRepository.cs b/src/IO.Swagger/Repositories/UserRepository.cs index eed92ee..0a80d5f 100644 --- a/src/IO.Swagger/Repositories/UserRepository.cs +++ b/src/IO.Swagger/Repositories/UserRepository.cs @@ -2,8 +2,10 @@ using IO.Swagger.Models.RequestDto; using IO.Swagger.Services; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; using System; using System.Security.Cryptography; +using System.Text; using System.Threading.Tasks; namespace IO.Swagger.Repositories @@ -11,7 +13,7 @@ namespace IO.Swagger.Repositories /// /// The EF implementation of this interface /// - /// + /// public class UserRepository : IUserRepository { private readonly BankDbContext bankDbContext; @@ -35,13 +37,8 @@ namespace IO.Swagger.Repositories // Generate a random salt byte[] saltBytes = RandomNumberGenerator.GetBytes(16); string salt = Convert.ToBase64String(saltBytes); - // Hash the password along with the salt - string password = request.Password; - string saltedPassword = password + salt; - byte[] passwordBytes = System.Text.Encoding.UTF8.GetBytes(saltedPassword); - byte[] hashedBytes = SHA256.HashData(passwordBytes); - string hashedPassword = Convert.ToBase64String(hashedBytes); + string hashedPassword = HashPassword(salt, request.Password); // Create and insert the user User newUser = new() @@ -53,8 +50,8 @@ namespace IO.Swagger.Repositories LastName = request.LastName }; - Microsoft.EntityFrameworkCore.ChangeTracking.EntityEntry unused1 = await bankDbContext.Users.AddAsync(newUser); - int unused = await bankDbContext.SaveChangesAsync(); + _ = await bankDbContext.Users.AddAsync(newUser); + _ = await bankDbContext.SaveChangesAsync(); return newUser; } @@ -66,12 +63,7 @@ namespace IO.Swagger.Repositories if (user == null) return null; - // Hash the supplied password with the retrieved salt - 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); + string hashedPassword = HashPassword(user.Salt, request.Password); return hashedPassword != user.PasswordHash ? null : user; } @@ -80,5 +72,20 @@ namespace IO.Swagger.Repositories { return await bankDbContext.Users.FirstOrDefaultAsync(u => u.Id == userId); } + + /// + /// Hashes the password. + /// + /// The salt to apply. + /// The password to hash. + /// The hashed and salted password + 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; + } } } diff --git a/src/IO.Swagger/Security/BearerAuthenticationHandler.cs b/src/IO.Swagger/Security/BearerAuthenticationHandler.cs index 522db77..cbaee12 100644 --- a/src/IO.Swagger/Security/BearerAuthenticationHandler.cs +++ b/src/IO.Swagger/Security/BearerAuthenticationHandler.cs @@ -1,3 +1,4 @@ +using IO.Swagger.Services; using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -17,20 +18,12 @@ namespace IO.Swagger.Security /// public class BearerAuthenticationHandler : AuthenticationHandler { - //TODO: Clean this up and use the service for it - private readonly string secretKey; - private readonly byte[] secretBytes; - - /// - /// scheme name for authentication handler. - /// - public const string SchemeName = "Bearer"; + private readonly JwtService jwtService; /// - public BearerAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) + public BearerAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, JwtService jwtService) : base(options, logger, encoder, clock) { - secretKey = Environment.GetEnvironmentVariable("JWT_SECRET_KEY"); - secretBytes = Encoding.UTF8.GetBytes(secretKey); + this.jwtService = jwtService ?? throw new ArgumentNullException(nameof(jwtService)); } /// @@ -38,53 +31,9 @@ namespace IO.Swagger.Security /// protected override Task HandleAuthenticateAsync() { - return Task.Run(() => - { - if (!Request.Headers.ContainsKey("Authorization")) - { - 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"); - }); + return Task.Run(() => Request.Headers.ContainsKey("Authorization") + ? jwtService.ValidateJwt(Request, Scheme.Name) + : AuthenticateResult.Fail("Missing Authorization Header")); } } } diff --git a/src/IO.Swagger/Services/BankDbContext.cs b/src/IO.Swagger/Services/BankDbContext.cs index aa4932c..39b5ff3 100644 --- a/src/IO.Swagger/Services/BankDbContext.cs +++ b/src/IO.Swagger/Services/BankDbContext.cs @@ -1,12 +1,13 @@ using IO.Swagger.Models.db; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace IO.Swagger.Services { /// /// The EF DbContext that owns all connections and interactions /// - /// + /// public class BankDbContext : DbContext { /// @@ -42,7 +43,7 @@ namespace IO.Swagger.Services base.OnModelCreating(modelBuilder); // currency -> user FK - Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder unused3 = modelBuilder.Entity() + _ = modelBuilder.Entity() .HasMany(u => u.Currencies) .WithOne(c => c.User) .HasForeignKey(c => c.UserId) @@ -50,21 +51,21 @@ namespace IO.Swagger.Services .OnDelete(DeleteBehavior.NoAction); // transaction -> from user - Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder unused2 = modelBuilder.Entity() + _ = modelBuilder.Entity() .HasMany(u => u.TransactionsFrom) .WithOne(t => t.FromUser) .HasForeignKey(t => t.FromUserId) .HasPrincipalKey(u => u.Id) .OnDelete(DeleteBehavior.NoAction); // transaction -> to user - Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder unused1 = modelBuilder.Entity() + _ = modelBuilder.Entity() .HasMany(u => u.TransactionsTo) .WithOne(t => t.ToUser) .HasForeignKey(t => t.ToUserId) .HasPrincipalKey(u => u.Id) .OnDelete(DeleteBehavior.NoAction); // transaction -> currency - Microsoft.EntityFrameworkCore.Metadata.Builders.ReferenceCollectionBuilder unused = modelBuilder.Entity() + _ = modelBuilder.Entity() .HasOne(t => t.Currency) .WithMany(c => c.Transactions) .HasForeignKey(t => t.CurrencyId) diff --git a/src/IO.Swagger/Services/JwtService.cs b/src/IO.Swagger/Services/JwtService.cs index c0955b5..db59431 100644 --- a/src/IO.Swagger/Services/JwtService.cs +++ b/src/IO.Swagger/Services/JwtService.cs @@ -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.IdentityModel.Tokens.Jwt; +using System.Net.Http.Headers; using System.Security.Claims; using System.Text; @@ -14,6 +18,11 @@ namespace IO.Swagger.Services private readonly string secretKey; private readonly byte[] secretBytes; + /// + /// The scheme name for authorization headers + /// + public const string SchemeName = "Bearer"; + /// /// Initializes a new instance of the class. /// @@ -32,8 +41,8 @@ namespace IO.Swagger.Services { Claim[] claims = new[] { - new Claim(ClaimTypes.NameIdentifier, userId.ToString()) - }; + new Claim(ClaimTypes.NameIdentifier, userId.ToString()) + }; JwtSecurityTokenHandler tokenHandler = new(); SecurityTokenDescriptor tokenDescriptor = new() @@ -46,5 +55,46 @@ namespace IO.Swagger.Services SecurityToken token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } + + /// + /// Validates the JWT. + /// + /// The request. + /// Name of the scheme. + /// The result of authenticating the JWT + 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"); + } } } diff --git a/src/IO.Swagger/Services/MapperProfile.cs b/src/IO.Swagger/Services/MapperProfile.cs index 2c9fbed..fb902c9 100644 --- a/src/IO.Swagger/Services/MapperProfile.cs +++ b/src/IO.Swagger/Services/MapperProfile.cs @@ -16,13 +16,13 @@ namespace IO.Swagger.Services /// public MapperProfile() { - IMappingExpression unused3 = CreateMap(); - IMappingExpression unused2 = CreateMap(); - IMappingExpression unused1 = CreateMap(); + _ = CreateMap(); + _ = CreateMap(); + _ = CreateMap(); - IMappingExpression unused = CreateMap().ForMember(ci => ci.AmountInCirculation, + _ = CreateMap().ForMember(ci => ci.AmountInCirculation, 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)); } } diff --git a/src/IO.Swagger/Startup.cs b/src/IO.Swagger/Startup.cs index 01aa17c..d74fd13 100644 --- a/src/IO.Swagger/Startup.cs +++ b/src/IO.Swagger/Startup.cs @@ -49,8 +49,7 @@ namespace IO.Swagger public void ConfigureServices(IServiceCollection services) { // Add framework services. - IMvcBuilder unused11 = services - .AddMvc(options => + _ = services.AddMvc(options => { options.InputFormatters.RemoveType(); options.OutputFormatters.RemoveType(); @@ -62,11 +61,10 @@ namespace IO.Swagger }) .AddXmlSerializerFormatters(); - AuthenticationBuilder unused10 = services.AddAuthentication(BearerAuthenticationHandler.SchemeName) - .AddScheme(BearerAuthenticationHandler.SchemeName, null); + _ = services.AddAuthentication(JwtService.SchemeName) + .AddScheme(JwtService.SchemeName, null); - IServiceCollection unused9 = services - .AddSwaggerGen(c => + _ = services.AddSwaggerGen(c => { c.SwaggerDoc("1.0.0", new OpenApiInfo { @@ -118,30 +116,26 @@ namespace IO.Swagger MapperConfiguration mapperConfig = new(mc => mc.AddProfile(new MapperProfile())); // 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") .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 string connectionString = Environment.GetEnvironmentVariable("DATABASE_CONNECTION_STRING"); - if (string.IsNullOrEmpty(connectionString)) - { throw new Exception("Database connection string not found in environment variable."); - } // DI setup - IServiceCollection unused5 = services.AddScoped(); - IServiceCollection unused4 = services.AddScoped(); - IServiceCollection unused3 = services.AddScoped(); - IServiceCollection unused2 = services.AddDbContext(x => x.UseSqlServer(connectionString: connectionString)); - IServiceCollection unused1 = services.AddSingleton(); - IMapper mapper = mapperConfig.CreateMapper(); - IServiceCollection unused = services.AddSingleton(mapper); + _ = services.AddScoped(); + _ = services.AddScoped(); + _ = services.AddScoped(); + _ = services.AddDbContext(x => x.UseSqlServer(connectionString)); + _ = services.AddSingleton(); + _ = services.AddSingleton(mapperConfig.CreateMapper()); } /// @@ -153,32 +147,30 @@ namespace IO.Swagger public void Configure(IApplicationBuilder app, IWebHostEnvironment env, BankDbContext context) { 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(); - IApplicationBuilder unused4 = app.UseSwaggerUI(c => - //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")); + _ = app.UseSwagger(); + _ = app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/1.0.0/swagger.json", "T&J Central Bank API")); //TODO: Use Https Redirection // app.UseHttpsRedirection(); - IApplicationBuilder unused3 = app.UseEndpoints(endpoints => endpoints.MapControllers()); + _ = app.UseEndpoints(endpoints => endpoints.MapControllers()); if (env.IsDevelopment()) { - IApplicationBuilder unused2 = app.UseDeveloperExceptionPage(); + _ = app.UseDeveloperExceptionPage(); } else { //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(); } } }