Sari la conținut

MSign (semnătură electronică)

ASYDATA folosește MSign (platforma de semnătură electronică din Moldova), accesat prin integratorul Prasada, pentru a semna documente: facturi emise, facturi primite și contracte. Orchestrarea e în src/Asy.Infrastructure/Msign/MsignService.cs, aggregate-ul de domeniu în src/Asy.Domain/Msign/MsignRequest.cs, interfața de serviciu în src/Asy.Application/Msign/Services/IMsignService.cs, iar clientul HTTP către Prasada în src/Asy.Infrastructure/Msign/PrasadaMsignClient.cs. Endpoint-urile sunt expuse de modulul Odoo-style src/Modules/Asy.Modules.Msign/.

MSign e nodul de semnare din comunicare și semnare și pasul intermediar din emiterea facturilor — vezi e-Factură (SFS).

DeclanșatorTip documentEntitate legatăpostBackTarget
Factură emisă (e-Factură)XMLRelatedInvoiceIdefactura:postinvoices:1
Factură primită (card Telegram)XMLRelatedInvoiceIdefactura:postinvoices:2
Contract (firmă sau partener)PDFRelatedContractId / RelatedDocumentShareIdnull
1. INIȚIERE → InitiateXmlAsync(...) sau InitiatePdfAsync(...)
→ creează MsignRequest (status Pending), criptează conținutul original
→ Prasada /api/msign/initiate(-pdf) → MSignRequestId + RedirectUrl
2. REDIRECT → user e dus la UI-ul MSign, alege certificatul, semnează
3. CALLBACK → GET /api/msign/callback?msignRequestId=…&msignStatus=success|error
→ HandleCallbackAsync → status CallbackReceived
4. REZULTAT → Prasada /api/msign/result/{id} → semnătură + certificat + document semnat
→ parsare certificat X.509 → metadate semnatar
→ criptare + persistare → status Completed
5. POST-ACȚIUNI (după Completed, în funcție de ce e setat):
- PostBackTarget setat → TryAutoPostAsync → PostInvoices la SFS
- RelatedContractId setat → TryAttachToContractAsync
- RelatedDocumentShareId setat → TryAttachToShareAsync
- RelatedInvoiceId setat → TryUpdateInvoiceEFacturaStatusAsync

InitiatePdfAsync și InitiateXmlAsync comit MsignRequest-ul în DB înainte de a chema Prasada, ca cererea să fie înregistrată chiar dacă apelul extern eșuează.

Enum-ul din src/Asy.Domain/Msign/MsignRequest.cs:

StareSens
Pendingtrimis la Prasada, așteaptă semnarea
CallbackReceivedcallback ajuns, se aduce rezultatul
Completedrezultat persistat — semnat OK
Failederoare (user a refuzat, eroare Prasada, timeout)

IsTerminal = Completed sau Failed.

Endpoint: GET /api/msign/callback (în src/Modules/Asy.Modules.Msign/Endpoints/MsignEndpoints.cs), fără autentificare — e un redirect de browser dinspre serviciul extern. HandleCallbackAsync găsește toate MsignRequest-urile cu același MSignRequestId (mai multe în caz de batch), aduce rezultatul de la Prasada și aplică post-acțiunile.

Din certificatul X.509 returnat de Prasada se extrag (în ApplyResult):

CâmpStocareSens
SignerNametext simplunumele din CN-ul certificatului
SignerIdnptext simplucod personal (cert de persoană fizică)
SignerOrgIdnotext simpluIDNO organizație (cert de organizație)
CertIssuer, CertSerialNumber, CertValidFrom, CertValidTotext simplumetadate certificat
SignedDocumentSha256text simpluhash pentru detectarea modificărilor ulterioare
SignatureEncrypted, CertificateEncrypted, SignedDocumentEncrypted, OriginalContentEncryptedcriptatconținut sensibil

Câmpurile sensibile se criptează cu IDataProtector cu purpose "Asy.Msign.v1". Identificatorul de Moldova se citește din serialNumber (OID 2.5.4.5), format NTRMD-<13 cifre>; prima cifră 2 → persoană fizică (SignerIdnp), altfel organizație (SignerOrgIdno).

PostBackTarget are formatul "efactura:postinvoices:<actorRole>" (<actorRole> = 1 furnizor, 2 cumpărător). Când e setat și statusul e Completed, TryAutoPostAsync reconstruiește plicul XAdES (combină XML-ul original cu semnătura ds:Signature), îl împachetează în <Documents> și apelează EfacturaService.InvokeSfsAsync("PostInvoices", …) cu InvoicesXmlStatus: 1. Rezultatul se salvează în PostBackResult / PostBackAt; succesul e detectat după totalInvoicesPosted >= 1 (SFS răspunde HTTP 200 cu errorMessage chiar și la eroare de validare).

MetodăDeclanșatorCe face
TryAttachToContractAsyncRelatedContractId setatre-urcă PDF-ul semnat în bucket asy-contracts (contracts/{firmId}/signed_{contractId}_{ts}.pdf), setează Contract.FilePath + SignedByFirmAt
TryAttachToShareAsyncRelatedDocumentShareId setatre-urcă PDF-ul co-semnat, setează Contract.SignedByPartnerAt + DocumentShare.SignedAt/SignerName/SignerIdnp/SignerOrgIdno; auto-asignează firma dacă certificatul de organizație al semnatarului are IDNO ce există în ASYDATA

Butonul MSign de pe cardul de e-Factură din Telegram nu face POST la SFS în momentul tap-ului — e un buton-URL care doar inițiază linkul de semnare și face redirect (302) către MSign. Constrângerea explicită a fost: „la msign sa nu faci post pe efactura, doar pana acolo” (vezi docs/modules/telegram.md).

Modul Asy.Modules.Msign, prefix /api/msign:

MetodăCaleAuth
POST/pdfda + gate modul
POST/xmlda + gate modul
GET/callbacknu (redirect browser)
GET/requests/{id}, /requestsda + gate modul
GET/requests/{id}/downloadda + gate modul