Skip to content

Commit f864e86

Browse files
committed
fix(api): ServicesResponse is now being cached and doesn't fetch data everytime DashboardViewModel is being rebuilt
fix(tor): do not fallback to clearnet when tor failed. fix(tor): do not leak connections during app startup chore: refactor bootstrap() function to be separated into bootstrapOffline and bootstrapOnline fix(cw_bitcoin): migrate payjoin to use ProxyWrapper
1 parent c9fa8f3 commit f864e86

File tree

11 files changed

+108
-69
lines changed

11 files changed

+108
-69
lines changed

.github/workflows/no_http_imports.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
- name: Check for http package usage
1212
if: github.event_name == 'pull_request'
1313
run: |
14-
GIT_GREP_OUT="$(git grep package:http | (grep .dart: || test $? = 1) | (grep -v proxy_wrapper.dart || test $? = 1) || true)"
14+
GIT_GREP_OUT="$(git grep package:http | (grep .dart: || test $? = 1) | (grep -v proxy_wrapper.dart || test $? = 1) | (grep -v very_insecure_http_do_not_use || test $? = 1) || true)"
1515
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
1616
echo "$GIT_GREP_OUT"
1717
echo "There are .dart files which use http imports"

cw_bitcoin/lib/payjoin/payjoin_receive_worker.dart

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import 'package:blockchain_utils/blockchain_utils.dart';
77
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
88
import 'package:cw_bitcoin/psbt/signer.dart';
99
import 'package:cw_core/utils/print_verbose.dart';
10-
import 'package:http/http.dart' as http;
10+
import 'package:cw_core/utils/proxy_wrapper.dart';
1111
import 'package:payjoin_flutter/bitcoin_ffi.dart';
1212
import 'package:payjoin_flutter/common.dart';
1313
import 'package:payjoin_flutter/receive.dart';
1414
import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj;
15+
import 'package:http/http.dart' as very_insecure_http_do_not_use; // for eerrors
1516

1617
enum PayjoinReceiverRequestTypes {
1718
processOriginalTx,
@@ -27,7 +28,7 @@ class PayjoinReceiverWorker {
2728
final pendingRequests = <String, Completer<dynamic>>{};
2829

2930
PayjoinReceiverWorker._(this.sendPort);
30-
31+
static final client = ProxyWrapper().getHttpIOClient();
3132
static Future<void> run(List<Object> args) async {
3233
await pj.core.init();
3334

@@ -41,11 +42,10 @@ class PayjoinReceiverWorker {
4142
receivePort.listen(worker.handleMessage);
4243

4344
try {
44-
final httpClient = http.Client();
4545
final receiver = Receiver.fromJson(receiverJson);
4646

4747
final uncheckedProposal =
48-
await worker.receiveUncheckedProposal(httpClient, receiver);
48+
await worker.receiveUncheckedProposal(receiver);
4949

5050
final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast();
5151
sendPort.send({
@@ -56,14 +56,14 @@ class PayjoinReceiverWorker {
5656
final payjoinProposal = await worker.processPayjoinProposal(
5757
uncheckedProposal,
5858
);
59-
final psbt = await worker.sendFinalProposal(httpClient, payjoinProposal);
59+
final psbt = await worker.sendFinalProposal(payjoinProposal);
6060
sendPort.send({
6161
'type': PayjoinReceiverRequestTypes.proposalSent,
6262
'psbt': psbt,
6363
});
6464
} catch (e) {
6565
if (e is HttpException ||
66-
(e is http.ClientException &&
66+
(e is very_insecure_http_do_not_use.ClientException &&
6767
e.message.contains("Software caused connection abort"))) {
6868
sendPort.send(PayjoinSessionError.recoverable(e.toString()));
6969
} else {
@@ -97,15 +97,14 @@ class PayjoinReceiverWorker {
9797
return completer.future;
9898
}
9999

100-
Future<UncheckedProposal> receiveUncheckedProposal(
101-
http.Client httpClient, Receiver session) async {
100+
Future<UncheckedProposal> receiveUncheckedProposal(Receiver session) async {
102101
while (true) {
103102
printV("Polling for Proposal (${session.id()})");
104103
final extractReq = await session.extractReq();
105104
final request = extractReq.$1;
106105

107106
final url = Uri.parse(request.url.asString());
108-
final httpRequest = await httpClient.post(url,
107+
final httpRequest = await client.post(url,
109108
headers: {'Content-Type': request.contentType}, body: request.body);
110109

111110
final proposal = await session.processRes(
@@ -114,13 +113,12 @@ class PayjoinReceiverWorker {
114113
}
115114
}
116115

117-
Future<String> sendFinalProposal(
118-
http.Client httpClient, PayjoinProposal finalProposal) async {
116+
Future<String> sendFinalProposal(PayjoinProposal finalProposal) async {
119117
final req = await finalProposal.extractV2Req();
120118
final proposalReq = req.$1;
121119
final proposalCtx = req.$2;
122120

123-
final request = await httpClient.post(
121+
final request = await client.post(
124122
Uri.parse(proposalReq.url.asString()),
125123
headers: {"Content-Type": proposalReq.contentType},
126124
body: proposalReq.body,

cw_bitcoin/lib/payjoin/payjoin_send_worker.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'dart:isolate';
55
import 'package:cw_bitcoin/payjoin/manager.dart';
66
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
77
import 'package:cw_core/utils/print_verbose.dart';
8-
import 'package:http/http.dart' as http;
8+
import 'package:cw_core/utils/proxy_wrapper.dart';
99
import 'package:payjoin_flutter/common.dart';
1010
import 'package:payjoin_flutter/send.dart';
1111
import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj;
@@ -42,19 +42,19 @@ class PayjoinSenderWorker {
4242
sendPort.send(e);
4343
}
4444
}
45+
final client = ProxyWrapper().getHttpIOClient();
4546

4647
/// Run a payjoin sender (V2 protocol first, fallback to V1).
4748
Future<String> runSender(Sender sender) async {
48-
final httpClient = http.Client();
4949

5050
try {
51-
return await _runSenderV2(sender, httpClient);
51+
return await _runSenderV2(sender);
5252
} catch (e) {
5353
printV(e);
5454
if (e is PayjoinException &&
5555
// TODO condition on error type instead of message content
5656
e.message?.contains('parse receiver public key') == true) {
57-
return await _runSenderV1(sender, httpClient);
57+
return await _runSenderV1(sender);
5858
} else if (e is HttpException) {
5959
printV(e);
6060
throw Exception(PayjoinSessionError.recoverable(e.toString()));
@@ -65,13 +65,13 @@ class PayjoinSenderWorker {
6565
}
6666

6767
/// Attempt to send payjoin using the V2 of the protocol.
68-
Future<String> _runSenderV2(Sender sender, http.Client httpClient) async {
68+
Future<String> _runSenderV2(Sender sender) async {
6969
try {
7070
final postRequest = await sender.extractV2(
7171
ohttpProxyUrl: await PayjoinManager.randomOhttpRelayUrl(),
7272
);
7373

74-
final postResult = await _postRequest(httpClient, postRequest.$1);
74+
final postResult = await _postRequest(postRequest.$1);
7575
final getContext =
7676
await postRequest.$2.processResponse(response: postResult);
7777

@@ -83,7 +83,7 @@ class PayjoinSenderWorker {
8383
final getRequest = await getContext.extractReq(
8484
ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
8585
);
86-
final getRes = await _postRequest(httpClient, getRequest.$1);
86+
final getRes = await _postRequest(getRequest.$1);
8787
final proposalPsbt = await getContext.processResponse(
8888
response: getRes,
8989
ohttpCtx: getRequest.$2,
@@ -97,10 +97,10 @@ class PayjoinSenderWorker {
9797
}
9898

9999
/// Attempt to send payjoin using the V1 of the protocol.
100-
Future<String> _runSenderV1(Sender sender, http.Client httpClient) async {
100+
Future<String> _runSenderV1(Sender sender) async {
101101
try {
102102
final postRequest = await sender.extractV1();
103-
final response = await _postRequest(httpClient, postRequest.$1);
103+
final response = await _postRequest(postRequest.$1);
104104

105105
sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted});
106106

@@ -110,7 +110,7 @@ class PayjoinSenderWorker {
110110
}
111111
}
112112

113-
Future<List<int>> _postRequest(http.Client client, Request req) async {
113+
Future<List<int>> _postRequest(Request req) async {
114114
final httpRequest = await client.post(Uri.parse(req.url.asString()),
115115
headers: {'Content-Type': req.contentType}, body: req.body);
116116

cw_core/lib/utils/proxy_wrapper.dart

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22
import 'dart:convert';
33
import 'dart:io';
4+
import 'package:cw_core/utils/print_verbose.dart';
45
import 'package:cw_core/utils/proxy_socket/abstract.dart';
56
import 'package:socks5_proxy/socks_client.dart';
67
import 'package:tor/tor.dart';
@@ -29,6 +30,8 @@ class ProxyWrapper {
2930
password: null,
3031
),
3132
]);
33+
} else {
34+
printV("+++++++ TOR NOT STARTED");
3235
}
3336

3437
return client;
@@ -124,16 +127,20 @@ class ProxyWrapper {
124127
if (torEnabled) {
125128
try {
126129
torClient = await getProxyHttpClient(portOverride: portOverride);
127-
} catch (_) {}
130+
} catch (_) {
131+
rethrow;
132+
}
128133

129134
if (onionUri != null) {
130135
try {
131136
return await makeGet(
132-
client: torClient!,
137+
client: torClient,
133138
uri: onionUri,
134139
headers: headers,
135140
);
136-
} catch (_) {}
141+
} catch (_) {
142+
rethrow;
143+
}
137144
}
138145

139146
if (clearnetUri != null) {
@@ -143,7 +150,9 @@ class ProxyWrapper {
143150
uri: clearnetUri,
144151
headers: headers,
145152
);
146-
} catch (_) {}
153+
} catch (_) {
154+
rethrow;
155+
}
147156
}
148157
}
149158

@@ -157,7 +166,7 @@ class ProxyWrapper {
157166
headers: headers,
158167
);
159168
},
160-
createHttpClient: NullOverrides().createHttpClient,
169+
// createHttpClient: NullOverrides().createHttpClient,
161170
);
162171
} catch (_) {
163172
// we weren't able to get a response:
@@ -190,31 +199,37 @@ class ProxyWrapper {
190199
if (torEnabled) {
191200
try {
192201
torClient = await getProxyHttpClient(portOverride: portOverride);
193-
} catch (_) {}
202+
} catch (_) {
203+
rethrow;
204+
}
194205
if (allowMitmMoneroBypassSSLCheck) {
195-
torClient!.badCertificateCallback =
206+
torClient.badCertificateCallback =
196207
((X509Certificate cert, String host, int port) => true);
197208
}
198209
if (onionUri != null) {
199210
try {
200211
return await makePost(
201-
client: torClient!,
212+
client: torClient,
202213
uri: onionUri,
203214
headers: headers,
204215
body: body,
205216
);
206-
} catch (_) {}
217+
} catch (_) {
218+
rethrow;
219+
}
207220
}
208221

209222
if (clearnetUri != null) {
210223
try {
211224
return await makePost(
212-
client: torClient!,
225+
client: torClient,
213226
uri: clearnetUri,
214227
headers: headers,
215228
body: body,
216229
);
217-
} catch (_) {}
230+
} catch (_) {
231+
rethrow;
232+
}
218233
}
219234
}
220235

@@ -229,10 +244,9 @@ class ProxyWrapper {
229244
body: body,
230245
);
231246
},
232-
createHttpClient: NullOverrides().createHttpClient,
247+
// createHttpClient: NullOverrides().createHttpClient,
233248
);
234249
} catch (_) {
235-
// we weren't able to get a response:
236250
rethrow;
237251
}
238252
}
@@ -263,7 +277,9 @@ class ProxyWrapper {
263277
headers: headers,
264278
body: body,
265279
);
266-
} catch (_) {}
280+
} catch (_) {
281+
rethrow;
282+
}
267283
}
268284

269285
if (clearnetUri != null) {
@@ -274,7 +290,9 @@ class ProxyWrapper {
274290
headers: headers,
275291
body: body,
276292
);
277-
} catch (_) {}
293+
} catch (_) {
294+
rethrow;
295+
}
278296
}
279297
}
280298

@@ -289,7 +307,7 @@ class ProxyWrapper {
289307
body: body,
290308
);
291309
},
292-
createHttpClient: NullOverrides().createHttpClient,
310+
// createHttpClient: NullOverrides().createHttpClient,
293311
);
294312
} catch (_) {
295313
// we weren't able to get a response:

lib/core/fiat_conversion_service.dart

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,13 @@ import 'package:cw_core/utils/proxy_wrapper.dart';
22
import 'package:cw_core/crypto_currency.dart';
33
import 'package:cake_wallet/entities/fiat_currency.dart';
44
import 'dart:convert';
5-
import 'package:flutter/foundation.dart';
65
import 'package:cake_wallet/.secrets.g.dart' as secrets;
76

87
const _fiatApiClearNetAuthority = 'fiat-api.cakewallet.com';
98
const _fiatApiOnionAuthority = 'n4z7bdcmwk2oyddxvzaap3x2peqcplh3pzdy7tpkk5ejz5n4mhfvoxqd.onion';
109
const _fiatApiPath = '/v2/rates';
1110

12-
Future<double> _fetchPrice(Map<String, dynamic> args) async {
13-
final crypto = args['crypto'] as String;
14-
final fiat = args['fiat'] as String;
15-
final torOnly = args['torOnly'] as bool;
11+
Future<double> _fetchPrice(String crypto, String fiat, bool torOnly) async {
1612

1713
final Map<String, String> queryParams = {
1814
'interval_count': '1',
@@ -24,15 +20,12 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
2420
num price = 0.0;
2521

2622
try {
27-
late final Uri uri;
28-
if (torOnly) {
29-
uri = Uri.http(_fiatApiOnionAuthority, _fiatApiPath, queryParams);
30-
} else {
31-
uri = Uri.https(_fiatApiClearNetAuthority, _fiatApiPath, queryParams);
32-
}
23+
final onionUri = Uri.http(_fiatApiOnionAuthority, _fiatApiPath, queryParams);
24+
final clearnetUri = Uri.https(_fiatApiClearNetAuthority, _fiatApiPath, queryParams);
3325

3426
final response = await ProxyWrapper().get(
35-
clearnetUri: uri,
27+
onionUri: onionUri,
28+
clearnetUri: torOnly ? onionUri : clearnetUri,
3629
);
3730
final responseString = await response.transform(utf8.decoder).join();
3831

@@ -53,18 +46,11 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
5346
}
5447
}
5548

56-
Future<double> _fetchPriceAsync(CryptoCurrency crypto, FiatCurrency fiat, bool torOnly) async =>
57-
compute(_fetchPrice, {
58-
'fiat': fiat.toString(),
59-
'crypto': crypto.toString(),
60-
'torOnly': torOnly,
61-
});
62-
6349
class FiatConversionService {
6450
static Future<double> fetchPrice({
6551
required CryptoCurrency crypto,
6652
required FiatCurrency fiat,
6753
required bool torOnly,
6854
}) async =>
69-
await _fetchPriceAsync(crypto, fiat, torOnly);
55+
await _fetchPrice(crypto.toString(), fiat.toString(), torOnly);
7056
}

0 commit comments

Comments
 (0)