using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; using TinfoilVibeServer.Authentication; using TinfoilVibeServer.Middleware; namespace TinfoilVibeServerTest.Tests { [TestFixture] public class BasicAuthMiddlewareTests { private Mock> _loggerMock; private Mock _authMock; private BasicAuthMiddleware _middleware; private RequestDelegate _next; [SetUp] public void SetUp() { _loggerMock = new Mock>(); _authMock = new Mock(); _next = (HttpContext ctx) => Task.CompletedTask; _middleware = new BasicAuthMiddleware(_next); } private HttpContext CreateContext(string authHeader = null, string ip = "127.0.0.1", int? uid = null) { var ctx = new DefaultHttpContext(); ctx.Connection.RemoteIpAddress = IPAddress.Parse(ip); if (!string.IsNullOrEmpty(authHeader)) { ctx.Request.Headers["Authorization"] = authHeader; } if (uid!= null) { ctx.Request.Headers["UID"] = uid.ToString(); } return ctx; } [Test] public async Task InvokeAsync_NoAuthHeader_ShouldReturn401() { // Arrange var ctx = CreateContext(); // Act await _middleware.InvokeAsync(ctx, _authMock.Object, _loggerMock.Object); // Assert Assert.That(ctx.Response.StatusCode, Is.EqualTo(StatusCodes.Status401Unauthorized)); _loggerMock.Verify(l => l.Log( LogLevel.Warning, It.IsAny(), It.Is((v, t) => v.ToString().Contains("Missing Authorization header")), null, It.IsAny>()), Times.Once); } [Test] public async Task InvokeAsync_BlacklistedIP_ShouldReturn403() { // Arrange var ctx = CreateContext("Basic dXNlcjpwYXNz"); _authMock.Setup(a => a.IsIPBlacklisted("127.0.0.1")).Returns(true); // Act await _middleware.InvokeAsync(ctx, _authMock.Object, _loggerMock.Object); // Assert Assert.That(ctx.Response.StatusCode, Is.EqualTo(StatusCodes.Status403Forbidden)); } [Test] public async Task InvokeAsync_ValidCredentials_ShouldCallNext() { // Arrange var user = "alice"; var pw = "secret"; var uid = 1234; var header = $"Basic {Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pw}"))}"; var ip = "127.0.0.1"; var ctx = CreateContext(header,ip, uid); string? error; _authMock.Setup(a => a.TryValidate(user, pw, uid, ip, out error)) .Returns(true); bool nextCalled = false; _next = (HttpContext _) => { nextCalled = true; return Task.CompletedTask; }; _middleware = new BasicAuthMiddleware(_next); // Act await _middleware.InvokeAsync(ctx, _authMock.Object, _loggerMock.Object); // Assert Assert.That(nextCalled, Is.True); Assert.That(ctx.Response.StatusCode, Is.EqualTo(StatusCodes.Status200OK)); } } }