protected override Task <OcelotConfigurationContentRaw> FetchDataImpl(string latestVersion)
        {
            var signedUri = SigningUtils
                            .SignUriForGoogleCloudStorage(_config.BucketName, _config.ObjectName, _config.AccessKey, _config.Secret);

            return(GetWithHttpAndETAG(latestVersion, signedUri));
        }
        /// <summary>This is the main code to sign a request.</summary>
        /// <param name="requestMessage">An HttpRequestMessage to be signed.</param>
        public void SignRequest(HttpRequestMessage requestMessage)
        {
            HttpMethod         httpMethod       = requestMessage.Method;
            HttpRequestHeaders httpHeaders      = requestMessage.Headers;
            HttpContent        body             = requestMessage.Content;
            string             requestMethodKey = httpMethod.Method.ToLowerInvariant();

            // Verify if the http request Method is supported.
            if (!signingStrategy.RequiredHeaders.TryGetValue(requestMethodKey, out var requiredHeaders))
            {
                throw new ArgumentException($"Http Request Method not found: {requestMethodKey}");
            }

            var headersToSign = requiredHeaders.ToList();

            // Add any missing required headers.
            SigningUtils.AddMissingHeaders(requestMessage, headersToSign);

            // Calculate the Signing string.
            var signingString = SigningUtils.CalculateStringToSign(requestMessage, headersToSign);

            logger.Debug($"signing string is {signingString}");

            var bytes = Encoding.UTF8.GetBytes(signingString);

            this.signer.BlockUpdate(bytes, 0, bytes.Length);
            var signature = Convert.ToBase64String(this.signer.GenerateSignature());

            var authorization = SigningUtils.CalculateAuthorization(headersToSign, SIGNATURE_VERSION, this.keyId, SIGNATURE_ALGORITHM, signature);

            httpHeaders.Add(Constants.AUTHORIZATION_HEADER, authorization);
        }
Exemplo n.º 3
0
        /// <inheritdoc />
        public ConsolidationSignatureResult CombineSignatures(Transaction incomingPartialTransaction)
        {
            lock (this.txLock)
            {
                // Nothing to sign.
                if (this.ConsolidationTransactions == null)
                {
                    return(ConsolidationSignatureResult.Failed());
                }

                // Get matching in-memory transaction.
                ConsolidationTransaction inMemoryTransaction = this.GetInMemoryConsolidationTransaction(incomingPartialTransaction);

                // Transaction doesn't exist or need signing.
                if (inMemoryTransaction == null || inMemoryTransaction.Status != ConsolidationTransactionStatus.Partial)
                {
                    return(ConsolidationSignatureResult.Failed());
                }

                // Attempt to merge signatures
                var         builder        = new TransactionBuilder(this.network);
                Transaction oldTransaction = inMemoryTransaction.PartialTransaction;

                this.logger.Debug("Attempting to merge signatures for '{0}' and '{1}'.", inMemoryTransaction.PartialTransaction.GetHash(), incomingPartialTransaction.GetHash());

                Transaction newTransaction = SigningUtils.CheckTemplateAndCombineSignatures(builder, inMemoryTransaction.PartialTransaction, new[] { incomingPartialTransaction });

                if (oldTransaction.GetHash() == newTransaction.GetHash())
                {
                    // Signing didn't work if the hash is still the same
                    this.logger.Debug("Signing failed.");
                    return(ConsolidationSignatureResult.Failed());
                }

                this.logger.Debug("Successfully signed transaction.");
                inMemoryTransaction.PartialTransaction = newTransaction;

                // NOTE: We don't need to reserve the transaction. The wallet will be at a standstill whilst this is happening.

                // If it is FullySigned, broadcast.
                if (this.walletManager.ValidateConsolidatingTransaction(inMemoryTransaction.PartialTransaction, true))
                {
                    inMemoryTransaction.Status = ConsolidationTransactionStatus.FullySigned;
                    this.logger.Debug("Consolidation transaction is fully signed. Broadcasting '{0}'", inMemoryTransaction.PartialTransaction.GetHash());
                    this.broadcasterManager.BroadcastTransactionAsync(inMemoryTransaction.PartialTransaction).GetAwaiter().GetResult();
                    return(ConsolidationSignatureResult.Succeeded(inMemoryTransaction.PartialTransaction));
                }

                this.logger.Debug("Consolidation transaction not fully signed yet.");

                return(ConsolidationSignatureResult.Succeeded(inMemoryTransaction.PartialTransaction));
            }
        }
Exemplo n.º 4
0
        protected override Task <OcelotConfigurationContentRaw> FetchDataImpl(string latestVersion)
        {
            string signedUri = null;
            var    type      = _config.Type == AzureStorageConfigurationType.Blob ? "blob" : "file";

            switch (_config.AccessType)
            {
            case AzureStorageConfigurationAccessType.SharedKey:
                signedUri = SigningUtils.SignUriForAzureStorage(_config.AccountName, _config.AccountKey, _config.ResourceUri, type);
                break;

            case AzureStorageConfigurationAccessType.SignedUri:
                signedUri = _config.ResourceUri;
                break;

            default:
                throw new InvalidOperationException($"AccessType {_config.AccessType} is not valid");
            }

            return(GetWithHttpAndETAG(latestVersion, signedUri));
        }
Exemplo n.º 5
0
        /// <summary>
        /// Creates a transaction to transfers funds from an old federation to a new federation.
        /// </summary>
        /// <param name="isSideChain">Indicates whether the <paramref name="network"/> is the sidechain.</param>
        /// <param name="network">The network that we are creating the recovery transaction for.</param>
        /// <param name="counterChainNetwork">The counterchain network.</param>
        /// <param name="dataDirPath">The root folder containing the old federation.</param>
        /// <param name="redeemScript">The new redeem script.</param>
        /// <param name="password">The password required to generate transactions using the federation wallet.</param>
        /// <param name="txTime">Any deposits beyond this UTC date will be ignored when selecting coin inputs.</param>
        /// <returns>A funds recovery transaction that moves funds to the new redeem script.</returns>
        public FundsRecoveryTransactionModel CreateFundsRecoveryTransaction(bool isSideChain, Network network, Network counterChainNetwork, string dataDirPath, Script redeemScript, string password, DateTime txTime)
        {
            var model = new FundsRecoveryTransactionModel()
            {
                Network = network, IsSideChain = isSideChain, RedeemScript = redeemScript
            };

            // Get the old redeem script from the wallet file.
            PayToMultiSigTemplateParameters multisigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(redeemScript);
            string           theChain          = isSideChain ? "sidechain" : "mainchain";
            var              nodeSettings      = new NodeSettings(network, args: new string[] { $"datadir={dataDirPath}", $"redeemscript={redeemScript}", $"-{theChain}" });
            var              walletFileStorage = new FileStorage <FederationWallet>(nodeSettings.DataFolder.WalletPath);
            FederationWallet wallet            = walletFileStorage.LoadByFileName("multisig_wallet.json");
            Script           oldRedeemScript   = wallet.MultiSigAddress.RedeemScript;
            PayToMultiSigTemplateParameters oldMultisigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(oldRedeemScript);

            model.oldMultisigAddress = oldRedeemScript.Hash.GetAddress(network);
            model.newMultisigAddress = redeemScript.Hash.GetAddress(network);

            // Create dummy inputs to avoid errors when constructing FederatedPegSettings.
            var extraArgs = new Dictionary <string, string>();

            extraArgs[FederatedPegSettings.FederationIpsParam] = oldMultisigParams.PubKeys.Select(p => "0.0.0.0".ToIPEndPoint(nodeSettings.Network.DefaultPort)).Join(",");
            var privateKey = Key.Parse(wallet.EncryptedSeed, password, network);

            extraArgs[FederatedPegSettings.PublicKeyParam] = privateKey.PubKey.ToHex(network);
            (new TextFileConfiguration(extraArgs.Select(i => $"{i.Key}={i.Value}").ToArray())).MergeInto(nodeSettings.ConfigReader);

            model.PubKey = privateKey.PubKey;

            var dBreezeSerializer = new DBreezeSerializer(network.Consensus.ConsensusFactory);
            var blockStore        = new BlockRepository(network, nodeSettings.DataFolder, nodeSettings.LoggerFactory, dBreezeSerializer);

            blockStore.Initialize();

            var           chain        = new ChainRepository(nodeSettings.DataFolder, nodeSettings.LoggerFactory, dBreezeSerializer);
            Block         genesisBlock = network.GetGenesis();
            ChainedHeader tip          = chain.LoadAsync(new ChainedHeader(genesisBlock.Header, genesisBlock.GetHash(), 0)).GetAwaiter().GetResult();
            var           chainIndexer = new ChainIndexer(network, tip);

            var nodeLifetime = new NodeLifetime();
            IDateTimeProvider dateTimeProvider = DateTimeProvider.Default;
            var federatedPegSettings           = new FederatedPegSettings(nodeSettings);
            var opReturnDataReader             = new OpReturnDataReader(nodeSettings.LoggerFactory, new CounterChainNetworkWrapper(counterChainNetwork));
            var walletFeePolicy = new WalletFeePolicy(nodeSettings);

            var walletManager = new FederationWalletManager(nodeSettings.LoggerFactory, network, chainIndexer, nodeSettings.DataFolder, walletFeePolicy,
                                                            new AsyncProvider(nodeSettings.LoggerFactory, new Signals(nodeSettings.LoggerFactory, new DefaultSubscriptionErrorHandler(nodeSettings.LoggerFactory)), nodeLifetime), nodeLifetime,
                                                            dateTimeProvider, federatedPegSettings, new WithdrawalExtractor(nodeSettings.LoggerFactory, federatedPegSettings, opReturnDataReader, network), blockStore);

            walletManager.Start();
            walletManager.EnableFederationWallet(password);

            if (!walletManager.IsFederationWalletActive())
            {
                throw new ArgumentException($"Could not activate the federation wallet on {network}.");
            }

            // Retrieves the unspent outputs in deterministic order.
            List <Stratis.Features.FederatedPeg.Wallet.UnspentOutputReference> coinRefs = walletManager.GetSpendableTransactionsInWallet().ToList();

            // Exclude coins (deposits) beyond the transaction (switch-over) time!
            coinRefs = coinRefs.Where(r => r.Transaction.CreationTime < txTime).ToList();
            if (!coinRefs.Any())
            {
                throw new ArgumentException($"There are no coins to recover from the federation wallet on {network}.");
            }

            Money fee = federatedPegSettings.GetWithdrawalTransactionFee(coinRefs.Count());

            var builder = new TransactionBuilder(network);

            builder.AddKeys(privateKey);
            builder.AddCoins(coinRefs.Select(c => ScriptCoin.Create(network, c.Transaction.Id, (uint)c.Transaction.Index, c.Transaction.Amount, c.Transaction.ScriptPubKey, oldRedeemScript)));

            // Split the coins into multiple outputs.
            Money     amount         = coinRefs.Sum(r => r.Transaction.Amount) - fee;
            const int numberOfSplits = 10;
            Money     splitAmount    = new Money((long)amount / numberOfSplits);
            var       recipients     = new List <Stratis.Features.FederatedPeg.Wallet.Recipient>();

            for (int i = 0; i < numberOfSplits; i++)
            {
                Money sendAmount = (i != (numberOfSplits - 1)) ? splitAmount : amount - splitAmount * (numberOfSplits - 1);

                builder.Send(redeemScript.PaymentScript, sendAmount);
            }

            builder.SetTimeStamp((uint)(new DateTimeOffset(txTime)).ToUnixTimeSeconds());
            builder.CoinSelector = new DeterministicCoinSelector();
            builder.SendFees(fee);

            model.tx = builder.BuildTransaction(true);

            File.WriteAllText(Path.Combine(dataDirPath, $"{network.Name}_{model.PubKey.ToHex(network).Substring(0, 8)}.hex"), model.tx.ToHex(network));

            // Merge our transaction with other transactions which have been placed in the data folder.
            Transaction oldTransaction = model.tx;
            string      namePattern    = $"{network.Name}_*.hex";
            int         sigCount       = 1;

            foreach (string fileName in Directory.EnumerateFiles(dataDirPath, namePattern))
            {
                Transaction incomingPartialTransaction = network.CreateTransaction(File.ReadAllText(fileName));

                // Don't merge with self.
                if (incomingPartialTransaction.GetHash() == oldTransaction.GetHash())
                {
                    continue;
                }

                // Transaction times must match.
                if (incomingPartialTransaction is PosTransaction && incomingPartialTransaction.Time != model.tx.Time)
                {
                    Console.WriteLine($"The locally generated transaction is time-stamped differently from the transaction contained in '{fileName}'. The imported signature can't be used.");
                    continue;
                }

                // Combine signatures.
                Transaction newTransaction = SigningUtils.CheckTemplateAndCombineSignatures(builder, model.tx, new[] { incomingPartialTransaction });

                if (oldTransaction.GetHash() == newTransaction.GetHash())
                {
                    Console.WriteLine($"The locally generated transaction is not similar to '{fileName}'. The imported signature can't be used.");
                    continue;
                }

                model.tx = newTransaction;
                sigCount++;
            }

            Console.WriteLine($"{sigCount} of {multisigParams.SignatureCount} signatures collected for {network.Name}.");

            if (sigCount >= multisigParams.SignatureCount)
            {
                if (builder.Verify(model.tx))
                {
                    // Write the transaction to file.
                    File.WriteAllText(Path.Combine(dataDirPath, $"{(txTime > DateTime.Now ? "Preliminary " : "")}{network.Name}Recovery.txt"), model.tx.ToHex(network));
                }
                else
                {
                    Console.WriteLine("Could not verify the transaction.");
                }
            }

            // Stop the wallet manager to release the database folder.
            nodeLifetime.StopApplication();
            walletManager.Stop();

            return(model);
        }
Exemplo n.º 6
0
        /// <summary>This is the main code to sign a request.</summary>
        /// <param name="requestMessage">An HttpRequestMessage to be signed.</param>
        public override void SignRequest(HttpRequestMessage requestMessage)
        {
            HttpMethod         httpMethod       = requestMessage.Method;
            HttpRequestHeaders httpHeaders      = requestMessage.Headers;
            HttpContent        body             = requestMessage.Content;
            string             requestMethodKey = httpMethod.Method.ToLowerInvariant();

            // Verify if the http request Method is supported.
            if (!signingStrategy.RequiredHeaders.TryGetValue(requestMethodKey, out var requiredHeaders))
            {
                throw new ArgumentException($"Http Request Method not found: {requestMethodKey}");
            }

            var headersToSign = requiredHeaders.ToList();
            //Add the Instance OBO User delegation token to request headers if the auth details provider implements IUserDelegationDetailsProvider and
            //if a token is available.
            var delegationToken = (AuthDetailsProvider as IUserDelegationDetailsProvider)?.GetDelegationToken();

            if (delegationToken != null)
            {
                logger.Debug($"Adding {Constants.OPC_OBO_TOKEN} to request headers");
                requestMessage.Headers.TryAddWithoutValidation(Constants.OPC_OBO_TOKEN, delegationToken);
            }

            // For PUT and POST, if the body is empty we still must explicitly set content-length = 0 and x-content-sha256.
            // The caller may already do this, but we shouldn't require it since we can determine it here.
            if (body == null && (string.Equals(requestMethodKey, "post") || string.Equals(requestMethodKey, "put")))
            {
                requestMessage.Content = new StringContent("");
                requestMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                requestMessage.Content.Headers.TryAddWithoutValidation(Constants.CONTENT_LENGTH, "0");
                requestMessage.Content.Headers.TryAddWithoutValidation(Constants.X_CONTENT_SHA256, Convert.ToBase64String(SHA256.Create().ComputeHash(new byte[0])));
            }

            // Few requests accept Constants.OPTIONAL_HEADERS_NAMES headers. In such cases, if the request contains any of the optional headers,
            // we need to include them in request signature.
            if (signingStrategy.OptionalHeaders.TryGetValue(requestMethodKey, out var optionalHeaders))
            {
                foreach (var optionalHeaderName in optionalHeaders)
                {
                    if (httpHeaders.Contains(optionalHeaderName))
                    {
                        headersToSign.Add(optionalHeaderName);
                    }
                }
            }

            // Add any missing required headers.
            SigningUtils.AddMissingHeaders(requestMessage, headersToSign);

            // Calculate the Signing string.
            var signingString = SigningUtils.CalculateStringToSign(requestMessage, headersToSign);
            var bytes         = Encoding.UTF8.GetBytes(signingString);

            this.signer.BlockUpdate(bytes, 0, bytes.Length);
            var signature = Convert.ToBase64String(this.signer.GenerateSignature());

            var authorization = SigningUtils.CalculateAuthorization(headersToSign, SIGNATURE_VERSION, this.keyId, SIGNATURE_ALGORITHM, signature);

            httpHeaders.Add(Constants.AUTHORIZATION_HEADER, authorization);
        }