Skip to content

Commit

Permalink
Publish trimmed into docker image, use noble-chiseled base image, min…
Browse files Browse the repository at this point in the history
…or refactoring
  • Loading branch information
aannenko committed Jun 27, 2024
1 parent 4028350 commit 0877cb1
Show file tree
Hide file tree
Showing 16 changed files with 144 additions and 91 deletions.
4 changes: 3 additions & 1 deletion src/.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.http
**/*.jfm
**/azds.yaml
**/bin
Expand All @@ -19,10 +20,11 @@
**/node_modules
**/npm-debug.log
**/obj
**/Properties
**/README.md
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
Expand Down
8 changes: 8 additions & 0 deletions src/CrackSharp.Api/Common/AppJsonSerializerContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Text.Json.Serialization;

namespace CrackSharp.Api.Common;

[JsonSerializable(typeof(HttpValidationProblemDetails))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}
3 changes: 1 addition & 2 deletions src/CrackSharp.Api/Common/Services/AwaitableMemoryCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ public Task<TValue> AwaitValueAsync(TKey key, CancellationToken cancellationToke
awaiter.Task.ContinueWith(task => awaiters.TryRemove(key, out _), TaskScheduler.Default);
return new(awaiter, taskCompletionSource);
}),
_awaiters)
.Value;
_awaiters).Value;

if (TryGetValue(key, out value))
taskCompletionSource.TrySetResult(value);
Expand Down
6 changes: 4 additions & 2 deletions src/CrackSharp.Api/CrackSharp.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest</AnalysisLevel>
<InvariantGlobalization>true</InvariantGlobalization>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\CrackSharp.Core\CrackSharp.Core.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.12" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
</ItemGroup>

</Project>
66 changes: 61 additions & 5 deletions src/CrackSharp.Api/CrackSharp.Api.http
Original file line number Diff line number Diff line change
@@ -1,17 +1,73 @@
@CrackSharp.Api_HostAddress = https://localhost:5001
@CrackSharp_Api_HostAddress = http://localhost:5000

GET {{CrackSharp.Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2
GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2

### 200 "LOL"

GET {{CrackSharp.Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?chars=LMNO&maxTextLength=4
GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?chars=LMNO&maxTextLength=4

### 200 "LOL"

GET {{CrackSharp.Api_HostAddress}}/api/v1/des/encrypt/abc
GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?chars=LMNO

### 200 "LOL"

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?maxTextLength=4

### 200 "LOL"

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/encrypt/abc

### 200 DES hash based on random salt

GET {{CrackSharp.Api_HostAddress}}/api/v1/des/encrypt/abc?salt=50
GET {{CrackSharp_Api_HostAddress}}/api/v1/des/encrypt/abc?salt=50

### 200 "50PaJ4.RO0YUo"



GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt

### 400 "Required parameter "string hash" was not provided from route or query string."

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ

### 400 "hash": [ "Value cannot be null or empty and must follow pattern ^[./0-9A-Za-z]{13}$" ]

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?maxTextLength=9

### 400 "maxTextLength": [ "Value must be greater than 0 and less than 9." ]

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?chars=-_

### 400 "chars": [ "Value cannot be null or empty and must follow pattern ^[./0-9A-Za-z]+$" ]

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ?maxTextLength=9&chars=-_

### 400 Multiple error messages for parameters

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/encrypt

### 400 Required parameter "string text" was not provided from route or query string.

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/encrypt/-_

### 400 "text": [ "Value cannot be null or empty and must follow pattern ^[./0-9A-Za-z]+$" ]

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/encrypt/abc?salt=_

### 400 "salt": [ "Value must follow pattern ^[./0-9A-Za-z]{2}$" ]

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/encrypt/abc?salt=def

### 400 "salt": [ "Value must follow pattern ^[./0-9A-Za-z]{2}$" ]



GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?maxTextLength=2

### 404 Not Found

GET {{CrackSharp_Api_HostAddress}}/api/v1/des/decrypt/FAzlTwVAZ1NZ2?chars=L

### 404 Not Found
16 changes: 9 additions & 7 deletions src/CrackSharp.Api/Des/Endpoints/DesApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using CrackSharp.Api.Des.Endpoints.Filters;
using CrackSharp.Core;
using Microsoft.AspNetCore.Http.HttpResults;
using System.ComponentModel.DataAnnotations;

namespace CrackSharp.Api.Des.Endpoints;

Expand All @@ -23,21 +24,22 @@ public static IEndpointRouteBuilder MapDesApi(this IEndpointRouteBuilder app)
}

private static async Task<Results<Ok<string>, NotFound, StatusCodeHttpResult>> Decrypt(
[AsParameters] DesDecryptRequest request,
[AsParameters] DesDecryptServices services,
CancellationToken cancellationToken)
[RegularExpression("^[./0-9A-Za-z]{13}$")] string hash,
[Range(1, 8)] int maxTextLength = 8,
[RegularExpression("^[./0-9A-Za-z]+$")] string chars = DesConstants.DecryptDefaultChars,
CancellationToken cancellationToken = default)
{
var decryptionService = services.DecryptionService;
var logger = services.Logger;
var (hash, maxTextLength, chars) = request;

const string partialMessage = $"Decryption of the {nameof(hash)} '{{{nameof(hash)}}}' " +
$"with {nameof(maxTextLength)} {{{nameof(maxTextLength)}}} and {nameof(chars)} '{{{nameof(chars)}}}'";

try
{
logger.LogInformation($"{partialMessage} requested.", hash, maxTextLength, chars);
var decrypted = await decryptionService.DecryptAsync(request, cancellationToken);
var decrypted = await decryptionService.DecryptAsync(new(hash, maxTextLength, chars) , cancellationToken);
logger.LogInformation($"{partialMessage} succeeded.", hash, maxTextLength, chars);

return TypedResults.Ok(decrypted);
Expand All @@ -60,12 +62,12 @@ private static async Task<Results<Ok<string>, NotFound, StatusCodeHttpResult>> D
}

private static Ok<string> Encrypt(
[AsParameters] DesEncryptRequest request,
[AsParameters] DesEncryptServices services)
[AsParameters] DesEncryptServices services,
[RegularExpression("^[./0-9A-Za-z]+$")] string text,
[RegularExpression("^[./0-9A-Za-z]{2}$")] string? salt = null)
{
var encryptionService = services.EncryptionService;
var logger = services.Logger;
var (text, salt) = request;

const string partialMessage = $"Encryption of the {nameof(text)} '{{{nameof(text)}}}' " +
$"with {nameof(salt)} '{{{nameof(salt)}}}'";
Expand Down
19 changes: 11 additions & 8 deletions src/CrackSharp.Api/Des/Endpoints/Filters/DesValidationFilters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ internal static class DesValidationFilters
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
var request = context.GetArgument<DesDecryptRequest>(0);
request = request with { Hash = WebUtility.UrlDecode(request.Hash) };
context.Arguments[0] = request;
var hash = context.GetArgument<string>(1);
var maxTextLength = context.GetArgument<int>(2);
var chars = context.GetArgument<string>(3);

hash = WebUtility.UrlDecode(hash);
context.Arguments[1] = hash;

var (hash, maxTextLength, chars) = request;
Dictionary<string, string[]>? errors = null;

if (hash is null || !_hashValidator.IsMatch(hash))
Expand All @@ -49,11 +51,12 @@ internal static class DesValidationFilters
EndpointFilterInvocationContext context,
EndpointFilterDelegate next)
{
var request = context.GetArgument<DesEncryptRequest>(0);
request = request with { Text = WebUtility.UrlDecode(request.Text) };
context.Arguments[0] = request;
var text = context.GetArgument<string>(1);
var salt = context.GetArgument<string>(2);

text = WebUtility.UrlDecode(text);
context.Arguments[1] = text;

var (text, salt) = request;
Dictionary<string, string[]>? errors = null;

if (text is null || !_charsValidator.IsMatch(text))
Expand Down
10 changes: 4 additions & 6 deletions src/CrackSharp.Api/Des/Model/DesDecryptRequest.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using System.ComponentModel.DataAnnotations;

namespace CrackSharp.Api.Des.Model;
namespace CrackSharp.Api.Des.Model;

public readonly record struct DesDecryptRequest(
[RegularExpression("^[./0-9A-Za-z]{13}$")] string Hash,
[Range(1, 8)] int MaxTextLength = 8,
[RegularExpression("^[./0-9A-Za-z]+$")] string Chars = DesConstants.DecryptDefaultChars);
string Hash,
int MaxTextLength = 8,
string Chars = DesConstants.DecryptDefaultChars);
3 changes: 3 additions & 0 deletions src/CrackSharp.Api/Des/Model/DesDecryptServices.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using CrackSharp.Api.Des.Services;
using Microsoft.AspNetCore.Mvc;

namespace CrackSharp.Api.Des.Model;

public readonly struct DesDecryptServices
{
[FromServices]
public required DesBruteForceDecryptionService DecryptionService { get; init; }

[FromServices]
public required ILogger<DesDecryptServices> Logger { get; init; }
}
8 changes: 3 additions & 5 deletions src/CrackSharp.Api/Des/Model/DesEncryptRequest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using System.ComponentModel.DataAnnotations;

namespace CrackSharp.Api.Des.Model;
namespace CrackSharp.Api.Des.Model;

public readonly record struct DesEncryptRequest(
[RegularExpression("^[./0-9A-Za-z]+$")] string Text,
[RegularExpression("^[./0-9A-Za-z]{2}$")] string? Salt = null);
string Text,
string? Salt = null);
3 changes: 3 additions & 0 deletions src/CrackSharp.Api/Des/Model/DesEncryptServices.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using CrackSharp.Api.Des.Services;
using Microsoft.AspNetCore.Mvc;

namespace CrackSharp.Api.Des.Model;

public readonly struct DesEncryptServices
{
[FromServices]
public required DesEncryptionService EncryptionService { get; init; }

[FromServices]
public required ILogger<DesEncryptServices> Logger { get; init; }
}
19 changes: 6 additions & 13 deletions src/CrackSharp.Api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
# Use SDK image
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build
ARG TARGETARCH
ARG BINARY_VERSION
WORKDIR /source

# Copy csproj and restore as distinct layers
COPY CrackSharp.Core/*.csproj CrackSharp.Core/
COPY CrackSharp.Api/*.csproj CrackSharp.Api/
RUN dotnet restore CrackSharp.Api -a $TARGETARCH

# Copy everything and build the app
# Copy everything and publish the app
COPY CrackSharp.Core/. CrackSharp.Core/
COPY CrackSharp.Api/. CrackSharp.Api/
ARG BINARY_VERSION
RUN (echo "$BINARY_VERSION" | grep -Eq "^[0-9]+\.[0-9]+\.[0-9]+(-[a-z0-9.]+)?$") && \
dotnet publish CrackSharp.Api --no-restore -a $TARGETARCH -o /app -p:Version=$BINARY_VERSION || \
dotnet publish CrackSharp.Api --no-restore -a $TARGETARCH -o /app
dotnet publish CrackSharp.Api -a $TARGETARCH -o /app -p:Version=$BINARY_VERSION || \
dotnet publish CrackSharp.Api -a $TARGETARCH -o /app

# Use runtime image
FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-noble-chiseled
WORKDIR /app

# Copy build results and run the app
COPY --from=build /app .
USER $APP_UID
ENTRYPOINT ["./CrackSharp.Api"]
17 changes: 12 additions & 5 deletions src/CrackSharp.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@
using CrackSharp.Api.Common.Services;
using CrackSharp.Api.Des.Endpoints;
using CrackSharp.Api.Des.Services;
using Microsoft.AspNetCore.Routing.Constraints;
using Swashbuckle.AspNetCore.SwaggerGen;

var builder = WebApplication.CreateBuilder(args);
var builder = WebApplication.CreateSlimBuilder(args);

builder.Services.ConfigureHttpJsonOptions(
options => options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default));

builder.Services.Configure<RouteOptions>(
options => options.SetParameterPolicy<RegexInlineRouteConstraint>("regex"));

builder.Services.AddSingleton<ISerializerDataContractResolver, JsonSerializerDataContractResolver>(
_ => new(new() { TypeInfoResolver = AppJsonSerializerContext.Default }));

// Add services to the container.
builder.Services.AddMemoryCache(options => options.SizeLimit = builder.Configuration.GetCacheSizeLimit());
builder.Services.AddSingleton(typeof(AwaitableMemoryCache<,>));
builder.Services.AddSingleton<DesBruteForceDecryptionService>();
Expand All @@ -17,15 +27,12 @@

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.MapDesApi();

app.Run();
23 changes: 4 additions & 19 deletions src/CrackSharp.Api/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:55053",
"sslPort": 44367
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"CrackSharp.Api": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
}
Loading

0 comments on commit 0877cb1

Please sign in to comment.