diff --git a/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs b/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs index 654a2c4b..58832ca3 100644 --- a/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs +++ b/EnvelopeGenerator.Application/Common/Dto/PdfSignOptionsDto.cs @@ -8,7 +8,8 @@ public sealed record PdfSignOptionsDto public string? Name { get; set; } public string? Reason { get; set; } public string? Location { get; set; } - public string? ContactInfo { get; set; } + public string? Email { get; set; } + public string? Phone { get; set; } public string? ApplicationName { get; set; } public PdfSignatureCertificationLevel? CertificationLevel { get; set; } } diff --git a/EnvelopeGenerator.Application/Common/Dto/PdfSignatureCheckResultDto.cs b/EnvelopeGenerator.Application/Common/Dto/PdfSignatureCheckResultDto.cs index d694b224..0c5ba02e 100644 --- a/EnvelopeGenerator.Application/Common/Dto/PdfSignatureCheckResultDto.cs +++ b/EnvelopeGenerator.Application/Common/Dto/PdfSignatureCheckResultDto.cs @@ -29,6 +29,8 @@ public sealed record PdfSignatureCheckItemDto( string? Location, string? DeclaredName, string? ContactInfo, + string? Email, + string? Phone, string? DigestAlgorithm, string? SignatureAlgorithm, string? SignerName, diff --git a/EnvelopeGenerator.Infrastructure.Crypt/README.md b/EnvelopeGenerator.Infrastructure.Crypt/README.md index 383144d2..a2a1d1d5 100644 --- a/EnvelopeGenerator.Infrastructure.Crypt/README.md +++ b/EnvelopeGenerator.Infrastructure.Crypt/README.md @@ -239,7 +239,7 @@ Sicherheitsregel: - `SignPdfAsync(...)`, `CheckPdfSignatureAsync(...)`, `ExtractOriginalPdfAsync(...)` - `IPkcs11SelfTestStatusProvider` - `PdfSignOptionsDto` - - `UUID`, `Reason`, `Name`, `Location`, `ContactInfo`, `SigningTime`, `CertificationLevel` + - `UUID`, `Reason`, `Name`, `Location`, `Email`, `Phone`, `CertificationLevel` - `PdfSignatureCheckResultDto` / `PdfSignatureCheckItemDto` - inklusive `BusinessReason`, `UUID`, `OriginalDocumentSha256` - `Pkcs11SelfTestStatusDto` diff --git a/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs b/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs index 7ab1a290..2c68ddc9 100644 --- a/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs +++ b/EnvelopeGenerator.Infrastructure.Crypt/Services/PdfDigitalSignatureService.cs @@ -42,7 +42,7 @@ public sealed class PdfDigitalSignatureService(IOptions options) Name = request.Name ?? pkcs11Options.CertificateLabel, Reason = reasonWithMeta, Location = request.Location, - ContactInfo = request.ContactInfo, + ContactInfo = BuildContactInfo(request.Email, request.Phone), SigningTime = pkcs11Options.UseUtcSigningTime ? DateTimeOffset.UtcNow : DateTimeOffset.Now, ApplicationName = pkcs11Options.ApplicationName, CertificationLevel = ToDevExpressCertificationLevel(request.CertificationLevel) @@ -108,6 +108,7 @@ public sealed class PdfDigitalSignatureService(IOptions options) var issuedTo = ParsePrincipal(certificate?.Subject); var issuedBy = ParsePrincipal(certificate?.Issuer); var reasonMeta = ParseReasonMeta(signature.Reason); + var contact = ParseContactInfo(signature.ContactInfo); items.Add(new PdfSignatureCheckItemDto( CoversWholeDoc: coversWholeDocument, @@ -116,6 +117,8 @@ public sealed class PdfDigitalSignatureService(IOptions options) Location: signature.Location, DeclaredName: signature.SignerName, ContactInfo: signature.ContactInfo, + Email: contact.Email, + Phone: contact.Phone, DigestAlgorithm: InferDigestAlgorithm(certificate), SignatureAlgorithm: InferSignatureAlgorithm(certificate), SignerName: issuedTo.CommonName ?? signature.SignerName, @@ -140,6 +143,7 @@ public sealed class PdfDigitalSignatureService(IOptions options) catch (Exception ex) { var reasonMeta = ParseReasonMeta(signature.Reason); + var contact = ParseContactInfo(signature.ContactInfo); items.Add(new PdfSignatureCheckItemDto( CoversWholeDoc: false, @@ -148,6 +152,8 @@ public sealed class PdfDigitalSignatureService(IOptions options) Location: signature.Location, DeclaredName: signature.SignerName, ContactInfo: signature.ContactInfo, + Email: contact.Email, + Phone: contact.Phone, DigestAlgorithm: null, SignatureAlgorithm: null, SignerName: signature.SignerName, @@ -463,6 +469,60 @@ public sealed class PdfDigitalSignatureService(IOptions options) return $"{prefix}| SFMETA:v1;doc={uuid};sha256={sourceHashHex}"; } + private static string? BuildContactInfo(string? email, string? phone) + { + var normalizedEmail = string.IsNullOrWhiteSpace(email) ? null : email.Trim(); + var normalizedPhone = string.IsNullOrWhiteSpace(phone) ? null : phone.Trim(); + + if (normalizedEmail is null && normalizedPhone is null) + return null; + + if (normalizedEmail is null) + return $"tel:{normalizedPhone}"; + + if (normalizedPhone is null) + return $"mailto:{normalizedEmail}"; + + return $"mailto:{normalizedEmail};tel:{normalizedPhone}"; + } + + private static (string? Email, string? Phone) ParseContactInfo(string? contactInfo) + { + if (string.IsNullOrWhiteSpace(contactInfo)) + return (null, null); + + string? email = null; + string? phone = null; + + foreach (var part in contactInfo.Split(';', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)) + { + if (part.StartsWith("mailto:", StringComparison.OrdinalIgnoreCase)) + { + email = part[7..].Trim(); + continue; + } + + if (part.StartsWith("tel:", StringComparison.OrdinalIgnoreCase)) + { + phone = part[4..].Trim(); + continue; + } + + if (email is null && part.Contains('@', StringComparison.Ordinal)) + { + email = part.Trim(); + continue; + } + + if (phone is null) + phone = part.Trim(); + } + + return ( + string.IsNullOrWhiteSpace(email) ? null : email, + string.IsNullOrWhiteSpace(phone) ? null : phone); + } + private static (string? BusinessReason, string? UUID, string? OriginalDocumentSha256) ParseReasonMeta(string? reason) { if (string.IsNullOrWhiteSpace(reason)) diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/PdfSignatureController.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/PdfSignatureController.cs index 8f4da57d..1f0500b3 100644 --- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/PdfSignatureController.cs +++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/PdfSignatureController.cs @@ -17,7 +17,8 @@ public class PdfSignatureController(IPdfDigitalSignatureService signatureService public string? Name { get; set; } public string? Reason { get; set; } public string? Location { get; set; } - public string? ContactInfo { get; set; } + public string? Email { get; set; } + public string? Phone { get; set; } } public sealed class CheckPdfSignatureForm @@ -52,7 +53,8 @@ public class PdfSignatureController(IPdfDigitalSignatureService signatureService Name = request.Name, Reason = request.Reason, Location = request.Location, - ContactInfo = request.ContactInfo, + Email = request.Email, + Phone = request.Phone, CertificationLevel = PdfSignatureCertificationLevel.FormFillingAndAnnotations };