/// <inheritdoc /> public virtual async Task SendOfferAsync(Wallet wallet, DefaultCreateOfferConfiguration config) { Logger.LogInformation(LoggingEvents.SendCredentialOffer, "DefinitionId {0}, ConnectionId {1}, IssuerDid {2}", config.CredentialDefinitionId, config.ConnectionId, config.IssuerDid); var connection = await ConnectionService.GetAsync(wallet, config.ConnectionId); var offer = await CreateOfferAsync(wallet, config); await RouterService.ForwardAsync(new ForwardEnvelopeMessage { Content = offer.ToJson(), Type = MessageUtils.FormatDidMessageType(connection.TheirDid, MessageTypes.Forward) }, connection.Endpoint); }
internal static async Task <(CredentialRecord issuerCredential, CredentialRecord holderCredential)> IssueCredentialAsync( ISchemaService schemaService, ICredentialService credentialService, IProducerConsumerCollection <IEnvelopeMessage> messages, string issuerConnectionId, Wallet issuerWallet, Wallet holderWallet, Pool pool, string proverMasterSecretId, bool revocable) { // Create an issuer DID/VK. Can also be created during provisioning var issuer = await Did.CreateAndStoreMyDidAsync(issuerWallet, new { seed = "000000000000000000000000Steward1" }.ToJson()); // Creata a schema and credential definition for this issuer var schemaId = await schemaService.CreateSchemaAsync(pool, issuerWallet, issuer.Did, $"Test-Schema-{Guid.NewGuid().ToString()}", "1.0", new[] { "first_name", "last_name" }); var definitionId = await schemaService.CreateCredentialDefinitionAsync(pool, issuerWallet, schemaId, issuer.Did, revocable, 100, new Uri("http://mock/tails")); var offerConfig = new DefaultCreateOfferConfiguration() { ConnectionId = issuerConnectionId, IssuerDid = issuer.Did, CredentialDefinitionId = definitionId }; // Send an offer to the holder using the established connection channel await credentialService.SendOfferAsync(issuerWallet, offerConfig); // Holder retrives message from their cloud agent var credentialOffer = FindContentMessage <CredentialOfferMessage>(messages); // Holder processes the credential offer by storing it var holderCredentialId = await credentialService.ProcessOfferAsync(holderWallet, credentialOffer); // Holder creates master secret. Will also be created during wallet agent provisioning await AnonCreds.ProverCreateMasterSecretAsync(holderWallet, proverMasterSecretId); // Holder accepts the credential offer and sends a credential request await credentialService.AcceptOfferAsync(holderWallet, pool, holderCredentialId, new Dictionary <string, string> { { "first_name", "Jane" }, { "last_name", "Doe" } }); // Issuer retrieves credential request from cloud agent var credentialRequest = FindContentMessage <CredentialRequestMessage>(messages); Assert.NotNull(credentialRequest); // Issuer processes the credential request by storing it var issuerCredentialId = await credentialService.ProcessCredentialRequestAsync(issuerWallet, credentialRequest); // Issuer accepts the credential requests and issues a credential await credentialService.IssueCredentialAsync(pool, issuerWallet, issuer.Did, issuerCredentialId); // Holder retrieves the credential from their cloud agent var credential = FindContentMessage <CredentialMessage>(messages); Assert.NotNull(credential); // Holder processes the credential by storing it in their wallet await credentialService.ProcessCredentialAsync(pool, holderWallet, credential); // Verify states of both credential records are set to 'Issued' var issuerCredential = await credentialService.GetAsync(issuerWallet, issuerCredentialId); var holderCredential = await credentialService.GetAsync(holderWallet, holderCredentialId); return(issuerCredential, holderCredential); }
/// <inheritdoc /> public virtual async Task <CredentialOfferMessage> CreateOfferAsync(Wallet wallet, DefaultCreateOfferConfiguration config) { Logger.LogInformation(LoggingEvents.CreateCredentialOffer, "DefinitionId {0}, ConnectionId {1}, IssuerDid {2}", config.CredentialDefinitionId, config.ConnectionId, config.IssuerDid); var connection = await ConnectionService.GetAsync(wallet, config.ConnectionId); var offerJson = await AnonCreds.IssuerCreateCredentialOfferAsync(wallet, config.CredentialDefinitionId); var nonce = JObject.Parse(offerJson)["nonce"].ToObject <string>(); // Write offer record to local wallet var credentialRecord = new CredentialRecord { Id = Guid.NewGuid().ToString(), CredentialDefinitionId = config.CredentialDefinitionId, OfferJson = offerJson, ValuesJson = CredentialUtils.FormatCredentialValues(config.CredentialAttributeValues), State = CredentialState.Offered, ConnectionId = connection.GetId(), }; credentialRecord.Tags.Add(TagConstants.Nonce, nonce); credentialRecord.Tags.Add(TagConstants.Role, TagConstants.Issuer); credentialRecord.Tags.Add(TagConstants.ConnectionId, connection.GetId()); if (!string.IsNullOrEmpty(config.IssuerDid)) { credentialRecord.Tags.Add(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(wallet, credentialRecord); var credentialOffer = await MessageSerializer.PackSealedAsync <CredentialOfferMessage>( new CredentialOfferDetails { OfferJson = offerJson }, wallet, connection.MyVk, connection.TheirVk); credentialOffer.Type = MessageUtils.FormatDidMessageType(connection.TheirDid, MessageTypes.CredentialOffer); return(credentialOffer); }