private async Task <CredentialRecord> UpdateValuesAsync(string credentialId, CredentialIssueMessage credentialIssue, IAgentContext agentContext) { var credentialAttachment = credentialIssue.Credentials.FirstOrDefault(x => x.Id == "libindy-cred-0") ?? throw new ArgumentException("Credential attachment not found"); var credentialJson = credentialAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String(); var jcred = JObject.Parse(credentialJson); var values = jcred["values"].ToObject <Dictionary <string, AttributeValue> >(); var credential = await _credentialService.GetAsync(agentContext, credentialId); credential.CredentialAttributesValues = values.Select(x => new CredentialPreviewAttribute { Name = x.Key, Value = x.Value.Raw, MimeType = CredentialMimeTypes.TextMimeType }).ToList(); await _recordService.UpdateAsync(agentContext.Wallet, credential); return(credential); }
/// <inheritdoc /> public async Task <(CredentialIssueMessage, CredentialRecord)> CreateCredentialAsync(IAgentContext agentContext, string credentialId, IEnumerable <CredentialPreviewAttribute> values) { var credentialRecord = await GetAsync(agentContext, credentialId); if (credentialRecord.State != CredentialState.Requested) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, $"Credential state was invalid. Expected '{CredentialState.Requested}', found '{credentialRecord.State}'"); } if (values != null && values.Any()) { credentialRecord.CredentialAttributesValues = values; } var definitionRecord = await SchemaService.GetCredentialDefinitionAsync(agentContext.Wallet, credentialRecord.CredentialDefinitionId); if (credentialRecord.ConnectionId != null) { var connection = await ConnectionService.GetAsync(agentContext, credentialRecord.ConnectionId); if (connection.State != ConnectionState.Connected) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); } } var(issuedCredential, revocationRecord) = await IssueCredentialSafeAsync(agentContext, definitionRecord, credentialRecord); if (definitionRecord.SupportsRevocation) { var provisioning = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); var paymentInfo = await PaymentService.GetTransactionCostAsync(agentContext, TransactionTypes.REVOC_REG_ENTRY); if (issuedCredential.RevocRegDeltaJson != null) { await LedgerService.SendRevocationRegistryEntryAsync( context : agentContext, issuerDid : provisioning.IssuerDid, revocationRegistryDefinitionId : revocationRecord.Id, revocationDefinitionType : "CL_ACCUM", value : issuedCredential.RevocRegDeltaJson, paymentInfo : paymentInfo); } // Store data relevant for credential revocation credentialRecord.CredentialRevocationId = issuedCredential.RevocId; credentialRecord.RevocationRegistryId = revocationRecord.Id; if (paymentInfo != null) { await RecordService.UpdateAsync(agentContext.Wallet, paymentInfo.PaymentAddress); } } await credentialRecord.TriggerAsync(CredentialTrigger.Issue); await RecordService.UpdateAsync(agentContext.Wallet, credentialRecord); var threadId = credentialRecord.GetTag(TagConstants.LastThreadId); var credentialMsg = new CredentialIssueMessage(agentContext.UseMessageTypesHttps) { Credentials = new[] { new Attachment { Id = "libindy-cred-0", MimeType = CredentialMimeTypes.ApplicationJsonMimeType, Data = new AttachmentContent { Base64 = issuedCredential.CredentialJson .GetUTF8Bytes() .ToBase64String() } } } }; credentialMsg.ThreadFrom(threadId); return(credentialMsg, credentialRecord); }
/// <inheritdoc /> public virtual async Task <string> ProcessCredentialAsync(IAgentContext agentContext, CredentialIssueMessage credential, ConnectionRecord connection) { var credentialAttachment = credential.Credentials.FirstOrDefault(x => x.Id == "libindy-cred-0") ?? throw new ArgumentException("Credential attachment not found"); var credentialJson = credentialAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String(); var credentialJobj = JObject.Parse(credentialJson); var definitionId = credentialJobj["cred_def_id"].ToObject <string>(); var revRegId = credentialJobj["rev_reg_id"]?.ToObject <string>(); var credentialRecord = await Policy.Handle <AriesFrameworkException>() .RetryAsync(3, async(ex, retry) => { await Task.Delay((int)Math.Pow(retry, 2) * 100); }) .ExecuteAsync(() => this.GetByThreadIdAsync(agentContext, credential.GetThreadId())); if (credentialRecord.State != CredentialState.Requested) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, $"Credential state was invalid. Expected '{CredentialState.Requested}', found '{credentialRecord.State}'"); } var credentialDefinition = await LedgerService.LookupDefinitionAsync(agentContext, definitionId); string revocationRegistryDefinitionJson = null; if (!string.IsNullOrEmpty(revRegId)) { // If credential supports revocation, lookup registry definition var revocationRegistry = await LedgerService.LookupRevocationRegistryDefinitionAsync(agentContext, revRegId); revocationRegistryDefinitionJson = revocationRegistry.ObjectJson; credentialRecord.RevocationRegistryId = revRegId; } var credentialId = await AnonCreds.ProverStoreCredentialAsync( wallet : agentContext.Wallet, credId : credentialRecord.Id, credReqMetadataJson : credentialRecord.CredentialRequestMetadataJson, credJson : credentialJson, credDefJson : credentialDefinition.ObjectJson, revRegDefJson : revocationRegistryDefinitionJson); credentialRecord.CredentialId = credentialId; await credentialRecord.TriggerAsync(CredentialTrigger.Issue); await RecordService.UpdateAsync(agentContext.Wallet, credentialRecord); EventAggregator.Publish(new ServiceMessageProcessingEvent { RecordId = credentialRecord.Id, MessageType = credential.Type, ThreadId = credential.GetThreadId() }); return(credentialRecord.Id); }
/// <inheritdoc /> public async Task <(CredentialIssueMessage, CredentialRecord)> CreateCredentialAsync(IAgentContext agentContext, string credentialId, IEnumerable <CredentialPreviewAttribute> values) { var credential = await GetAsync(agentContext, credentialId); if (credential.State != CredentialState.Requested) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, $"Credential state was invalid. Expected '{CredentialState.Requested}', found '{credential.State}'"); } if (values != null && values.Any()) { credential.CredentialAttributesValues = values; } var definitionRecord = await SchemaService.GetCredentialDefinitionAsync(agentContext.Wallet, credential.CredentialDefinitionId); if (credential.ConnectionId != null) { var connection = await ConnectionService.GetAsync(agentContext, credential.ConnectionId); if (connection.State != ConnectionState.Connected) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); } } string revocationRegistryId = null; BlobStorageReader tailsReader = null; if (definitionRecord.SupportsRevocation) { var revocationRecordSearch = await RecordService.SearchAsync <RevocationRegistryRecord>( agentContext.Wallet, SearchQuery.Equal(nameof(RevocationRegistryRecord.CredentialDefinitionId), definitionRecord.Id), null, 5); var revocationRecord = revocationRecordSearch.Single(); // TODO: Credential definition can have multiple revocation registries revocationRegistryId = revocationRecord.Id; tailsReader = await TailsService.OpenTailsAsync(revocationRecord.TailsFile); } var issuedCredential = await AnonCreds.IssuerCreateCredentialAsync(agentContext.Wallet, credential.OfferJson, credential.RequestJson, CredentialUtils.FormatCredentialValues(credential.CredentialAttributesValues), revocationRegistryId, tailsReader); if (definitionRecord.SupportsRevocation) { var provisioning = await ProvisioningService.GetProvisioningAsync(agentContext.Wallet); var paymentInfo = await PaymentService.GetTransactionCostAsync(agentContext, TransactionTypes.REVOC_REG_ENTRY); await LedgerService.SendRevocationRegistryEntryAsync( context : agentContext, issuerDid : provisioning.IssuerDid, revocationRegistryDefinitionId : revocationRegistryId, revocationDefinitionType : "CL_ACCUM", value : issuedCredential.RevocRegDeltaJson, paymentInfo : paymentInfo); credential.CredentialRevocationId = issuedCredential.RevocId; if (paymentInfo != null) { await RecordService.UpdateAsync(agentContext.Wallet, paymentInfo.PaymentAddress); } } await credential.TriggerAsync(CredentialTrigger.Issue); await RecordService.UpdateAsync(agentContext.Wallet, credential); var threadId = credential.GetTag(TagConstants.LastThreadId); var credentialMsg = new CredentialIssueMessage { Credentials = new[] { new Attachment { Id = "libindy-cred-0", MimeType = CredentialMimeTypes.ApplicationJsonMimeType, Data = new AttachmentContent { Base64 = issuedCredential.CredentialJson .GetUTF8Bytes() .ToBase64String() } } } }; credentialMsg.ThreadFrom(threadId); return(credentialMsg, credential); }