From 3b21dbc8f7920efb7406158915fc0152a024f6c5 Mon Sep 17 00:00:00 2001 From: TekH Date: Thu, 22 Oct 2026 02:26:21 +0200 Subject: [PATCH] feat(api): add PdfSignatureController and wire signing DI --- .../Controllers/PdfSignatureController.cs | 72 +++++++++++++++++++ .../DocumentService.API.csproj | 2 + DocumentService.API/Program.cs | 4 ++ 3 files changed, 78 insertions(+) create mode 100644 DocumentService.API/Controllers/PdfSignatureController.cs diff --git a/DocumentService.API/Controllers/PdfSignatureController.cs b/DocumentService.API/Controllers/PdfSignatureController.cs new file mode 100644 index 0000000..d9efb40 --- /dev/null +++ b/DocumentService.API/Controllers/PdfSignatureController.cs @@ -0,0 +1,72 @@ +using DocumentOperator.Application.Common.Dto; +using DocumentOperator.Application.SignPdf; +using DocumentService.Domain.Common.Exceptions; +using MediatR; +using Microsoft.AspNetCore.Mvc; + +namespace DocumentService.API.Controllers; + +/// +/// Controller for PDF digital signing (PKCS#11 / company certificate). +/// +[ApiController] +[Route("api/pdf/signature")] +public class PdfSignatureController(IMediator mediator) : ControllerBase +{ + /// + /// Digitally signs a PDF using the configured PKCS#11 signing infrastructure. + /// + /// Base64-encoded PDF, optional signature image, and signing options + /// Cancellation token + /// Signed PDF + /// PDF signed successfully - returns signed PDF + /// Invalid input (Base64 format error, invalid appearance) + /// Internal server error during signing + [HttpPost("sign")] + [Consumes("application/json")] + [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] + public async Task Sign([FromBody] SignPdfRequest request, CancellationToken cancellationToken) + { + byte[] signedPdf; + try + { + signedPdf = await mediator.Send(new SignPdfCommand + { + InputPdf = new MemoryStream(Convert.FromBase64String(request.Base64Pdf)), + Options = request.Options, + SignatureImage = string.IsNullOrWhiteSpace(request.Base64SignatureImage) + ? null + : new MemoryStream(Convert.FromBase64String(request.Base64SignatureImage)) + }, cancellationToken); + } + catch (FormatException ex) + { + throw new BadRequestException("Invalid Base64 format: " + ex.Message); + } + + return File(signedPdf, "application/pdf", "signed.pdf"); + } +} + +/// +/// Request DTO for PDF signing via JSON payload. +/// +public sealed class SignPdfRequest +{ + /// + /// Base64-encoded PDF to sign. + /// + public required string Base64Pdf { get; init; } + + /// + /// Optional Base64-encoded signature image (PNG/JPEG). + /// + public string? Base64SignatureImage { get; init; } + + /// + /// Signing options (metadata + appearance). + /// + public required PdfSignOptionsDto Options { get; init; } +} diff --git a/DocumentService.API/DocumentService.API.csproj b/DocumentService.API/DocumentService.API.csproj index 1540120..fdfc245 100644 --- a/DocumentService.API/DocumentService.API.csproj +++ b/DocumentService.API/DocumentService.API.csproj @@ -36,6 +36,8 @@ + + diff --git a/DocumentService.API/Program.cs b/DocumentService.API/Program.cs index cbd09dd..8943e98 100644 --- a/DocumentService.API/Program.cs +++ b/DocumentService.API/Program.cs @@ -7,8 +7,10 @@ using DocumentService.Infrastructure.Configuration; using DocumentService.Application; using DocumentService.Application.Common.Configuration; using DocumentService.Infrastructure; +using DocumentService.Infrastructure.Crypt.DependencyInjection; using DocumentService.API.Middleware; using DocumentService.API.Configuration; +using DocumentOperator.Application; var builder = WebApplication.CreateBuilder(args); @@ -50,6 +52,8 @@ try // ======================================== builder.Services.AddApplication(builder.Configuration); // Application Layer (MediatR, FluentValidation, Behaviors) builder.Services.AddInfrastructure(); // Infrastructure Layer (DevExpress, Services) + builder.Services.AddDocumentOperatorApplication(builder.Configuration); // PDF signing Application (MediatR) + builder.Services.AddCryptInfrastructure(builder.Configuration); // PKCS#11 PDF signing (DevExpress) builder.Services.AddControllers(); // Controllers (Controller-based API) builder.Services.AddEndpointsApiExplorer();