/// <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);
        }
Esempio n. 3
0
        /// <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);
        }
Esempio n. 4
0
        /// <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);
        }