Add support for visual PDF signatures
Enhanced `PdfSignOptionsDto` with a `VisualSignature` property and introduced the `PdfVisualSignatureOptionsDto` class for configuring visual signature options. Updated `PdfDigitalSignatureService` to handle visual signatures, including page number resolution, signature bounds calculation, and appearance customization. Refactored `PdfSignatureController` to support visual signatures by extending `SignPdfForm` with `SignatureImageFile` and `VSignature` properties. Improved validation for page numbers and signature dimensions. Streamlined `Sign` and `IsSigned` endpoints for better clarity and reduced redundancy. Added XML documentation for improved API clarity and performed general code cleanup to enhance maintainability.
This commit is contained in:
@@ -38,14 +38,19 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
|
||||
var reasonWithMeta = BuildReasonWithMeta(request.Reason ?? pkcs11Options.DefaultReason, uuid, sourceHashHex);
|
||||
|
||||
using var signer = new PdfDocumentSigner(workingInput);
|
||||
var signaturePageNumber = ResolveSignaturePageNumber(request.VisualSignature?.PageNumber, signer.PageCount);
|
||||
|
||||
var digestCalculator = new DigestCalculator(HashAlgorithmType.SHA256);
|
||||
var signerInfo = new ExternalSignerInfo(PdfSignatureType.Pkcs7, 32768, digestCalculator);
|
||||
var signatureFieldInfo = new PdfSignatureFieldInfo(1)
|
||||
var signatureFieldInfo = new PdfSignatureFieldInfo(signaturePageNumber)
|
||||
{
|
||||
Name = $"Sig_{DateTimeOffset.UtcNow:yyyyMMddHHmmss}"
|
||||
};
|
||||
|
||||
var signatureBounds = CreateSignatureBounds(request.VisualSignature);
|
||||
if (signatureBounds is not null)
|
||||
signatureFieldInfo.SignatureBounds = signatureBounds;
|
||||
|
||||
var builder = new PdfDeferredSignatureBuilder(signerInfo, signatureFieldInfo)
|
||||
{
|
||||
Name = request.Name ?? pkcs11Options.CertificateLabel,
|
||||
@@ -59,6 +64,21 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
|
||||
?? PdfCertificationLevel.NoCertification
|
||||
};
|
||||
|
||||
if(request.VisualSignature is PdfVisualSignatureOptionsDto visualSignature)
|
||||
{
|
||||
builder.SetSignatureAppearance(new PdfSignatureAppearance
|
||||
{
|
||||
AppearanceType = PdfSignatureAppearanceType.Name,
|
||||
ShowLabels = visualSignature.ShowLabels,
|
||||
ShowName = true,
|
||||
ShowDate = false,
|
||||
ShowReason = false,
|
||||
ShowLocation = false,
|
||||
ShowDistinguishedName = false
|
||||
});
|
||||
builder.SetImageData(visualSignature.ImageBytes);
|
||||
}
|
||||
|
||||
var deferredSigner = signer.SignDeferred(builder);
|
||||
var externalSigner = new Pkcs11ExternalSigner(pkcs11Options);
|
||||
deferredSigner.Sign(outputPdf, externalSigner.BuildSignature(deferredSigner.HashValue, digestCalculator.AlgorithmOid));
|
||||
@@ -535,6 +555,37 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
|
||||
: Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
private static int ResolveSignaturePageNumber(int? requestedPageNumber, int pageCount)
|
||||
{
|
||||
var pageNumber = requestedPageNumber ?? 1;
|
||||
if (pageNumber < 1)
|
||||
throw new ArgumentOutOfRangeException(nameof(requestedPageNumber), "SignaturePageNumber must be greater than or equal to 1.");
|
||||
|
||||
if (pageCount > 0 && pageNumber > pageCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(requestedPageNumber), $"SignaturePageNumber {pageNumber} exceeds page count {pageCount}.");
|
||||
|
||||
return pageNumber;
|
||||
}
|
||||
|
||||
private static PdfRectangle? CreateSignatureBounds(PdfVisualSignatureOptionsDto? visualOptions)
|
||||
{
|
||||
if (visualOptions is null)
|
||||
return null;
|
||||
|
||||
var left = visualOptions.Left;
|
||||
var bottom = visualOptions.Bottom;
|
||||
var width = visualOptions.Width;
|
||||
var height = visualOptions.Height;
|
||||
|
||||
if (left < 0 || bottom < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(visualOptions), "VisualSignature.Left and VisualSignature.Bottom cannot be negative.");
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(visualOptions), "VisualSignature.Width and VisualSignature.Height must be greater than zero.");
|
||||
|
||||
return new PdfRectangle(left, bottom, left + width, bottom + height);
|
||||
}
|
||||
|
||||
private static string BuildReasonWithMeta(string? businessReason, string uuid, string sourceHashHex)
|
||||
{
|
||||
var trimmedReason = string.IsNullOrWhiteSpace(businessReason) ? null : businessReason.Trim();
|
||||
|
||||
Reference in New Issue
Block a user