diff --git a/Azaion.Api/Azaion.Api.csproj b/Azaion.Api/Azaion.Api.csproj index adde894..9880e00 100644 --- a/Azaion.Api/Azaion.Api.csproj +++ b/Azaion.Api/Azaion.Api.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable Linux @@ -9,14 +9,13 @@ - - + - + diff --git a/Azaion.Api/Program.cs b/Azaion.Api/Program.cs index 0b9e0e3..fe24899 100644 --- a/Azaion.Api/Program.cs +++ b/Azaion.Api/Program.cs @@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Rewrite; using Microsoft.IdentityModel.Tokens; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Serilog; Log.Logger = new LoggerConfiguration() @@ -79,19 +79,13 @@ builder.Services.AddSwaggerGen(c => In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Description = "Put **_ONLY_** your JWT Bearer token on textbox below!", - - Reference = new OpenApiReference - { - Id = JwtBearerDefaults.AuthenticationScheme, - Type = ReferenceType.SecurityScheme - } }; - c.AddSecurityDefinition(jwtSecurityScheme.Reference.Id, jwtSecurityScheme); + c.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, jwtSecurityScheme); - c.AddSecurityRequirement(new OpenApiSecurityRequirement + c.AddSecurityRequirement(_ => new OpenApiSecurityRequirement { - { jwtSecurityScheme, Array.Empty() } + { new OpenApiSecuritySchemeReference(JwtBearerDefaults.AuthenticationScheme, null), new List() } }); }); builder.Services.Configure(builder.Configuration.GetSection(nameof(ResourcesConfig))); @@ -142,75 +136,75 @@ app.MapPost("/login", var user = await userService.ValidateUser(request, ct: cancellationToken); return Results.Ok(new { Token = authService.CreateToken(user)}); }) - .WithOpenApi(op => new(op){ Summary = "Login"});; + .WithSummary("Login"); app.MapPost("/users", async (RegisterUserRequest registerUserRequest, IUserService userService, CancellationToken cancellationToken) => await userService.RegisterUser(registerUserRequest, cancellationToken)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new(op){ Summary = "Creates a new user"}); + .WithSummary("Creates a new user"); app.MapGet("/users/current", async (IAuthService authService) => await authService.GetCurrentUser()) .RequireAuthorization() - .WithOpenApi(op => new(op){ Summary = "Get Current User"}); + .WithSummary("Get Current User"); app.MapGet("/users", async (string? searchEmail, RoleEnum? searchRole, IUserService userService, CancellationToken ct) => await userService.GetUsers(searchEmail, searchRole, ct)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new(op){ Summary = "List users by criteria"}); + .WithSummary("List users by criteria"); app.MapPut("/users/hardware/set", async ([FromBody]SetHWRequest request, IUserService userService, ICache cache, CancellationToken ct) => await userService.UpdateHardware(request.Email, request.Hardware, ct: ct)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new OpenApiOperation(op){ Summary = "Sets user's hardware"}); + .WithSummary("Sets user's hardware"); app.MapPut("/users/queue-offsets/set", async ([FromBody]SetUserQueueOffsetsRequest request, IUserService userService, CancellationToken ct) => await userService.UpdateQueueOffsets(request.Email, request.Offsets, ct)) .RequireAuthorization() - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Sets user's queue offsets" }); + .WithSummary("Sets user's queue offsets"); app.MapPut("/users/{email}/set-role/{role}", async (string email, RoleEnum role, IUserService userService, CancellationToken ct) => await userService.ChangeRole(email, role, ct)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Set user's role" }); + .WithSummary("Set user's role"); app.MapPut("/users/{email}/enable", async (string email, IUserService userService, CancellationToken ct) => await userService.SetEnableStatus(email, true, ct)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Disable user" }); + .WithSummary("Enable user"); app.MapPut("/users/{email}/disable", async (string email, IUserService userService, CancellationToken ct) => await userService.SetEnableStatus(email, false, ct)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Disable user" }); + .WithSummary("Disable user"); app.MapDelete("/users/{email}", async (string email, IUserService userService, CancellationToken ct) => await userService.RemoveUser(email, ct)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Remove user" }); + .WithSummary("Remove user"); app.MapPost("/resources/{dataFolder?}", async ([FromRoute]string? dataFolder, IFormFile data, IResourcesService resourceService, CancellationToken ct) => await resourceService.SaveResource(dataFolder, data, ct)) .Accepts("multipart/form-data") .RequireAuthorization() - //.WithOpenApi(op => new(op){ Summary = "Upload resource"}); //For some reason doesn't work when this is specified. + .WithSummary("Upload resource") .DisableAntiforgery(); app.MapGet("/resources/list/{dataFolder?}", async ([FromRoute]string? dataFolder, string? search, IResourcesService resourcesService, CancellationToken ct) => await resourcesService.ListResources(dataFolder, search, ct)) .RequireAuthorization() - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Lists resources in folder" }); + .WithSummary("Lists resources in folder"); app.MapPost("/resources/clear/{dataFolder?}", ([FromRoute]string? dataFolder, IResourcesService resourcesService) => resourcesService.ClearFolder(dataFolder)) .RequireAuthorization(apiAdminPolicy) - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Clear folder" }); + .WithSummary("Clear folder"); app.MapPost("/resources/get/{dataFolder?}", //Need to have POST method for secure password async ([FromBody]GetResourceRequest request, [FromRoute]string? dataFolder, IAuthService authService, @@ -227,7 +221,7 @@ app.MapPost("/resources/get/{dataFolder?}", //Need to have POST method for secur return Results.File(stream, "application/octet-stream", request.FileName); }).RequireAuthorization() - .WithOpenApi(op => new OpenApiOperation(op){ Summary = "Gets encrypted by users Password and HardwareHash resources. POST method for secure password"}); + .WithSummary("Gets encrypted by users Password and HardwareHash resources. POST method for secure password"); app.MapGet("/resources/get-installer", async (IAuthService authService, IResourcesService resourcesService, CancellationToken ct) => @@ -240,7 +234,7 @@ app.MapGet("/resources/get-installer", throw new FileNotFoundException("Installer file was not found!"); return Results.File(stream, "application/octet-stream", name); }).RequireAuthorization() - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Gets latest installer" }); + .WithSummary("Gets latest installer"); app.MapGet("/resources/get-installer/stage", async (IAuthService authService, IResourcesService resourcesService, CancellationToken ct) => @@ -253,7 +247,7 @@ app.MapGet("/resources/get-installer/stage", throw new FileNotFoundException("Installer file was not found!"); return Results.File(stream, "application/octet-stream", name); }).RequireAuthorization() - .WithOpenApi(op => new OpenApiOperation(op) { Summary = "Gets latest installer" }); + .WithSummary("Gets latest installer"); app.MapPost("/resources/check", diff --git a/Azaion.Common/Azaion.Common.csproj b/Azaion.Common/Azaion.Common.csproj index b6648be..5659ec8 100644 --- a/Azaion.Common/Azaion.Common.csproj +++ b/Azaion.Common/Azaion.Common.csproj @@ -1,7 +1,7 @@ - + - net8.0 + net10.0 enable enable @@ -9,15 +9,12 @@ - - + - - C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.Extensions.Options.dll - + diff --git a/Azaion.Services/Azaion.Services.csproj b/Azaion.Services/Azaion.Services.csproj index 31a44f7..d8d6d85 100644 --- a/Azaion.Services/Azaion.Services.csproj +++ b/Azaion.Services/Azaion.Services.csproj @@ -1,7 +1,7 @@ - + - net8.0 + net10.0 enable enable @@ -11,18 +11,11 @@ - - C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.AspNetCore.Http.Abstractions.dll - - - - C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\8.0.8\Microsoft.Extensions.Options.dll - + - diff --git a/Azaion.Test/Azaion.Test.csproj b/Azaion.Test/Azaion.Test.csproj index 2d78392..9e6d737 100644 --- a/Azaion.Test/Azaion.Test.csproj +++ b/Azaion.Test/Azaion.Test.csproj @@ -1,7 +1,7 @@ - + - net8.0 + net10.0 enable enable diff --git a/Dockerfile b/Dockerfile index 3f0a8bc..9374898 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base WORKDIR /app EXPOSE 8080 # Build whole app -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /app COPY . . diff --git a/env/api/02-nginx-docker-registry-tunnel.sh b/env/api/02-nginx-docker-registry-tunnel.sh new file mode 100644 index 0000000..2c0c230 --- /dev/null +++ b/env/api/02-nginx-docker-registry-tunnel.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +apt install -y docker.io apache2-utils nginx + +# install cloudflared +curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb +dpkg -i cloudflared.deb +rm cloudflared.deb + +docker run -d -p 5000:5000 --name registry --restart always registry:latest + +cd /etc/nginx +mkdir -p auth +cd auth +htpasswd -c .htpasswd zxsanny +chmod 640 .htpasswd +chown root:www-data .htpasswd + +cd /etc/nginx/sites-available +tee docker-registry << 'END' +server { + listen 80; + server_name _; + client_max_body_size 900M; + + location / { + auth_basic "Registry"; + auth_basic_user_file /etc/nginx/auth/.htpasswd; + proxy_pass http://localhost:5000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +END +ln -sf /etc/nginx/sites-available/docker-registry /etc/nginx/sites-enabled/ +rm -f /etc/nginx/sites-enabled/default + +nginx -t +systemctl restart nginx + +# start tunnel — prints a *.trycloudflare.com URL +cloudflared tunnel --url http://localhost:80 + +# then from another machine: +# docker login +# enter username: zxsanny and the password set above