Move the server to own directory, commit old changes
This commit is contained in:
parent
e7d9e56d24
commit
c82196745a
0
.gitignore → amalgam-server/.gitignore
vendored
0
.gitignore → amalgam-server/.gitignore
vendored
@ -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);
|
@ -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);
|
||||
|
25
amalgam-server/Controllers/ProjectController.cs
Normal file
25
amalgam-server/Controllers/ProjectController.cs
Normal 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!");
|
||||
}
|
||||
}
|
@ -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]
|
@ -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) {}
|
||||
|
@ -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()
|
@ -2,7 +2,7 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Lunar.Exchange.Amalgam.Data.Migrations
|
||||
namespace Lunar.Exchange.Amalgam.Server.Data.Migrations
|
||||
{
|
||||
public partial class Initial : Migration
|
||||
{
|
@ -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()
|
6
amalgam-server/Data/Models/Artifact.cs
Normal file
6
amalgam-server/Data/Models/Artifact.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Lunar.Exchange.Amalgam.Server.Data.Models;
|
||||
|
||||
public class Artifact
|
||||
{
|
||||
public int Id { get; set; }
|
||||
}
|
20
amalgam-server/Data/Models/ArtifactSource.cs
Normal file
20
amalgam-server/Data/Models/ArtifactSource.cs
Normal 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();
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace Lunar.Exchange.Amalgam.Data.Models;
|
||||
namespace Lunar.Exchange.Amalgam.Server.Data.Models;
|
||||
|
||||
public class Project
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace Lunar.Exchange.Amalgam.Models;
|
||||
namespace Lunar.Exchange.Amalgam.Server.Models;
|
||||
|
||||
public class AmalgamOptions
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace Lunar.Exchange.Amalgam.Models;
|
||||
namespace Lunar.Exchange.Amalgam.Server.Models;
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
using Utilities;
|
@ -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!;
|
||||
}
|
@ -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())
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace Lunar.Exchange.Amalgam.Utilities;
|
||||
namespace Lunar.Exchange.Amalgam.Server.Utilities;
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.ActionConstraints;
|
44
amalgam-server/Utilities/SnakeCaseFormatter.cs
Normal file
44
amalgam-server/Utilities/SnakeCaseFormatter.cs
Normal 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();
|
||||
}
|
||||
}
|
@ -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>
|
Loading…
Reference in New Issue
Block a user