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șatori
Secțiune intitulată „Declanșatori”| Declanșator | Tip document | Entitate legată | postBackTarget |
|---|---|---|---|
| Factură emisă (e-Factură) | XML | RelatedInvoiceId | efactura:postinvoices:1 |
| Factură primită (card Telegram) | XML | RelatedInvoiceId | efactura:postinvoices:2 |
| Contract (firmă sau partener) | RelatedContractId / RelatedDocumentShareId | null |
Fluxul de semnare
Secțiune intitulată „Fluxul de semnare”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 → TryUpdateInvoiceEFacturaStatusAsyncInitiatePdfAsync și InitiateXmlAsync comit MsignRequest-ul în DB înainte de a chema Prasada, ca
cererea să fie înregistrată chiar dacă apelul extern eșuează.
Stările MsignStatus
Secțiune intitulată „Stările MsignStatus”Enum-ul din src/Asy.Domain/Msign/MsignRequest.cs:
| Stare | Sens |
|---|---|
Pending | trimis la Prasada, așteaptă semnarea |
CallbackReceived | callback ajuns, se aduce rezultatul |
Completed | rezultat persistat — semnat OK |
Failed | eroare (user a refuzat, eroare Prasada, timeout) |
IsTerminal = Completed sau Failed.
Callback-ul
Secțiune intitulată „Callback-ul”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.
Metadatele semnatarului
Secțiune intitulată „Metadatele semnatarului”Din certificatul X.509 returnat de Prasada se extrag (în ApplyResult):
| Câmp | Stocare | Sens |
|---|---|---|
SignerName | text simplu | numele din CN-ul certificatului |
SignerIdnp | text simplu | cod personal (cert de persoană fizică) |
SignerOrgIdno | text simplu | IDNO organizație (cert de organizație) |
CertIssuer, CertSerialNumber, CertValidFrom, CertValidTo | text simplu | metadate certificat |
SignedDocumentSha256 | text simplu | hash pentru detectarea modificărilor ulterioare |
SignatureEncrypted, CertificateEncrypted, SignedDocumentEncrypted, OriginalContentEncrypted | criptat | conț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 (auto-post la SFS)
Secțiune intitulată „PostBackTarget (auto-post la SFS)”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).
Auto-attach (contract / partajare)
Secțiune intitulată „Auto-attach (contract / partajare)”| Metodă | Declanșator | Ce face |
|---|---|---|
TryAttachToContractAsync | RelatedContractId setat | re-urcă PDF-ul semnat în bucket asy-contracts (contracts/{firmId}/signed_{contractId}_{ts}.pdf), setează Contract.FilePath + SignedByFirmAt |
TryAttachToShareAsync | RelatedDocumentShareId setat | re-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 |
Constrângerea de la butonul MSign din Telegram
Secțiune intitulată „Constrângerea de la butonul MSign din Telegram”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).
Endpoint-urile MSign
Secțiune intitulată „Endpoint-urile MSign”Modul Asy.Modules.Msign, prefix /api/msign:
| Metodă | Cale | Auth |
|---|---|---|
POST | /pdf | da + gate modul |
POST | /xml | da + gate modul |
GET | /callback | nu (redirect browser) |
GET | /requests/{id}, /requests | da + gate modul |
GET | /requests/{id}/download | da + gate modul |
- e-Factură (SFS) — emiterea facturilor și PostInvoices
- Comunicare și semnare — locul semnării în business flow
- Telegram — butonul MSign de pe card
- Domenii — contextul Msign
- Schema vizuală pe Figma