예제 #1
0
        public async Task <ActionResult <IEnumerable <AttributeValue> > > IssueIdpAttributes(string issuer, [FromBody] IssueAttributesRequestDTO request)
        {
            if (request is null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            AccountDescriptor account          = _accountsService.GetByPublicKey(issuer.HexStringToByteArray());
            StatePersistency  statePersistency = _executionContextManager.ResolveStateExecutionServices(account.AccountId);

            IEnumerable <AttributeDefinition> attributeDefinitions = _dataAccessService.GetAttributesSchemeByIssuer(issuer, true)
                                                                     .Select(a => new AttributeDefinition
            {
                SchemeId      = a.IdentitiesSchemeId,
                AttributeName = a.AttributeName,
                SchemeName    = a.AttributeSchemeName,
                Alias         = a.Alias,
                Description   = a.Description,
                IsActive      = a.IsActive,
                IsRoot        = a.CanBeRoot
            });

            if (!attributeDefinitions.Any(a => a.IsRoot))
            {
                throw new NoRootAttributeSchemeDefinedException(issuer);
            }

            var issuanceInputDetails = GetValidatedIssuanceDetails(request, attributeDefinitions);

            Identity identity = CreateIdentityInDb(account, issuanceInputDetails);

            IssuanceDetailsDto issuanceDetails;

            if (!string.IsNullOrEmpty(request.PublicSpendKey) && !string.IsNullOrEmpty(request.PublicViewKey))
            {
                ConfidentialAccount targetAccount = new ConfidentialAccount
                {
                    PublicSpendKey = request.PublicSpendKey.HexStringToByteArray(),
                    PublicViewKey  = request.PublicViewKey.HexStringToByteArray()
                };

                issuanceDetails = await IssueIdpAttributesAsRoot(issuer, request.Protection, identity, issuanceInputDetails, account, targetAccount, statePersistency).ConfigureAwait(false);
            }
            else
            {
                issuanceDetails = await IssueIdpAttributesAsAssociated(issuer, identity, issuanceInputDetails, statePersistency).ConfigureAwait(false);
            }

            await _idenitiesHubContext.Clients.Group(account.AccountId.ToString()).SendAsync("RequestForIssuance", issuanceDetails);

            IIntegrationIdP integrationService = GetIntegrationService(account.AccountId);

            if (integrationService != null)
            {
                IssuanceDetails issuanceIntegration = new IssuanceDetails
                {
                    RootAttribute = new IssuanceDetails.IssuanceDetailsRoot
                    {
                        AttributeName         = issuanceDetails.RootAttribute.AttributeName,
                        AssetCommitment       = issuanceDetails.RootAttribute.AssetCommitment.HexStringToByteArray(),
                        OriginatingCommitment = issuanceDetails.RootAttribute.OriginatingCommitment.HexStringToByteArray(),
                        SurjectionProof       = issuanceDetails.RootAttribute.SurjectionProof.HexStringToByteArray()
                    },
                    AssociatedAttributes = issuanceDetails.AssociatedAttributes
                                           .Select(a =>
                                                   new IssuanceDetails.IssuanceDetailsAssociated
                    {
                        AttributeName           = a.AttributeName,
                        AssetCommitment         = a.AssetCommitment.HexStringToByteArray(),
                        BindingToRootCommitment = a.BindingToRootCommitment.HexStringToByteArray()
                    }).ToList()
                };

                integrationService.IssueAttributes(account.AccountId, issuanceIntegration);
            }

            var attributeValues = FillAttributeValues(request.Attributes, attributeDefinitions);

            return(Ok(attributeValues));

            #region Internal Functions

            IReadOnlyCollection <AttributeValue> FillAttributeValues(Dictionary <string, IssueAttributesRequestDTO.AttributeValue> attributes,
                                                                     IEnumerable <AttributeDefinition> attributeDefinitions)
            {
                List <AttributeValue> attributeValues = new List <AttributeValue>();
                var protectionAttrDefinition          = attributeDefinitions.FirstOrDefault(a => a.SchemeName == AttributesSchemes.ATTR_SCHEME_NAME_PASSWORD);

                foreach (var attributeName in attributes.Keys.Where(a => protectionAttrDefinition?.AttributeName != a))
                {
                    string content = attributes[attributeName].Value;

                    AttributeValue attributeValue = new AttributeValue
                    {
                        Value      = content,
                        Definition = attributeDefinitions.FirstOrDefault(d => d.AttributeName == attributeName)
                    };
                    attributeValues.Add(attributeValue);
                }

                return(new ReadOnlyCollection <AttributeValue>(attributeValues));
            }

            async Task <IssuanceDetailsDto> IssueIdpAttributesAsRoot(
                string issuer,
                IssuanceProtection protection,
                Identity identity,
                IEnumerable <AttributeIssuanceDetails> attributeIssuanceDetails,
                AccountDescriptor account,
                ConfidentialAccount targetAccount,
                StatePersistency statePersistency)
            {
                IssuanceDetailsDto issuanceDetails = new IssuanceDetailsDto();

                IEnumerable <IdentitiesScheme> identitiesSchemes = _dataAccessService.GetAttributesSchemeByIssuer(issuer, true);

                var rootAttributeDetails = attributeIssuanceDetails.First(a => a.Definition.IsRoot);

                byte[] rootAssetId = await _assetsService.GenerateAssetId(rootAttributeDetails.Definition.SchemeName, rootAttributeDetails.Value.Value, issuer).ConfigureAwait(false);

                IdentityAttribute rootAttribute = identity.Attributes.FirstOrDefault(a => a.AttributeName == rootAttributeDetails.Definition.AttributeName);

                if (!CreateRootAttributeIfNeeded(statePersistency, rootAttribute, rootAssetId))
                {
                    var  protectionAttribute = identity.Attributes.FirstOrDefault(a => a.AttributeName == AttributesSchemes.ATTR_SCHEME_NAME_PASSWORD);
                    bool res = VerifyProtectionAttribute(protectionAttribute,
                                                         protection.SignatureE.HexStringToByteArray(),
                                                         protection.SignatureS.HexStringToByteArray(),
                                                         protection.SessionCommitment.HexStringToByteArray());

                    if (!res)
                    {
                        _logger.Warning($"[{account.AccountId}]: Failed to verify Surjection Proofs of the Protection Attribute");
                        throw new ProtectionAttributeVerificationFailedException();
                    }
                }
                else
                {
                    issuanceDetails.AssociatedAttributes
                        = await IssueAssociatedAttributes(
                              attributeIssuanceDetails.Where(a => !a.Definition.IsRoot)
                              .ToDictionary(d => identity.Attributes.First(a => a.AttributeName == d.Definition.AttributeName).AttributeId, d => d),
                              statePersistency.TransactionsService,
                              issuer, rootAssetId).ConfigureAwait(false);
                }

                var packet = TransferAssetToUtxo(statePersistency.TransactionsService, targetAccount, rootAssetId);

                if (packet == null)
                {
                    _logger.Error($"[{account.AccountId}]: failed to transfer Root Attribute");
                    throw new RootAttributeTransferFailedException();
                }

                _dataAccessService.AddOrUpdateIdentityTarget(identity.IdentityId, targetAccount.PublicSpendKey.ToHexString(), targetAccount.PublicViewKey.ToHexString());

                issuanceDetails.RootAttribute = new IssuanceDetailsDto.IssuanceDetailsRoot
                {
                    AttributeName         = rootAttribute.AttributeName,
                    OriginatingCommitment = packet.SurjectionProof.AssetCommitments[0].ToHexString(),
                    AssetCommitment       = packet.TransferredAsset.AssetCommitment.ToHexString(),
                    SurjectionProof       = $"{packet.SurjectionProof.Rs.E.ToHexString()}{packet.SurjectionProof.Rs.S[0].ToHexString()}"
                };

                return(issuanceDetails);
            }

            async Task <IssuanceDetailsDto> IssueIdpAttributesAsAssociated(
                string issuer,
                Identity identity,
                IEnumerable <AttributeIssuanceDetails> attributeIssuanceDetails,
                StatePersistency statePersistency)
            {
                IssuanceDetailsDto issuanceDetails = new IssuanceDetailsDto();

                IdentitiesScheme rootScheme = _dataAccessService.GetRootIdentityScheme(issuer);

                IEnumerable <IdentitiesScheme> identitiesSchemes = _dataAccessService.GetAttributesSchemeByIssuer(issuer, true);
                var rootAttributeDetails = attributeIssuanceDetails.First(a => a.Definition.IsRoot);

                var packet = await IssueAssociatedAttribute(
                    rootScheme.AttributeSchemeName,
                    rootAttributeDetails.Value.Value,
                    rootAttributeDetails.Value.BlindingPointValue,
                    rootAttributeDetails.Value.BlindingPointRoot,
                    issuer,
                    statePersistency.TransactionsService).ConfigureAwait(false);

                _dataAccessService.UpdateIdentityAttributeCommitment(identity.Attributes.FirstOrDefault(a => a.AttributeName == rootScheme.AttributeName).AttributeId, packet.AssetCommitment);

                byte[] rootAssetId = _assetsService.GenerateAssetId(rootScheme.IdentitiesSchemeId, rootAttributeDetails.Value.Value);
                issuanceDetails.AssociatedAttributes = await IssueAssociatedAttributes(
                    attributeIssuanceDetails
                    .ToDictionary(d => identity.Attributes.First(a => a.AttributeName == d.Definition.AttributeName).AttributeId, d => d),
                    statePersistency.TransactionsService,
                    issuer, rootAssetId).ConfigureAwait(false);

                return(issuanceDetails);
            }
예제 #2
0
        public async Task <ActionStatus> IssueAttributes(long accountId, IssuanceDetails issuanceDetails)
        {
            ActionStatus actionStatus = new ActionStatus
            {
                IntegrationType   = Key,
                IntegrationAction = nameof(IssueAttributes),
                ActionSucceeded   = true
            };

            await _semaphoreSlim.WaitAsync();

            try
            {
                var privateKey = _dataAccessService.GetAccountKeyValue(accountId, "RskSecretKey");
                if (string.IsNullOrEmpty(privateKey))
                {
                    actionStatus.ActionSucceeded = false;
                    actionStatus.ErrorMsg        = $"Account {accountId} has no integration with {Key}";
                }
                else
                {
                    var account = new Account(privateKey);

                    actionStatus.IntegrationAddress = account.Address;

                    var web3 = new Web3(account, _integrationConfiguration.RpcUri);
                    var o10IdentityService = new O10IdentityService(web3, _integrationConfiguration.ContractAddress);

                    var issuers = await o10IdentityService.GetAllIssuersQueryAsync().ConfigureAwait(false);

                    if (!issuers.ReturnValue1.Any(issuers => issuers.Address.Equals(account.Address, StringComparison.InvariantCultureIgnoreCase)))
                    {
                        actionStatus.ActionSucceeded = false;
                        actionStatus.ErrorMsg        = $"Account with Id {accountId} not registered as an Identity Provider";
                    }
                    else
                    {
                        List <AttributeRecord> attributeRecords = new List <AttributeRecord>
                        {
                            new AttributeRecord
                            {
                                AttributeName     = issuanceDetails.RootAttribute.AttributeName,
                                AssetCommitment   = issuanceDetails.RootAttribute.AssetCommitment,
                                BindingCommitment = issuanceDetails.RootAttribute.OriginatingCommitment
                            }
                        };

                        foreach (var attr in issuanceDetails.AssociatedAttributes)
                        {
                            attributeRecords.Add(new AttributeRecord
                            {
                                AttributeName     = attr.AttributeName,
                                AssetCommitment   = attr.AssetCommitment,
                                BindingCommitment = attr.BindingToRootCommitment,
                                AttributeId       = new BigInteger(0),
                                Version           = new BigInteger(0)
                            });
                        }

                        var balance = await web3.Eth.GetBalance.SendRequestAsync(account.Address).ConfigureAwait(false);

                        var functionIssueAttributesHandler = web3.Eth.GetContractTransactionHandler <IssueAttributesFunction>();
                        IssueAttributesFunction func       = new IssueAttributesFunction
                        {
                            AttributeRecords = attributeRecords
                        };
                        var esimatedGas = await functionIssueAttributesHandler.EstimateGasAsync(_integrationConfiguration.ContractAddress, func).ConfigureAwait(false);

                        func.Gas = new BigInteger(esimatedGas.ToLong() * 100);
                        if (balance < func.Gas)
                        {
                            actionStatus.ActionSucceeded = false;
                            actionStatus.ErrorMsg        = "Not enough funds";
                        }
                        else
                        {
                            var receipt = await o10IdentityService.IssueAttributesRequestAndWaitForReceiptAsync(func.AttributeRecords).ConfigureAwait(false);

                            if (receipt.Failed())
                            {
                                actionStatus.ActionSucceeded = false;
                                actionStatus.ErrorMsg        = $"Transaction with hash {receipt.TransactionHash} failed";
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"{nameof(IssueAttributes)} failed for the acccount {accountId}", ex);
                actionStatus.ActionSucceeded = false;
                actionStatus.ErrorMsg        = ex.Message;
            }
            finally
            {
                _semaphoreSlim.Release();
            }

            return(actionStatus);
        }