Move the server to own directory, commit old changes

This commit is contained in:
Saphire 2024-07-19 01:04:45 +06:00
parent e7d9e56d24
commit c82196745a
Signed by: Saphire
GPG Key ID: B26EB7A1F07044C4
22 changed files with 154 additions and 34 deletions

View File

@ -1,9 +1,9 @@
namespace Lunar.Exchange.Amalgam.Auth;
namespace Lunar.Exchange.Amalgam.Server.Auth;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text.Encodings.Web;
using Lunar.Exchange.Amalgam.Models;
using Lunar.Exchange.Amalgam.Server.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
@ -39,8 +39,8 @@ public class GithubHookAuthenticationHandler : AuthenticationHandler<Authenticat
return Task.FromResult(AuthenticateResult.Fail("Invalid header format"));
var claims = new[] {
new Claim(ClaimTypes.Hash, headers[0][7..])
};
new Claim(ClaimTypes.Hash, headers[0][7..])
};
var claimsIdentity = new ClaimsIdentity(claims, GithubHookAuthorizationHandler.POLICY_NAME);
var ticket = new AuthenticationTicket(new ClaimsPrincipal(claimsIdentity), Scheme.Name);

View File

@ -1,4 +1,4 @@
namespace Lunar.Exchange.Amalgam.Controllers;
namespace Lunar.Exchange.Amalgam.Server.Controllers;
using Models;
using Utilities;
@ -6,6 +6,8 @@ using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography;
using Microsoft.Extensions.Options;
using System.Text.Json;
using System.Text;
using Lunar.Exchange.Amalgam.Server.Data;
[ApiController]
[Route("deployment")]
@ -15,29 +17,43 @@ public class DeploymentController : ControllerBase
public static readonly int MAX_SIZE = 50 * 1024 * 1024; // 50 MB
private readonly ILogger<DeploymentController> Logger;
private readonly AmalgamOptions Options;
private readonly AmalgamContext DbContext;
public DeploymentController(ILogger<DeploymentController> logger, IOptions<AmalgamOptions> options)
public DeploymentController(
ILogger<DeploymentController> logger,
IOptions<AmalgamOptions> options,
AmalgamContext dbContext
)
{
Logger = logger;
Options = options.Value;
DbContext = dbContext;
}
[HttpPost("push")]
// TODO: authorize properly- move that into a filter/etc?
public async Task<IActionResult> PushArtifact([FromHeader(Name = "X-Amalgam-Header")] string clientHeader, IFormFile artifact)
public async Task<IActionResult> PushArtifact([FromHeader(Name = "X-Amalgam-Push-Header")] string clientHeader, IFormFile artifact)
{
var headerBytes = Convert.FromBase64String(clientHeader);
var segmented = clientHeader.Split(" ");
if (!Guid.TryParseExact(segmented[0], "D", out var sourceId))
return Unauthorized(new { Error = "Invalid header" });
var source = DbContext.ArtifactSources.SingleOrDefault(e => e.Guid == sourceId);
if (source is null)
return Unauthorized(new { Error = "Unknown client" });
var headerBytes = Convert.FromBase64String(segmented[1]);
var plaintextHeaderBytes = new byte[headerBytes.Length - 28];
var key = Convert.FromBase64String(Options.SharedSecret);
using (var chacha = new ChaCha20Poly1305(key)) {
using (var chacha = new ChaCha20Poly1305(source.SharedSecret)) {
try {
chacha.Decrypt(
nonce: headerBytes[..12],
tag: headerBytes[12..28],
ciphertext: headerBytes[28..],
plaintext :plaintextHeaderBytes
plaintext: plaintextHeaderBytes
);
}
catch (CryptographicException e)
@ -56,7 +72,7 @@ public class DeploymentController : ControllerBase
if (timespan.TotalSeconds > TIME_INTERVAL)
return Unauthorized(new { Error = "Expired proof" });
Logger.LogInformation("Received a valid file push from {}", "TODO");
Logger.LogInformation("Received a valid file push from {}", sourceId);
if (header.FileSize > MAX_SIZE)
return StatusCode(
@ -84,13 +100,14 @@ public class DeploymentController : ControllerBase
nonce: encrypted[..12],
tag: encrypted[12..28],
ciphertext: encrypted[28..],
plaintext: plaintextBytes
plaintext: plaintextBytes,
associatedData: headerBytes
);
};
var filePath = Path.GetTempFileName();
Logger.LogInformation("Writing received file to {} (orig: {})", filePath, artifact.FileName);
Logger.LogInformation("Writing received file to {} (orig: {})", filePath, header.FileName);
using var stream = System.IO.File.Create(filePath);
await stream.WriteAsync(plaintextBytes);

View File

@ -0,0 +1,25 @@
namespace Lunar.Exchange.Amalgam.Server.Controllers;
using Models;
using Utilities;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("project")]
public class ProjectController : ControllerBase
{
private readonly ILogger<ProjectController> Logger;
public ProjectController(ILogger<ProjectController> logger)
{
Logger = logger;
}
[HttpPost("{id}/push")]
// TODO: authorize properly
public async Task<IActionResult> PushArtifact(Guid id)
{
await Console.Out.WriteLineAsync($"Artifact pushed for GUID:{id}");
return Ok("Ping ok!");
}
}

View File

@ -1,9 +1,9 @@
namespace Lunar.Exchange.Amalgam.Controllers;
namespace Lunar.Exchange.Amalgam.Server.Controllers;
using Models;
using Utilities;
using Microsoft.AspNetCore.Mvc;
using Lunar.Exchange.Amalgam.Auth;
using Lunar.Exchange.Amalgam.Server.Auth;
[ApiController]
[GithubHookAuthorize]

View File

@ -1,12 +1,13 @@
namespace Lunar.Exchange.Amalgam.Data;
namespace Lunar.Exchange.Amalgam.Server.Data;
using System.Reflection;
using Lunar.Exchange.Amalgam.Data.Models;
using Lunar.Exchange.Amalgam.Server.Data.Models;
using Microsoft.EntityFrameworkCore;
public class AmalgamContext : DbContext
{
public DbSet<Project> Projects { get; set; } = null!;
public DbSet<ArtifactSource> ArtifactSources { get; set; } = null!;
public AmalgamContext(DbContextOptions<AmalgamContext> options) : base(options) {}

View File

@ -1,5 +1,5 @@
// <auto-generated />
using Lunar.Exchange.Amalgam.Data;
using Lunar.Exchange.Amalgam.Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@ -7,7 +7,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Lunar.Exchange.Amalgam.Data.Migrations
namespace Lunar.Exchange.Amalgam.Server.Data.Migrations
{
[DbContext(typeof(AmalgamContext))]
[Migration("20220424202349_Initial")]
@ -18,7 +18,7 @@ namespace Lunar.Exchange.Amalgam.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.4");
modelBuilder.Entity("Lunar.Exchange.Amalgam.Data.Models.Project", b =>
modelBuilder.Entity("Lunar.Exchange.Amalgam.Server.Data.Models.Project", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()

View File

@ -2,7 +2,7 @@
#nullable disable
namespace Lunar.Exchange.Amalgam.Data.Migrations
namespace Lunar.Exchange.Amalgam.Server.Data.Migrations
{
public partial class Initial : Migration
{

View File

@ -1,12 +1,12 @@
// <auto-generated />
using Lunar.Exchange.Amalgam.Data;
using Lunar.Exchange.Amalgam.Server.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Lunar.Exchange.Amalgam.Data.Migrations
namespace Lunar.Exchange.Amalgam.Server.Data.Migrations
{
[DbContext(typeof(AmalgamContext))]
partial class AmalgamContextModelSnapshot : ModelSnapshot
@ -16,7 +16,7 @@ namespace Lunar.Exchange.Amalgam.Data.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.4");
modelBuilder.Entity("Lunar.Exchange.Amalgam.Data.Models.Project", b =>
modelBuilder.Entity("Lunar.Exchange.Amalgam.Server.Data.Models.Project", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()

View File

@ -0,0 +1,6 @@
namespace Lunar.Exchange.Amalgam.Server.Data.Models;
public class Artifact
{
public int Id { get; set; }
}

View File

@ -0,0 +1,20 @@
namespace Lunar.Exchange.Amalgam.Server.Data.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class ArtifactSource
{
public int Id { get; set; }
public Guid Guid { get; set; }
// Probably should be stored in a better way but right now host compromise IS the DB compromise...
public byte[] SharedSecret { get; set; } = null!;
public void Configure(EntityTypeBuilder<ArtifactSource> builder)
{
builder.Property(e => e.SharedSecret)
.IsRequired()
.HasMaxLength(32)
.IsFixedLength();
}
}

View File

@ -1,4 +1,4 @@
namespace Lunar.Exchange.Amalgam.Data.Models;
namespace Lunar.Exchange.Amalgam.Server.Data.Models;
public class Project
{

View File

@ -1,4 +1,4 @@
namespace Lunar.Exchange.Amalgam.Models;
namespace Lunar.Exchange.Amalgam.Server.Models;
public class AmalgamOptions
{

View File

@ -1,4 +1,4 @@
namespace Lunar.Exchange.Amalgam.Models;
namespace Lunar.Exchange.Amalgam.Server.Models;
using System.Text.Json.Serialization;
using Utilities;

View File

@ -1,7 +1,8 @@
namespace Lunar.Exchange.Amalgam.Models;
namespace Lunar.Exchange.Amalgam.Server.Models;
public class ClientHeaderModel
{
public DateTime Timestamp { get; set; }
public long FileSize { get; set; }
public string FileName { get; set; } = null!;
}

View File

@ -1,6 +1,6 @@
using Lunar.Exchange.Amalgam.Data;
using Lunar.Exchange.Amalgam.Auth;
using Lunar.Exchange.Amalgam.Models;
using Lunar.Exchange.Amalgam.Server.Data;
using Lunar.Exchange.Amalgam.Server.Auth;
using Lunar.Exchange.Amalgam.Server.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
@ -53,7 +53,6 @@ var app = builder.Build();
await context.Database.MigrateAsync();
}
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{

View File

@ -1,4 +1,4 @@
namespace Lunar.Exchange.Amalgam.Utilities;
namespace Lunar.Exchange.Amalgam.Server.Utilities;
using System;
using Microsoft.AspNetCore.Mvc.ActionConstraints;

View File

@ -0,0 +1,44 @@
namespace Lunar.Exchange.Amalgam.Server.Utilities;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Formatters;
public class SnakeCaseEndpointJsonAttribute : ActionFilterAttribute
{
private static readonly SystemTextJsonOutputFormatter Formatter = new(new JsonSerializerOptions
{
PropertyNamingPolicy = new SnakeCaseNamingPolicy()
});
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Result is ObjectResult objectResult)
objectResult.Formatters.Add(Formatter);
}
}
public class SnakeCaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name)
{
if (name == null) return null!;
var capitals = name.Count(t => char.IsUpper(t));
if (char.IsUpper(name[0])) capitals--;
Span<char> buffer = new char[name.Length + capitals];
for (int i = 0, output = 0; i < name.Length; i++)
{
var @char = name[i];
buffer[output++] = i > 0 && char.IsUpper(@char) ? '_' : @char;
buffer[output++] = @char;
}
if (buffer[^1] == '\0')
throw new Exception("Null leftover in the string buffer");
return new string(buffer).ToLower();
}
}

View File

@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Lunar.Exchange.Amalgam</RootNamespace>
<RootNamespace>Lunar.Exchange.Amalgam.Server</RootNamespace>
<UserSecretsId>90ff12a5-9b1c-4fc4-8080-f5430e34c681</UserSecretsId>
</PropertyGroup>
@ -22,4 +22,11 @@
<Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput" />
</Exec>
</Target>
<PropertyGroup>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
</Project>