WIP: tor http connection

This commit is contained in:
ryleedavis 2023-09-08 16:53:09 -06:00
parent f240163a91
commit dea35fd801
6 changed files with 168 additions and 70 deletions

View file

@ -5,20 +5,22 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:http/http.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
import 'package:stackwallet/models/isar/ordinal.dart';
import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/amount/amount_formatter.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/utilities/show_loading.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/background.dart';
@ -230,11 +232,16 @@ class _OrdinalImageGroup extends StatelessWidget {
static const _spacing = 12.0;
Future<String> _savePngToFile() async {
final response = await get(Uri.parse(ordinal.content));
HTTP client = HTTP();
if (response.statusCode != 200) {
throw Exception(
"statusCode=${response.statusCode} body=${response.bodyBytes}");
final response = await client.get(
url: Uri.parse(ordinal.content),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.code != 200) {
throw Exception("statusCode=${response.code} body=${response.bodyBytes}");
}
final bytes = response.bodyBytes;

View file

@ -3,21 +3,23 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:http/http.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
import 'package:stackwallet/models/isar/ordinal.dart';
import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
import 'package:stackwallet/providers/db/main_db_provider.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/themes/stack_colors.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/amount/amount_formatter.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/utilities/show_loading.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
@ -50,11 +52,16 @@ class _DesktopOrdinalDetailsViewState
late final UTXO? utxo;
Future<String> _savePngToFile() async {
final response = await get(Uri.parse(widget.ordinal.content));
HTTP client = HTTP();
if (response.statusCode != 200) {
throw Exception(
"statusCode=${response.statusCode} body=${response.bodyBytes}");
final response = await client.get(
url: Uri.parse(widget.ordinal.content),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.code != 200) {
throw Exception("statusCode=${response.code} body=${response.bodyBytes}");
}
final bytes = response.bodyBytes;

View file

@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:convert';
import 'package:decimal/decimal.dart';
import 'package:http/http.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/balance.dart';
@ -11,6 +10,7 @@ import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'
import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart';
import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/services/coins/coin_service.dart';
import 'package:stackwallet/services/event_bus/events/global/node_connection_status_changed_event.dart';
import 'package:stackwallet/services/event_bus/events/global/updated_in_background_event.dart';
@ -19,6 +19,7 @@ import 'package:stackwallet/services/event_bus/global_event_bus.dart';
import 'package:stackwallet/services/mixins/wallet_cache.dart';
import 'package:stackwallet/services/mixins/wallet_db.dart';
import 'package:stackwallet/services/node_service.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/constants.dart';
@ -101,6 +102,8 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override
bool get shouldAutoSync => _shouldAutoSync;
HTTP client = HTTP();
@override
set shouldAutoSync(bool shouldAutoSync) {
if (_shouldAutoSync != shouldAutoSync) {
@ -239,7 +242,12 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override
Future<Amount> estimateFeeFor(Amount amount, int feeRate) async {
var api = "https://api.tzstats.com/series/op?start_date=today&collapse=1d";
var response = jsonDecode((await get(Uri.parse(api))).body)[0];
var response = jsonDecode((await client.get(
url: Uri.parse(api),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
))
.body)[0];
double totalFees = response[4] as double;
int totalTxs = response[8] as int;
int feePerTx = (totalFees / totalTxs * 1000000).floor();
@ -259,7 +267,12 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override
Future<FeeObject> get fees async {
var api = "https://api.tzstats.com/series/op?start_date=today&collapse=10d";
var response = jsonDecode((await get(Uri.parse(api))).body);
var response = jsonDecode((await client.get(
url: Uri.parse(api),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
))
.body);
double totalFees = response[0][4] as double;
int totalTxs = response[0][8] as int;
int feePerTx = (totalFees / totalTxs * 1000000).floor();
@ -493,8 +506,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
try {
String balanceCall = "https://api.mainnet.tzkt.io/v1/accounts/"
"${await currentReceivingAddress}/balance";
var response = jsonDecode(
await get(Uri.parse(balanceCall)).then((value) => value.body));
var response = jsonDecode(await client
.get(
url: Uri.parse(balanceCall),
proxyInfo: Prefs.instance.useTor
? TorService.sharedInstance.proxyInfo
: null,
)
.then((value) => value.body));
Amount balanceInAmount = Amount(
rawValue: BigInt.parse(response.toString()),
fractionDigits: coin.decimals);
@ -516,8 +535,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<void> updateTransactions() async {
String transactionsCall = "https://api.mainnet.tzkt.io/v1/accounts/"
"${await currentReceivingAddress}/operations";
var response = jsonDecode(
await get(Uri.parse(transactionsCall)).then((value) => value.body));
var response = jsonDecode(await client
.get(
url: Uri.parse(transactionsCall),
proxyInfo: Prefs.instance.useTor
? TorService.sharedInstance.proxyInfo
: null,
)
.then((value) => value.body));
List<Tuple2<Transaction, Address>> txs = [];
for (var tx in response as List) {
if (tx["type"] == "transaction") {
@ -591,8 +616,14 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
Future<void> updateChainHeight() async {
try {
var api = "${getCurrentNode().host}/chains/main/blocks/head/header/shell";
var jsonParsedResponse =
jsonDecode(await get(Uri.parse(api)).then((value) => value.body));
var jsonParsedResponse = jsonDecode(await client
.get(
url: Uri.parse(api),
proxyInfo: Prefs.instance.useTor
? TorService.sharedInstance.proxyInfo
: null,
)
.then((value) => value.body));
final int intHeight = int.parse(jsonParsedResponse["level"].toString());
Logging.instance.log("Chain height: $intHeight", level: LogLevel.Info);
await updateCachedChainHeight(intHeight);
@ -672,8 +703,12 @@ class TezosWallet extends CoinServiceAPI with WalletCache, WalletDB {
@override
Future<bool> testNetworkConnection() async {
try {
await get(Uri.parse(
"${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell"));
await client.get(
url: Uri.parse(
"${getCurrentNode().host}:${getCurrentNode().port}/chains/main/blocks/head/header/shell"),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
return true;
} catch (e) {
return false;

View file

@ -17,11 +17,14 @@ import 'package:stackwallet/dto/ethereum/eth_tx_dto.dart';
import 'package:stackwallet/dto/ethereum/pending_eth_tx_dto.dart';
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
import 'package:stackwallet/models/paymint/fee_object_model.dart';
import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/eth_commons.dart';
import 'package:stackwallet/utilities/extensions/extensions.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'package:tuple/tuple.dart';
class EthApiException implements Exception {
@ -46,19 +49,23 @@ class EthereumResponse<T> {
abstract class EthereumAPI {
static String get stackBaseServer => DefaultNodes.ethereum.host;
static HTTP client = HTTP();
static Future<EthereumResponse<List<EthTxDTO>>> getEthTransactions({
required String address,
int firstBlock = 0,
bool includeTokens = false,
}) async {
try {
final response = await get(
Uri.parse(
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/export?addrs=$address&firstBlock=$firstBlock",
),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
if (response.body.isNotEmpty) {
final json = jsonDecode(response.body) as Map;
final list = json["data"] as List?;
@ -86,7 +93,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getEthTransactions($address) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -173,13 +180,15 @@ abstract class EthereumAPI {
List<EthTxDTO> txns,
) async {
try {
final response = await get(
Uri.parse(
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/transactions?transactions=${txns.map((e) => e.hash).join(" ")}&raw=true",
),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
if (response.body.isNotEmpty) {
final json = jsonDecode(response.body) as Map;
final list = List<Map<String, dynamic>>.from(json["data"] as List);
@ -208,7 +217,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getEthTransactionNonces($txns) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -231,13 +240,15 @@ abstract class EthereumAPI {
static Future<EthereumResponse<List<EthTokenTxExtraDTO>>>
getEthTokenTransactionsByTxids(List<String> txids) async {
try {
final response = await get(
Uri.parse(
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/transactions?transactions=${txids.join(" ")}",
),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
if (response.body.isNotEmpty) {
final json = jsonDecode(response.body) as Map;
final list = json["data"] as List?;
@ -257,13 +268,13 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getEthTokenTransactionsByTxids($txids) response is empty but status code is "
"${response.statusCode}",
"${response.code}",
);
}
} else {
throw EthApiException(
"getEthTokenTransactionsByTxids($txids) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -288,13 +299,15 @@ abstract class EthereumAPI {
required String tokenContractAddress,
}) async {
try {
final response = await get(
Uri.parse(
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/export?addrs=$address&emitter=$tokenContractAddress&logs=true",
),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
if (response.body.isNotEmpty) {
final json = jsonDecode(response.body) as Map;
final list = json["data"] as List?;
@ -321,7 +334,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getTokenTransactions($address, $tokenContractAddress) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -422,9 +435,13 @@ abstract class EthereumAPI {
final uri = Uri.parse(
"$stackBaseServer/tokens?addrs=$contractAddress $address",
);
final response = await get(uri);
final response = await client.get(
url: uri,
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
final json = jsonDecode(response.body);
if (json["data"] is List) {
final map = json["data"].first as Map;
@ -442,7 +459,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getWalletTokenBalance($address) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -469,9 +486,13 @@ abstract class EthereumAPI {
final uri = Uri.parse(
"$stackBaseServer/state?addrs=$address&parts=all",
);
final response = await get(uri);
final response = await client.get(
url: uri,
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
final json = jsonDecode(response.body);
if (json["data"] is List) {
final map = json["data"].first as Map;
@ -488,7 +509,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getAddressNonce($address) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -510,13 +531,15 @@ abstract class EthereumAPI {
static Future<EthereumResponse<GasTracker>> getGasOracle() async {
try {
final response = await get(
Uri.parse(
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/gas-prices",
),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
final json = jsonDecode(response.body) as Map;
if (json["success"] == true) {
try {
@ -541,7 +564,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getGasOracle() failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -579,13 +602,15 @@ abstract class EthereumAPI {
static Future<EthereumResponse<EthContract>> getTokenContractInfoByAddress(
String contractAddress) async {
try {
final response = await get(
Uri.parse(
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/tokens?addrs=$contractAddress&parts=all",
),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
final json = jsonDecode(response.body) as Map;
if (json["data"] is List) {
final map = Map<String, dynamic>.from(json["data"].first as Map);
@ -621,7 +646,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getTokenByContractAddress($contractAddress) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -646,13 +671,15 @@ abstract class EthereumAPI {
required String contractAddress,
}) async {
try {
final response = await get(
Uri.parse(
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/abis?addrs=$contractAddress&verbose=true",
),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
if (response.code == 200) {
final json = jsonDecode(response.body)["data"] as List;
return EthereumResponse(
@ -662,7 +689,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getTokenAbi($name, $contractAddress) failed with status code: "
"${response.statusCode}",
"${response.code}",
);
}
} on EthApiException catch (e) {
@ -687,9 +714,13 @@ abstract class EthereumAPI {
String contractAddress,
) async {
try {
final response = await get(Uri.parse(
"$stackBaseServer/state?addrs=$contractAddress&parts=proxy"));
if (response.statusCode == 200) {
final response = await client.get(
url: Uri.parse(
"$stackBaseServer/state?addrs=$contractAddress&parts=proxy"),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.code == 200) {
final json = jsonDecode(response.body);
final list = json["data"] as List;
final map = Map<String, dynamic>.from(list.first as Map);
@ -701,7 +732,7 @@ abstract class EthereumAPI {
} else {
throw EthApiException(
"getProxyTokenImplementationAddress($contractAddress) failed with"
" status code: ${response.statusCode}",
" status code: ${response.code}",
);
}
} on EthApiException catch (e) {

View file

@ -1,13 +1,16 @@
import 'dart:typed_data';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;
import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
final pMonKeyService = Provider((ref) => MonKeyService());
class MonKeyService {
static const baseURL = "https://monkey.banano.cc/api/v1/monkey/";
HTTP client = HTTP();
Future<Uint8List> fetchMonKey({
required String address,
@ -20,13 +23,17 @@ class MonKeyService {
url += '?format=png&size=512&background=false';
}
final response = await http.get(Uri.parse(url));
final response = await client.get(
url: Uri.parse(url),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
if (response.statusCode == 200) {
return response.bodyBytes;
if (response.code == 200) {
return Uint8List.fromList(response.bodyBytes);
} else {
throw Exception(
"statusCode=${response.statusCode} body=${response.body}",
"statusCode=${response.code} body=${response.body}",
);
}
} catch (e, s) {

View file

@ -15,11 +15,13 @@ import 'package:archive/archive_io.dart';
import 'package:crypto/crypto.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/isar/stack_theme.dart';
import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/utilities/stack_file_system.dart';
final pThemeService = Provider<ThemeService>((ref) {
@ -39,6 +41,8 @@ class ThemeService {
void init(MainDB db) => _db ??= db;
HTTP client = HTTP();
Future<void> install({required Uint8List themeArchiveData}) async {
final themesDir = StackFileSystem.themesDir!;
@ -207,7 +211,11 @@ class ThemeService {
Future<List<StackThemeMetaData>> fetchThemes() async {
try {
final response = await get(Uri.parse("$baseServerUrl/themes"));
final response = await client.get(
url: Uri.parse("$baseServerUrl/themes"),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
final jsonList = jsonDecode(response.body) as List;
@ -230,10 +238,13 @@ class ThemeService {
required StackThemeMetaData themeMetaData,
}) async {
try {
final response =
await get(Uri.parse("$baseServerUrl/theme/${themeMetaData.id}"));
final response = await client.get(
url: Uri.parse("$baseServerUrl/theme/${themeMetaData.id}"),
proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
);
final bytes = response.bodyBytes;
final bytes = Uint8List.fromList(response.bodyBytes);
// verify hash
final digest = sha256.convert(bytes);