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); }
/// <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)); } }
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)); }
/// <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); }
/// <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); }