using System.Net; using System.Net.Http.Headers; using System.Net.Http.Json; using BigRegister.Api.Contracts; using Microsoft.AspNetCore.Mvc.Testing; namespace BigRegister.Tests; /// RB-01/BIO-004: GET /uploads/{id}/content and /uploads/status used to take no /// HttpContext at all — a diploma or identity scan was protected by GUID /// unguessability alone, while DELETE on the same resource was owner-scoped. public class UploadAccessTests(TestWebApplicationFactory factory) : IClassFixture { private readonly HttpClient _client = factory.CreateClient(); private const string OtherCitizen = "999999990"; private async Task UploadAsOwner() { var form = new MultipartFormDataContent(); var file = new ByteArrayContent(new byte[] { 1, 2, 3 }); file.Headers.ContentType = new MediaTypeHeaderValue("application/pdf"); form.Add(file, "file", "diploma.pdf"); form.Add(new StringContent("diploma"), "categoryId"); form.Add(new StringContent("local-rb01"), "localId"); form.Add(new StringContent("registratie"), "wizardId"); var res = await _client.PostAsync("/api/v1/uploads", form); Assert.Equal(HttpStatusCode.Created, res.StatusCode); return (await res.Content.ReadFromJsonAsync())!.DocumentId; } private Task Get(string path, params (string Name, string Value)[] headers) { var req = new HttpRequestMessage(HttpMethod.Get, path); foreach (var (name, value) in headers) req.Headers.Add(name, value); return _client.SendAsync(req); } [Fact] public async Task The_owner_can_read_the_bytes() { var id = await UploadAsOwner(); Assert.Equal(HttpStatusCode.OK, (await Get($"/api/v1/uploads/{id}/content")).StatusCode); } [Fact] public async Task Another_citizen_gets_404_not_403() { var id = await UploadAsOwner(); // 404, not 403: a foreign id must not be distinguishable from one that never existed. Assert.Equal(HttpStatusCode.NotFound, (await Get($"/api/v1/uploads/{id}/content", ("X-Subject", OtherCitizen))).StatusCode); } [Fact] public async Task A_behandelaar_can_read_a_linked_document() { var id = await UploadAsOwner(); Assert.Equal(HttpStatusCode.OK, (await Get($"/api/v1/uploads/{id}/content", ("X-Medewerker", "medewerker-1"))).StatusCode); } [Fact] public async Task A_medewerker_without_the_behandelaar_rol_does_not() { var id = await UploadAsOwner(); Assert.Equal(HttpStatusCode.NotFound, (await Get($"/api/v1/uploads/{id}/content", ("X-Medewerker", "medewerker-1"), ("X-Rollen", "geen"))).StatusCode); } [Fact] public async Task Status_reports_another_citizens_localId_as_unknown() { await UploadAsOwner(); var res = await Get("/api/v1/uploads/status?localIds=local-rb01", ("X-Subject", OtherCitizen)); res.EnsureSuccessStatusCode(); var status = (await res.Content.ReadFromJsonAsync())!; var item = Assert.Single(status.Results); Assert.Equal("unknown", item.Status); Assert.Null(item.DocumentId); } }