Refactor contact info handling in PDF signing

Replaced the `ContactInfo` property with separate `Email` and `Phone` fields in `PdfSignOptionsDto` and `PdfSignatureCheckItemDto` for better granularity. Updated the `PdfDigitalSignatureService` to handle the new fields, introducing `BuildContactInfo` and `ParseContactInfo` methods for constructing and parsing contact information.

Modified the `PdfSignatureController` to reflect these changes, updating request models and the `SignPdfAsync` method. Updated the `README.md` to document the new structure. These changes improve the clarity and structure of contact information handling.
This commit is contained in:
2026-10-14 15:10:55 +02:00
parent 816bbce9c6
commit 51c0f51738
5 changed files with 70 additions and 5 deletions

View File

@@ -8,7 +8,8 @@ public sealed record PdfSignOptionsDto
public string? Name { get; set; } public string? Name { get; set; }
public string? Reason { get; set; } public string? Reason { get; set; }
public string? Location { 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 string? ApplicationName { get; set; }
public PdfSignatureCertificationLevel? CertificationLevel { get; set; } public PdfSignatureCertificationLevel? CertificationLevel { get; set; }
} }

View File

@@ -29,6 +29,8 @@ public sealed record PdfSignatureCheckItemDto(
string? Location, string? Location,
string? DeclaredName, string? DeclaredName,
string? ContactInfo, string? ContactInfo,
string? Email,
string? Phone,
string? DigestAlgorithm, string? DigestAlgorithm,
string? SignatureAlgorithm, string? SignatureAlgorithm,
string? SignerName, string? SignerName,

View File

@@ -239,7 +239,7 @@ Sicherheitsregel:
- `SignPdfAsync(...)`, `CheckPdfSignatureAsync(...)`, `ExtractOriginalPdfAsync(...)` - `SignPdfAsync(...)`, `CheckPdfSignatureAsync(...)`, `ExtractOriginalPdfAsync(...)`
- `IPkcs11SelfTestStatusProvider` - `IPkcs11SelfTestStatusProvider`
- `PdfSignOptionsDto` - `PdfSignOptionsDto`
- `UUID`, `Reason`, `Name`, `Location`, `ContactInfo`, `SigningTime`, `CertificationLevel` - `UUID`, `Reason`, `Name`, `Location`, `Email`, `Phone`, `CertificationLevel`
- `PdfSignatureCheckResultDto` / `PdfSignatureCheckItemDto` - `PdfSignatureCheckResultDto` / `PdfSignatureCheckItemDto`
- inklusive `BusinessReason`, `UUID`, `OriginalDocumentSha256` - inklusive `BusinessReason`, `UUID`, `OriginalDocumentSha256`
- `Pkcs11SelfTestStatusDto` - `Pkcs11SelfTestStatusDto`

View File

@@ -42,7 +42,7 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
Name = request.Name ?? pkcs11Options.CertificateLabel, Name = request.Name ?? pkcs11Options.CertificateLabel,
Reason = reasonWithMeta, Reason = reasonWithMeta,
Location = request.Location, Location = request.Location,
ContactInfo = request.ContactInfo, ContactInfo = BuildContactInfo(request.Email, request.Phone),
SigningTime = pkcs11Options.UseUtcSigningTime ? DateTimeOffset.UtcNow : DateTimeOffset.Now, SigningTime = pkcs11Options.UseUtcSigningTime ? DateTimeOffset.UtcNow : DateTimeOffset.Now,
ApplicationName = pkcs11Options.ApplicationName, ApplicationName = pkcs11Options.ApplicationName,
CertificationLevel = ToDevExpressCertificationLevel(request.CertificationLevel) CertificationLevel = ToDevExpressCertificationLevel(request.CertificationLevel)
@@ -108,6 +108,7 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
var issuedTo = ParsePrincipal(certificate?.Subject); var issuedTo = ParsePrincipal(certificate?.Subject);
var issuedBy = ParsePrincipal(certificate?.Issuer); var issuedBy = ParsePrincipal(certificate?.Issuer);
var reasonMeta = ParseReasonMeta(signature.Reason); var reasonMeta = ParseReasonMeta(signature.Reason);
var contact = ParseContactInfo(signature.ContactInfo);
items.Add(new PdfSignatureCheckItemDto( items.Add(new PdfSignatureCheckItemDto(
CoversWholeDoc: coversWholeDocument, CoversWholeDoc: coversWholeDocument,
@@ -116,6 +117,8 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
Location: signature.Location, Location: signature.Location,
DeclaredName: signature.SignerName, DeclaredName: signature.SignerName,
ContactInfo: signature.ContactInfo, ContactInfo: signature.ContactInfo,
Email: contact.Email,
Phone: contact.Phone,
DigestAlgorithm: InferDigestAlgorithm(certificate), DigestAlgorithm: InferDigestAlgorithm(certificate),
SignatureAlgorithm: InferSignatureAlgorithm(certificate), SignatureAlgorithm: InferSignatureAlgorithm(certificate),
SignerName: issuedTo.CommonName ?? signature.SignerName, SignerName: issuedTo.CommonName ?? signature.SignerName,
@@ -140,6 +143,7 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
catch (Exception ex) catch (Exception ex)
{ {
var reasonMeta = ParseReasonMeta(signature.Reason); var reasonMeta = ParseReasonMeta(signature.Reason);
var contact = ParseContactInfo(signature.ContactInfo);
items.Add(new PdfSignatureCheckItemDto( items.Add(new PdfSignatureCheckItemDto(
CoversWholeDoc: false, CoversWholeDoc: false,
@@ -148,6 +152,8 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
Location: signature.Location, Location: signature.Location,
DeclaredName: signature.SignerName, DeclaredName: signature.SignerName,
ContactInfo: signature.ContactInfo, ContactInfo: signature.ContactInfo,
Email: contact.Email,
Phone: contact.Phone,
DigestAlgorithm: null, DigestAlgorithm: null,
SignatureAlgorithm: null, SignatureAlgorithm: null,
SignerName: signature.SignerName, SignerName: signature.SignerName,
@@ -463,6 +469,60 @@ public sealed class PdfDigitalSignatureService(IOptions<Pkcs11Options> options)
return $"{prefix}| SFMETA:v1;doc={uuid};sha256={sourceHashHex}"; 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) private static (string? BusinessReason, string? UUID, string? OriginalDocumentSha256) ParseReasonMeta(string? reason)
{ {
if (string.IsNullOrWhiteSpace(reason)) if (string.IsNullOrWhiteSpace(reason))

View File

@@ -17,7 +17,8 @@ public class PdfSignatureController(IPdfDigitalSignatureService signatureService
public string? Name { get; set; } public string? Name { get; set; }
public string? Reason { get; set; } public string? Reason { get; set; }
public string? Location { 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 public sealed class CheckPdfSignatureForm
@@ -52,7 +53,8 @@ public class PdfSignatureController(IPdfDigitalSignatureService signatureService
Name = request.Name, Name = request.Name,
Reason = request.Reason, Reason = request.Reason,
Location = request.Location, Location = request.Location,
ContactInfo = request.ContactInfo, Email = request.Email,
Phone = request.Phone,
CertificationLevel = PdfSignatureCertificationLevel.FormFillingAndAnnotations CertificationLevel = PdfSignatureCertificationLevel.FormFillingAndAnnotations
}; };