public async Task CanDoBasicPostHttpsRequestAsync() { using var client = new TorHttpClient(new Uri("https://api.smartbit.com.au"), Global.Instance.TorSocks5Endpoint); HttpContent content = new StringContent("{\"hex\": \"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2d03a58605204d696e656420627920416e74506f6f6c20757361311f10b53620558903d80272a70c0000724c0600ffffffff010f9e5096000000001976a9142ef12bd2ac1416406d0e132e5bc8d0b02df3861b88ac00000000\"}"); HttpResponseMessage message = await client.SendAsync(HttpMethod.Post, "/v1/blockchain/decodetx", content); var responseContentString = await message.Content.ReadAsStringAsync(); Assert.Equal("{\"success\":true,\"transaction\":{\"Version\":\"1\",\"LockTime\":\"0\",\"Vin\":[{\"TxId\":null,\"Vout\":null,\"ScriptSig\":null,\"CoinBase\":\"03a58605204d696e656420627920416e74506f6f6c20757361311f10b53620558903d80272a70c0000724c0600\",\"TxInWitness\":null,\"Sequence\":\"4294967295\"}],\"Vout\":[{\"Value\":25.21865743,\"N\":0,\"ScriptPubKey\":{\"Asm\":\"OP_DUP OP_HASH160 2ef12bd2ac1416406d0e132e5bc8d0b02df3861b OP_EQUALVERIFY OP_CHECKSIG\",\"Hex\":\"76a9142ef12bd2ac1416406d0e132e5bc8d0b02df3861b88ac\",\"ReqSigs\":1,\"Type\":\"pubkeyhash\",\"Addresses\":[\"15HCzh8AoKRnTWMtmgAsT9TKUPrQ6oh9HQ\"]}}],\"TxId\":\"a02b9bd4264ab5d7c43ee18695141452b23b230b2a8431b28bbe446bf2b2f595\"}}", responseContentString); }
public async Task CanDoIpAddressAsync() { using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2)); TorHttpClient client = MakeTorHttpClient(new("http://172.217.6.142")); HttpResponseMessage httpResponseMessage = await client.SendAsync(HttpMethod.Get, relativeUri : "", content : null, ctsTimeout.Token); string content = await httpResponseMessage.Content.ReadAsStringAsync(ctsTimeout.Token); Assert.NotEmpty(content); }
public async Task CanRequestChunkEncodedAsync() { using var client = new TorHttpClient(new Uri("http://anglesharp.azurewebsites.net/"), Global.Instance.TorSocks5Endpoint); var response = await client.SendAsync(HttpMethod.Get, "Chunked"); var content = await response.Content.ReadAsStringAsync(); Assert.Contains("Chunked transfer encoding test", content); Assert.Contains("This is a chunked response after 100 ms.", content); Assert.Contains("This is a chunked response after 1 second. The server should not close the stream before all chunks are sent to a client.", content); }
public async Task CanRequestOnionV3Async() { using var client = new TorHttpClient(new Uri("http://dds6qkxpwdeubwucdiaord2xgbbeyds25rbsgr73tbfpqpt4a6vjwsyd.onion"), Global.Instance.TorSocks5Endpoint); HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, ""); var content = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Contains("whonix", content, StringComparison.OrdinalIgnoreCase); }
public async Task CanRequestOnionV2Async() { using var client = new TorHttpClient(new Uri("http://expyuzz4wqqyqhjn.onion/"), Global.Instance.TorSocks5Endpoint); HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, ""); var content = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Contains("tor", content, StringComparison.OrdinalIgnoreCase); }
public async Task CanRequestChunkEncodedAsync() { using (var client = new TorHttpClient(new Uri("https://jigsaw.w3.org/"))) { var response = await client.SendAsync(HttpMethod.Get, "/HTTP/ChunkedScript"); var content = await response.Content.ReadAsStringAsync(); Assert.Equal(1000, Regex.Matches(content, "01234567890123456789012345678901234567890123456789012345678901234567890").Count); } }
public async Task CanDoHttpsAsync() { using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2)); TorHttpClient client = MakeTorHttpClient(new("https://postman-echo.com")); using HttpResponseMessage httpResponseMessage = await client.SendAsync(HttpMethod.Get, "get?foo1=bar1&foo2=bar2", null, ctsTimeout.Token); var content = await httpResponseMessage.Content.ReadAsStringAsync(ctsTimeout.Token); Assert.Contains("{\"args\":{\"foo1\":\"bar1\",\"foo2\":\"bar2\"}", content); }
public async Task CanRequestOnionV3Async() { using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2)); TorHttpClient client = MakeTorHttpClient(new("http://www.dds6qkxpwdeubwucdiaord2xgbbeyds25rbsgr73tbfpqpt4a6vjwsyd.onion")); HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, "", null, ctsTimeout.Token); var content = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Contains("whonix", content, StringComparison.OrdinalIgnoreCase); }
public async Task CanRequestOnionAsync() { using (var client = new TorHttpClient(new Uri("https://www.facebookcorewwwi.onion/"))) { HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, ""); var content = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Contains("facebook", content, StringComparison.OrdinalIgnoreCase); } }
public async Task CanRequestOnionV2Async() { using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2)); TorHttpClient client = MakeTorHttpClient(new("http://expyuzz4wqqyqhjn.onion/")); HttpResponseMessage response = await client.SendAsync(HttpMethod.Get, relativeUri : "", null, ctsTimeout.Token); var content = await response.Content.ReadAsStringAsync(ctsTimeout.Token); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Contains("tor", content, StringComparison.OrdinalIgnoreCase); }
public async Task CanRequestChunkEncodedAsync() { using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2)); TorHttpClient client = MakeTorHttpClient(new("http://anglesharp.azurewebsites.net/")); var response = await client.SendAsync(HttpMethod.Get, "Chunked", null, ctsTimeout.Token); var content = await response.Content.ReadAsStringAsync(ctsTimeout.Token); Assert.Contains("Chunked transfer encoding test", content); Assert.Contains("This is a chunked response after 100 ms.", content); Assert.Contains("This is a chunked response after 1 second. The server should not close the stream before all chunks are sent to a client.", content); }
public async Task CanDoBasicPostHttpsRequestAsync() { using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2)); TorHttpClient client = MakeTorHttpClient(new("https://postman-echo.com")); using HttpContent content = new StringContent("This is expected to be sent back as part of response body."); HttpResponseMessage message = await client.SendAsync(HttpMethod.Post, "post", content, ctsTimeout.Token); var responseContentString = await message.Content.ReadAsStringAsync(ctsTimeout.Token); Assert.Contains("{\"args\":{},\"data\":\"This is expected to be sent back as part of response body.\"", responseContentString); }
public async Task CanDoBasicPostRequestWithNonAsciiCharsAsync() { using (var client = new TorHttpClient(new Uri("http://httpbin.org"))) { string json = "Hello ñ"; var httpContent = new StringContent(json, Encoding.UTF8, "application/json"); HttpResponseMessage message = await client.SendAsync(HttpMethod.Post, "post", httpContent); var responseContentString = await message.Content.ReadAsStringAsync(); Assert.Contains(@"Hello \u00f1", responseContentString); } }
public async Task BroadcastInvalidTxAsync() { await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1); var content = new StringContent($"''", Encoding.UTF8, "application/json"); Logger.TurnOff(); using (var client = new TorHttpClient(new Uri(RegTestFixture.BackendEndPoint), null)) using (var response = await client.SendAsync(HttpMethod.Post, $"/api/v{WalletWasabi.Helpers.Constants.BackendMajorVersion}/btc/blockchain/broadcast", content)) { Assert.NotEqual(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); Assert.Contains("The hex field is required.", await response.Content.ReadAsStringAsync()); } Logger.TurnOn(); }
public async Task GetExchangeRatesAsync() { using var client = new TorHttpClient(new Uri(RegTestFixture.BackendEndPoint), null); using var response = await client.SendAsync(HttpMethod.Get, $"/api/v{WalletWasabi.Helpers.Constants.BackendMajorVersion}/btc/offchain/exchange-rates"); Assert.True(response.StatusCode == HttpStatusCode.OK); var exchangeRates = await response.Content.ReadAsJsonAsync <List <ExchangeRate> >(); Assert.Single(exchangeRates); var rate = exchangeRates[0]; Assert.Equal("USD", rate.Ticker); Assert.True(rate.Rate > 0); }
public async Task CanDoBasicPostRequestAsync() { using (var client = new TorHttpClient(new Uri("http://httpbin.org"))) { HttpContent content = new FormUrlEncodedContent(new[] { new KeyValuePair <string, string>("foo", "bar@98") }); HttpResponseMessage message = await client.SendAsync(HttpMethod.Post, "post", content); var responseContentString = await message.Content.ReadAsStringAsync(); Assert.Contains("bar@98", responseContentString); } }
public async Task BroadcastInvalidTxAsync() { (string password, IRPCClient rpc, Network network, Coordinator coordinator, ServiceConfiguration serviceConfiguration, BitcoinStore bitcoinStore, Backend.Global global) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1); var content = new StringContent($"''", Encoding.UTF8, "application/json"); Logger.TurnOff(); using (var client = new TorHttpClient(new Uri(RegTestFixture.BackendEndPoint), null)) using (var response = await client.SendAsync(HttpMethod.Post, $"/api/v{Constants.BackendMajorVersion}/ltc/blockchain/broadcast", content)) { Assert.NotEqual(HttpStatusCode.OK, response.StatusCode); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); Assert.Equal("Invalid hex.", await response.Content.ReadAsJsonAsync <string>()); } Logger.TurnOn(); }
public static async Task <HttpResponseMessage> SendAndRetryAsync(this TorHttpClient client, HttpMethod method, HttpStatusCode expectedCode, string relativeUri, int retry = 2, HttpContent content = null) { HttpResponseMessage response = null; while (retry-- > 0) { response?.Dispose(); response = await client.SendAsync(method, relativeUri, content); if (response.StatusCode == expectedCode) { break; } await Task.Delay(1000); } return(response); }
public async Task DoesntIsolateStreamsAsync() { using var c1 = new TorHttpClient(new Uri("http://api.ipify.org"), Common.TorSocks5Endpoint); using var c2 = new TorHttpClient(new Uri("http://api.ipify.org"), Common.TorSocks5Endpoint); using var c3 = new TorHttpClient(new Uri("http://api.ipify.org"), Common.TorSocks5Endpoint); var t1 = c1.SendAsync(HttpMethod.Get, ""); var t2 = c2.SendAsync(HttpMethod.Get, ""); var t3 = c3.SendAsync(HttpMethod.Get, ""); var ips = new HashSet <IPAddress> { IPAddress.Parse(await(await t1).Content.ReadAsStringAsync()), IPAddress.Parse(await(await t2).Content.ReadAsStringAsync()), IPAddress.Parse(await(await t3).Content.ReadAsStringAsync()) }; Assert.True(ips.Count < 3); }
public async Task IsolatesStreamsAsync() { using var c1 = new TorHttpClient(new Uri("http://api.ipify.org"), Global.Instance.TorSocks5Endpoint, isolateStream: true); using var c2 = new TorHttpClient(new Uri("http://api.ipify.org"), Global.Instance.TorSocks5Endpoint, isolateStream: true); using var c3 = new TorHttpClient(new Uri("http://api.ipify.org"), Global.Instance.TorSocks5Endpoint, isolateStream: true); var t1 = c1.SendAsync(HttpMethod.Get, ""); var t2 = c2.SendAsync(HttpMethod.Get, ""); var t3 = c3.SendAsync(HttpMethod.Get, ""); var ips = new HashSet <IPAddress> { IPAddress.Parse(await(await t1).Content.ReadAsStringAsync()), IPAddress.Parse(await(await t2).Content.ReadAsStringAsync()), IPAddress.Parse(await(await t3).Content.ReadAsStringAsync()) }; Assert.True(ips.Count >= 2); // very rarely it fails to isolate }
public async Task BroadcastReplayTxAsync() { (_, IRPCClient rpc, _, _, _, _, _) = await Common.InitializeTestEnvironmentAsync(RegTestFixture, 1); var utxos = await rpc.ListUnspentAsync(); var utxo = utxos[0]; var tx = await rpc.GetRawTransactionAsync(utxo.OutPoint.Hash); var content = new StringContent($"'{tx.ToHex()}'", Encoding.UTF8, "application/json"); Logger.TurnOff(); using (var client = new TorHttpClient(new Uri(RegTestFixture.BackendEndPoint), null)) using (var response = await client.SendAsync(HttpMethod.Post, $"/api/v{WalletWasabi.Helpers.Constants.BackendMajorVersion}/btc/blockchain/broadcast", content)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("Transaction is already in the blockchain.", await response.Content.ReadAsJsonAsync <string>()); } Logger.TurnOn(); }
public async Task IsolatesStreamsAsync() { using CancellationTokenSource ctsTimeout = new(TimeSpan.FromMinutes(2)); TorHttpClient c1 = MakeTorHttpClient(new("http://api.ipify.org"), Mode.NewCircuitPerRequest); TorHttpClient c2 = MakeTorHttpClient(new("http://api.ipify.org"), Mode.NewCircuitPerRequest); TorHttpClient c3 = MakeTorHttpClient(new("http://api.ipify.org"), Mode.NewCircuitPerRequest); Task <HttpResponseMessage> t1 = c1.SendAsync(HttpMethod.Get, "", null, ctsTimeout.Token); Task <HttpResponseMessage> t2 = c2.SendAsync(HttpMethod.Get, "", null, ctsTimeout.Token); Task <HttpResponseMessage> t3 = c3.SendAsync(HttpMethod.Get, "", null, ctsTimeout.Token); var ips = new HashSet <IPAddress> { IPAddress.Parse(await(await t1).Content.ReadAsStringAsync(ctsTimeout.Token)), IPAddress.Parse(await(await t2).Content.ReadAsStringAsync(ctsTimeout.Token)), IPAddress.Parse(await(await t3).Content.ReadAsStringAsync(ctsTimeout.Token)) }; Assert.True(ips.Count >= 2); // very rarely it fails to isolate }
private async Task TorIpIsNotTheRealOneAsync() { var requestUri = "https://api.ipify.org/"; IPAddress realIp; IPAddress torIp; // 1. Get real IP using (var httpClient = new HttpClient()) { var content = await(await httpClient.GetAsync(requestUri)).Content.ReadAsStringAsync(); var gotIp = IPAddress.TryParse(content.Replace("\n", ""), out realIp); Assert.True(gotIp); } // 2. Get Tor IP using (var client = new TorHttpClient(new Uri(requestUri))) { var content = await(await client.SendAsync(HttpMethod.Get, "")).Content.ReadAsStringAsync(); var gotIp = IPAddress.TryParse(content.Replace("\n", ""), out torIp); Assert.True(gotIp); } Assert.NotEqual(realIp, torIp); }
public void StartMonitor(TimeSpan torMisbehaviorCheckPeriod, TimeSpan checkIfRunningAfterTorMisbehavedFor, Uri fallBackTestRequestUri) { Logger.LogInfo("Starting Tor monitor..."); if (Interlocked.CompareExchange(ref _monitorState, StateRunning, StateNotStarted) != StateNotStarted) { return; } Task.Run(async() => { try { while (IsRunning) { try { await Task.Delay(torMisbehaviorCheckPeriod, Stop.Token).ConfigureAwait(false); if (TorHttpClient.TorDoesntWorkSince is { }) // If Tor misbehaves. { TimeSpan torMisbehavedFor = DateTimeOffset.UtcNow - TorHttpClient.TorDoesntWorkSince ?? TimeSpan.Zero; if (torMisbehavedFor > checkIfRunningAfterTorMisbehavedFor) { if (TorHttpClient.LatestTorException is TorSocks5FailureResponseException torEx) { if (torEx.RepField == RepField.HostUnreachable) { Uri baseUri = new Uri($"{fallBackTestRequestUri.Scheme}://{fallBackTestRequestUri.DnsSafeHost}"); using (var client = new TorHttpClient(baseUri, TorSocks5EndPoint)) { var message = new HttpRequestMessage(HttpMethod.Get, fallBackTestRequestUri); await client.SendAsync(message, Stop.Token).ConfigureAwait(false); } // Check if it changed in the meantime... if (TorHttpClient.LatestTorException is TorSocks5FailureResponseException torEx2 && torEx2.RepField == RepField.HostUnreachable) { // Fallback here... RequestFallbackAddressUsage = true; } } } else { Logger.LogInfo($"Tor did not work properly for {(int)torMisbehavedFor.TotalSeconds} seconds. Maybe it crashed. Attempting to start it..."); await StartAsync(ensureRunning: true).ConfigureAwait(false); // Try starting Tor, if it does not work it'll be another issue. } } } } catch (Exception ex) when(ex is OperationCanceledException || ex is TaskCanceledException || ex is TimeoutException) { Logger.LogTrace(ex); } catch (Exception ex) { Logger.LogDebug(ex); } } }