/// <summary>Retrieves a credential record by its thread id.</summary> /// <param name="credentialService">Credential service.</param> /// <param name="context">The context.</param> /// <param name="threadId">The thread id.</param> /// <returns>The credential record.</returns> public static async Task <CredentialRecord> GetByThreadIdAsync( this ICredentialService credentialService, IAgentContext context, string threadId) { CredentialRecord record = null; try { record = await credentialService.GetAsync(context, threadId); return(record); } catch (AriesFrameworkException) { // Record was not found, thread ID didn't match record ID. This is OK } var search = await credentialService.ListAsync(context, SearchQuery.Equal(TagConstants.LastThreadId, threadId), 100); if (search.Count == 0) { throw new AriesFrameworkException(ErrorCode.RecordNotFound, $"Credential record not found by thread id : {threadId}"); } if (search.Count > 1) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, $"Multiple credential records found by thread id : {threadId}"); } record = search.Single(); return(record); }
private async Task <(IssuerCreateCredentialResult, RevocationRegistryRecord)> IssueCredentialSafeAsync( IAgentContext agentContext, DefinitionRecord definitionRecord, CredentialRecord credentialRecord) { BlobStorageReader tailsReader = null; RevocationRegistryRecord revocationRecord = null; if (definitionRecord.SupportsRevocation) { revocationRecord = await RecordService.GetAsync <RevocationRegistryRecord>(agentContext.Wallet, definitionRecord.CurrentRevocationRegistryId); tailsReader = await TailsService.OpenTailsAsync(revocationRecord.TailsFile); } try { return(await AnonCreds.IssuerCreateCredentialAsync( agentContext.Wallet, credentialRecord.OfferJson, credentialRecord.RequestJson, CredentialUtils.FormatCredentialValues(credentialRecord.CredentialAttributesValues), definitionRecord.CurrentRevocationRegistryId, tailsReader), revocationRecord); } catch (RevocationRegistryFullException) { if (!definitionRecord.RevocationAutoScale) { throw; } } var registryIndex = definitionRecord.CurrentRevocationRegistryId.Split(':').LastOrDefault()?.Split('-').FirstOrDefault(); string registryTag; if (int.TryParse(registryIndex, out var currentIndex)) { registryTag = $"{currentIndex + 1}-{definitionRecord.MaxCredentialCount}"; } else { registryTag = $"1-{definitionRecord.MaxCredentialCount}"; } var(_, nextRevocationRecord) = await SchemaService.CreateRevocationRegistryAsync(agentContext, registryTag, definitionRecord); definitionRecord.CurrentRevocationRegistryId = nextRevocationRecord.Id; await RecordService.UpdateAsync(agentContext.Wallet, definitionRecord); tailsReader = await TailsService.OpenTailsAsync(nextRevocationRecord.TailsFile); return(await AnonCreds.IssuerCreateCredentialAsync( agentContext.Wallet, credentialRecord.OfferJson, credentialRecord.RequestJson, CredentialUtils.FormatCredentialValues(credentialRecord.CredentialAttributesValues), nextRevocationRecord.Id, tailsReader), nextRevocationRecord); }
/// <inheritdoc /> public virtual async Task <string> ProcessOfferAsync(IAgentContext agentContext, CredentialOfferMessage credentialOffer, ConnectionRecord connection) { var offerAttachment = credentialOffer.Offers.FirstOrDefault(x => x.Id == "libindy-cred-offer-0") ?? throw new ArgumentNullException(nameof(CredentialOfferMessage.Offers)); var offerJson = offerAttachment.Data.Base64.GetBytesFromBase64().GetUTF8String(); var offer = JObject.Parse(offerJson); var definitionId = offer["cred_def_id"].ToObject <string>(); var schemaId = offer["schema_id"].ToObject <string>(); var threadId = credentialOffer.GetThreadId() ?? Guid.NewGuid().ToString(); // Write offer record to local wallet var credentialRecord = new CredentialRecord { Id = threadId, OfferJson = offerJson, ConnectionId = connection?.Id, CredentialDefinitionId = definitionId, CredentialAttributesValues = credentialOffer.CredentialPreview?.Attributes .Select(x => new CredentialPreviewAttribute { Name = x.Name, MimeType = x.MimeType, Value = x.Value }).ToArray(), SchemaId = schemaId, State = CredentialState.Offered }; credentialRecord.SetTag(TagConstants.Role, TagConstants.Holder); credentialRecord.SetTag(TagConstants.LastThreadId, threadId); await RecordService.AddAsync(agentContext.Wallet, credentialRecord); EventAggregator.Publish(new ServiceMessageProcessingEvent { RecordId = credentialRecord.Id, MessageType = credentialOffer.Type, ThreadId = threadId }); return(credentialRecord.Id); }
/// <inheritdoc /> public async Task <(CredentialOfferMessage, CredentialRecord)> CreateOfferAsync( IAgentContext agentContext, OfferConfiguration config, string connectionId) { Logger.LogInformation(LoggingEvents.CreateCredentialOffer, "DefinitionId {0}, IssuerDid {1}", config.CredentialDefinitionId, config.IssuerDid); var threadId = Guid.NewGuid().ToString(); if (!string.IsNullOrEmpty(connectionId)) { var connection = await ConnectionService.GetAsync(agentContext, connectionId); if (connection.State != ConnectionState.Connected) { throw new AriesFrameworkException(ErrorCode.RecordInInvalidState, $"Connection state was invalid. Expected '{ConnectionState.Connected}', found '{connection.State}'"); } } if (config.CredentialAttributeValues != null && config.CredentialAttributeValues.Any()) { CredentialUtils.ValidateCredentialPreviewAttributes(config.CredentialAttributeValues); } var offerJson = await AnonCreds.IssuerCreateCredentialOfferAsync( agentContext.Wallet, config.CredentialDefinitionId); var offerJobj = JObject.Parse(offerJson); var schemaId = offerJobj["schema_id"].ToObject <string>(); // Write offer record to local wallet var credentialRecord = new CredentialRecord { Id = threadId, CredentialDefinitionId = config.CredentialDefinitionId, OfferJson = offerJson, ConnectionId = connectionId, SchemaId = schemaId, CredentialAttributesValues = config.CredentialAttributeValues, State = CredentialState.Offered, }; credentialRecord.SetTag(TagConstants.LastThreadId, threadId); credentialRecord.SetTag(TagConstants.Role, TagConstants.Issuer); if (!string.IsNullOrEmpty(config.IssuerDid)) { credentialRecord.SetTag(TagConstants.IssuerDid, config.IssuerDid); } if (config.Tags != null) { foreach (var tag in config.Tags) { if (!credentialRecord.Tags.Keys.Contains(tag.Key)) { credentialRecord.Tags.Add(tag.Key, tag.Value); } } } await RecordService.AddAsync(agentContext.Wallet, credentialRecord); return(new CredentialOfferMessage(agentContext.UseMessageTypesHttps) { Id = threadId, Offers = new Attachment[] { new Attachment { Id = "libindy-cred-offer-0", MimeType = CredentialMimeTypes.ApplicationJsonMimeType, Data = new AttachmentContent { Base64 = offerJson.GetUTF8Bytes().ToBase64String() } } }, CredentialPreview = credentialRecord.CredentialAttributesValues != null ? new CredentialPreviewMessage(agentContext.UseMessageTypesHttps) { Attributes = credentialRecord.CredentialAttributesValues.Select(x => new CredentialPreviewAttribute { Name = x.Name, MimeType = x.MimeType, Value = x.Value?.ToString() }).ToArray() } : null }, credentialRecord); }
/// <summary>Creates a deep copy.</summary> /// <returns></returns> public CredentialRecord DeepCopy() { CredentialRecord copy = (CredentialRecord)MemberwiseClone(); return(copy); }