Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Build and run unit tests

env:
DOTNET_VERSION: '9.x'
DOTNET_VERSION: '10.x'

on:
push:
Expand All @@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6

- name: Set up .NET Core
uses: actions/setup-dotnet@v5
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Release CI/CD
env:
AZURE_WEBAPP_NAME: app-rdmg
AZURE_WEBAPP_PACKAGE_PATH: '.'
DOTNET_VERSION: '9.x'
DOTNET_VERSION: '10.x'

on:
push:
Expand All @@ -18,7 +18,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6

- name: Set up .NET Core
uses: actions/setup-dotnet@v5
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>true</ImplicitUsings>
<Nullable>enable</Nullable>
Expand Down
25 changes: 12 additions & 13 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,23 @@
<PackageVersion Include="LigerShark.WebOptimizer.Core" Version="3.0.477" />
<PackageVersion Include="Mapster" Version="7.4.0" />
<PackageVersion Include="Mapster.DependencyInjection" Version="1.0.1" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.10" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SQLite" Version="9.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.10" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="9.0.10" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.0" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SQLite" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="10.0.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="Microsoft.Web.LibraryManager.Build" Version="3.0.71" />
<PackageVersion Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageVersion Include="Serilog.Settings.Configuration" Version="9.0.0" />
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
<PackageVersion Include="Serilog.Sinks.MSSqlServer" Version="9.0.1" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
<PackageVersion Include="System.Text.Json" Version="9.0.10" />
<PackageVersion Include="Serilog.Sinks.MSSqlServer" Version="9.0.2" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.15.0" />
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="xunit.v3" Version="3.1.0" />
<PackageVersion Include="xunit.v3" Version="3.2.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

I just wanted to see how is .NET under Linux so i ported my app to ASP.NET Core + Entity Framework Core.

You will need the .NET 9.0 SDK to build/run this project (simply run dotnet build/run in the terminal).
You will need the .NET 10.0 SDK to build/run this project (simply run dotnet build/run in the terminal).

## Usage

Expand Down
27 changes: 15 additions & 12 deletions src/RDMG.Core/Helpers/PasswordHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,34 @@ namespace RDMG.Core.Helpers;

public static class PasswordHelper
{
private const int Iterations = 10000;
private const int HashLength = 20;
private const int SaltLength = 16;
private static readonly HashAlgorithmName HashAlgorithmName = HashAlgorithmName.SHA512;

public static string EncryptPassword(string password)
{
using var randomNumberGenerator = RandomNumberGenerator.Create();
var salt = new byte[16];
var salt = new byte[SaltLength];
randomNumberGenerator.GetBytes(salt);
using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA512);
var hash = pbkdf2.GetBytes(20);
var hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
var hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, HashAlgorithmName, HashLength);
var hashBytes = new byte[SaltLength + HashLength];
Array.Copy(salt, 0, hashBytes, 0, SaltLength);
Array.Copy(hash, 0, hashBytes, SaltLength, HashLength);
return Convert.ToBase64String(hashBytes);
}

public static bool CheckPassword(string savedPasswordHash, string password)
{
var result = true;
var hashBytes = Convert.FromBase64String(savedPasswordHash);
var salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
using var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA512);
var hash = pbkdf2.GetBytes(20);
var salt = new byte[SaltLength];
Array.Copy(hashBytes, 0, salt, 0, SaltLength);
var hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, HashAlgorithmName, HashLength);

for (var i = 0; i < 20; i++)
for (var i = 0; i < HashLength; i++)
{
if (hashBytes[i + 16] == hash[i])
if (hashBytes[i + SaltLength] == hash[i])
continue;
result = false;
break;
Expand Down
1 change: 0 additions & 1 deletion src/RDMG.Core/RDMG.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<PackageReference Include="Mapster"/>
<PackageReference Include="Mapster.DependencyInjection"/>
<PackageReference Include="Microsoft.EntityFrameworkCore"/>
<PackageReference Include="System.Text.Json"/>
<PackageReference Include="Serilog.AspNetCore"/>
<PackageReference Include="Serilog.Settings.Configuration"/>
<PackageReference Include="Serilog.Sinks.File"/>
Expand Down
9 changes: 5 additions & 4 deletions src/RDMG.Web/Controllers/Web/DungeonController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.Text.Json;
using RDMG.Core.Abstractions.Services.Exceptions;
using RDMG.Resources;
using RDMG.Web.Extensions;

namespace RDMG.Web.Controllers.Web;

Expand Down Expand Up @@ -68,7 +69,7 @@ public async Task<IActionResult> Delete(int id, CancellationToken cancellationTo
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting dungeon.");
this.HandleException(ex, _logger, "Error deleting dungeon.");
}

return RedirectToAction("Index");
Expand Down Expand Up @@ -107,7 +108,7 @@ await _dungeonService.RenameDungeonAsync(model.Id, model.UserId, model.NewDungeo
}
catch (Exception ex)
{
_logger.LogError(ex, "Error renaming dungeon.");
this.HandleException(ex, _logger, "Error renaming dungeon.");
}

return View(model);
Expand All @@ -123,7 +124,7 @@ public async Task<IActionResult> DeleteOption(int id, CancellationToken cancella
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting dungeon option.");
this.HandleException(ex, _logger, "Error deleting dungeon option.");
}

return RedirectToAction("Index");
Expand Down Expand Up @@ -166,7 +167,7 @@ public async Task<IActionResult> Create(DungeonOptionCreateViewModel model, Canc
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating dungeon.");
this.HandleException(ex, _logger, "Error creating dungeon.");
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/RDMG.Web/Controllers/Web/ProfileController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Microsoft.AspNetCore.Mvc;
using RDMG.Core.Abstractions.Services;
using RDMG.Core.Abstractions.Services.Models;
using RDMG.Web.Extensions;
using RDMG.Web.Models.Profile;

namespace RDMG.Web.Controllers.Web;
Expand Down Expand Up @@ -44,8 +45,7 @@ public async Task<IActionResult> ChangePassword(ProfileChangePasswordModel model
}
catch (Exception ex)
{
_logger.LogError(ex, "Error changing password.");
ModelState.AddModelError("", ex.Message);
this.HandleException(ex, _logger, "Error changing password.");
}
}
return View(model);
Expand Down
15 changes: 9 additions & 6 deletions src/RDMG.Web/Controllers/Web/UserController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using RDMG.Core.Abstractions.Services;
using RDMG.Core.Abstractions.Services.Models;
using RDMG.Core.Domain;
using RDMG.Web.Extensions;
using RDMG.Web.Models.User;

namespace RDMG.Web.Controllers.Web;
Expand Down Expand Up @@ -44,10 +45,10 @@ public async Task<IActionResult> Create(UserCreateViewModel model)
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating user.");
ModelState.AddModelError("", ex.Message);
this.HandleException(ex, _logger, "Error creating user.");
}
}

return View(model);
}

Expand All @@ -73,10 +74,10 @@ public async Task<IActionResult> Edit(UserEditViewModel model)
}
catch (Exception ex)
{
_logger.LogError(ex, "Error editing user.");
ModelState.AddModelError("", ex.Message);
this.HandleException(ex, _logger, "Error editing user.");
}
}

return View(model);
}

Expand All @@ -90,8 +91,9 @@ public async Task<IActionResult> Delete(int id)
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting user.");
this.HandleException(ex, _logger, "Error deleting user.");
}

return RedirectToAction("Index");
}

Expand All @@ -105,8 +107,9 @@ public async Task<IActionResult> Restore(int id)
}
catch (Exception ex)
{
_logger.LogError(ex, "Error restoring user.");
this.HandleException(ex, _logger, "Error restoring user.");
}

return RedirectToAction("Index");
}
}
4 changes: 2 additions & 2 deletions src/RDMG.Web/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /app
COPY . ./

RUN dotnet restore ./src/RDMG.Web/RDMG.Web.csproj
RUN dotnet publish "src/RDMG.Web/RDMG.Web.csproj" -c Release -o out

FROM mcr.microsoft.com/dotnet/aspnet:9.0
FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app/out ./

Expand Down
33 changes: 33 additions & 0 deletions src/RDMG.Web/Extensions/ControllerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using RDMG.Core.Abstractions.Services.Exceptions;

namespace RDMG.Web.Extensions;

public static class ControllerExtensions
{
public static void HandleException(this Controller controller, Exception ex, ILogger logger,
string? defaultError = null)
{
switch (ex)
{
case ServiceAggregateException ae:
{
foreach (var exception in ae.GetInnerExceptions())
{
controller.ModelState.AddModelError(string.Empty, exception.Message);
}

break;
}
case ServiceException e:
controller.ModelState.AddModelError(string.Empty, e.Message);
break;
default:
logger.LogError(ex, "{GetDisplayUrl}: {DefaultError}", controller.Request.GetDisplayUrl(),
defaultError ?? ServiceException.GeneralError);
controller.ModelState.AddModelError(string.Empty, defaultError ?? ServiceException.GeneralError);
break;
}
}
}