mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-26 04:05:53 +00:00
Merge branch 'staging' into fix_1061
This commit is contained in:
commit
22f9d4c653
4 changed files with 67 additions and 54 deletions
|
@ -12,6 +12,9 @@ import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/io_client.dart';
|
||||||
|
import 'package:monero_rpc/monero_rpc.dart';
|
||||||
|
import 'package:digest_auth/digest_auth.dart';
|
||||||
import 'package:socks5_proxy/socks.dart';
|
import 'package:socks5_proxy/socks.dart';
|
||||||
import 'package:tor_ffi_plugin/socks_socket.dart';
|
import 'package:tor_ffi_plugin/socks_socket.dart';
|
||||||
|
|
||||||
|
@ -27,11 +30,18 @@ class MoneroNodeConnectionResponse {
|
||||||
final int? port;
|
final int? port;
|
||||||
final bool success;
|
final bool success;
|
||||||
|
|
||||||
MoneroNodeConnectionResponse(this.cert, this.url, this.port, this.success);
|
MoneroNodeConnectionResponse(
|
||||||
|
this.cert,
|
||||||
|
this.url,
|
||||||
|
this.port,
|
||||||
|
this.success,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<MoneroNodeConnectionResponse> testMoneroNodeConnection(
|
Future<MoneroNodeConnectionResponse> testMoneroNodeConnection(
|
||||||
Uri uri,
|
Uri uri,
|
||||||
|
String? username,
|
||||||
|
String? password,
|
||||||
bool allowBadX509Certificate, {
|
bool allowBadX509Certificate, {
|
||||||
required ({
|
required ({
|
||||||
InternetAddress host,
|
InternetAddress host,
|
||||||
|
@ -59,36 +69,37 @@ Future<MoneroNodeConnectionResponse> testMoneroNodeConnection(
|
||||||
await socket.connect();
|
await socket.connect();
|
||||||
await socket.connectTo(uri.host, uri.port);
|
await socket.connectTo(uri.host, uri.port);
|
||||||
|
|
||||||
final body = jsonEncode({
|
final rawRequest = DaemonRpc.rawRequestRpc(uri, 'get_info', {});
|
||||||
"jsonrpc": "2.0",
|
var response = await socket.send(rawRequest);
|
||||||
"id": "0",
|
// check if we need authentication
|
||||||
"method": "get_info",
|
String? authenticateHeaderValue;
|
||||||
});
|
for (final line in response.split('\r\n')) {
|
||||||
|
if (line.contains('WWW-authenticate: ')) {
|
||||||
final request = 'POST /json_rpc HTTP/1.1\r\n'
|
// both the password and username needs to be
|
||||||
'Host: ${uri.host}\r\n'
|
if (username == null || password == null) {
|
||||||
'Content-Type: application/json\r\n'
|
// node asking us for authentication, but we don't have any crendentials.
|
||||||
'Content-Length: ${body.length}\r\n'
|
return MoneroNodeConnectionResponse(null, null, null, false);
|
||||||
'\r\n'
|
}
|
||||||
'$body';
|
authenticateHeaderValue =
|
||||||
|
line.replaceFirst('WWW-authenticate: ', '').trim();
|
||||||
socket.write(request);
|
|
||||||
print("Request sent: $request");
|
|
||||||
|
|
||||||
final buffer = StringBuffer();
|
|
||||||
await for (var response in socket.inputStream) {
|
|
||||||
buffer.write(utf8.decode(response));
|
|
||||||
if (buffer.toString().contains("\r\n\r\n")) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// header to authenticate was present, we need to remake the request with digest
|
||||||
|
if (authenticateHeaderValue != null) {
|
||||||
|
final digestAuth = DigestAuth(username!, password!);
|
||||||
|
digestAuth.initFromAuthorizationHeader(authenticateHeaderValue);
|
||||||
|
|
||||||
final result = buffer.toString();
|
// generate the Authorization header for the second request.
|
||||||
print("Response received: $result");
|
final authHeader = digestAuth.getAuthString('POST', uri.path);
|
||||||
|
final rawRequestAuthenticated =
|
||||||
|
DaemonRpc.rawRequestRpc(uri, 'get_info', {}, authHeader);
|
||||||
|
// resend with an authenticated request
|
||||||
|
response = await socket.send(rawRequestAuthenticated);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the response contains "results" and does not contain "error"
|
// Check if the response contains "results" and does not contain "error"
|
||||||
final success =
|
final success =
|
||||||
result.contains('"result":') && !result.contains('"error"');
|
response.contains('"result":') && !response.contains('"error"');
|
||||||
|
|
||||||
return MoneroNodeConnectionResponse(null, null, null, success);
|
return MoneroNodeConnectionResponse(null, null, null, success);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
@ -124,36 +135,15 @@ Future<MoneroNodeConnectionResponse> testMoneroNodeConnection(
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
final daemonRpc = DaemonRpc(
|
||||||
final request = await httpClient.postUrl(uri);
|
IOClient(httpClient),
|
||||||
|
'$uri',
|
||||||
final body = utf8.encode(
|
username: username,
|
||||||
jsonEncode({
|
password: password,
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"id": "0",
|
|
||||||
"method": "get_info",
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
final result = await daemonRpc.call('get_info', {});
|
||||||
|
|
||||||
request.headers.add(
|
final success = result.containsKey('status') && result['status'] == 'OK';
|
||||||
'Content-Length',
|
|
||||||
body.length.toString(),
|
|
||||||
preserveHeaderCase: true,
|
|
||||||
);
|
|
||||||
request.headers.set(
|
|
||||||
'Content-Type',
|
|
||||||
'application/json',
|
|
||||||
preserveHeaderCase: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
request.add(body);
|
|
||||||
|
|
||||||
final response = await request.close();
|
|
||||||
final result = await response.transform(utf8.decoder).join();
|
|
||||||
// print("HTTP Response: $result");
|
|
||||||
|
|
||||||
final success =
|
|
||||||
result.contains('"result":') && !result.contains('"error"');
|
|
||||||
|
|
||||||
return MoneroNodeConnectionResponse(null, null, null, success);
|
return MoneroNodeConnectionResponse(null, null, null, success);
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
|
@ -210,3 +200,18 @@ Future<bool> showBadX509CertificateDialog(
|
||||||
|
|
||||||
return result ?? false;
|
return result ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension on SOCKSSocket {
|
||||||
|
/// write the raw request to the socket and return the response as String
|
||||||
|
Future<String> send(String rawRequest) async {
|
||||||
|
write(rawRequest);
|
||||||
|
final buffer = StringBuffer();
|
||||||
|
await for (final response in inputStream) {
|
||||||
|
buffer.write(utf8.decode(response));
|
||||||
|
if (buffer.toString().contains("\r\n\r\n")) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ Future<bool> _xmrHelper(
|
||||||
final data = nodeFormData;
|
final data = nodeFormData;
|
||||||
final url = data.host!;
|
final url = data.host!;
|
||||||
final port = data.port;
|
final port = data.port;
|
||||||
|
final username = data.login;
|
||||||
|
final password = data.password;
|
||||||
|
|
||||||
final uri = Uri.parse(url);
|
final uri = Uri.parse(url);
|
||||||
|
|
||||||
|
@ -51,6 +53,8 @@ Future<bool> _xmrHelper(
|
||||||
|
|
||||||
final response = await testMoneroNodeConnection(
|
final response = await testMoneroNodeConnection(
|
||||||
Uri.parse(uriString),
|
Uri.parse(uriString),
|
||||||
|
username,
|
||||||
|
password,
|
||||||
false,
|
false,
|
||||||
proxyInfo: proxyInfo,
|
proxyInfo: proxyInfo,
|
||||||
).timeout(Duration(seconds: proxyInfo != null ? 30 : 10));
|
).timeout(Duration(seconds: proxyInfo != null ? 30 : 10));
|
||||||
|
@ -67,6 +71,8 @@ Future<bool> _xmrHelper(
|
||||||
if (shouldAllowBadCert) {
|
if (shouldAllowBadCert) {
|
||||||
final response = await testMoneroNodeConnection(
|
final response = await testMoneroNodeConnection(
|
||||||
Uri.parse(uriString),
|
Uri.parse(uriString),
|
||||||
|
username,
|
||||||
|
password,
|
||||||
true,
|
true,
|
||||||
proxyInfo: proxyInfo,
|
proxyInfo: proxyInfo,
|
||||||
);
|
);
|
||||||
|
|
|
@ -229,7 +229,7 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface {
|
||||||
bool get hasMnemonicPassphraseSupport => true;
|
bool get hasMnemonicPassphraseSupport => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 12];
|
List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AddressType get defaultAddressType => defaultDerivePathType.getAddressType();
|
AddressType get defaultAddressType => defaultDerivePathType.getAddressType();
|
||||||
|
|
|
@ -204,6 +204,8 @@ dependencies:
|
||||||
cbor: ^6.3.3
|
cbor: ^6.3.3
|
||||||
cs_monero: 1.0.0-pre.1
|
cs_monero: 1.0.0-pre.1
|
||||||
cs_monero_flutter_libs: 1.0.0-pre.0
|
cs_monero_flutter_libs: 1.0.0-pre.0
|
||||||
|
monero_rpc: ^2.0.0
|
||||||
|
digest_auth: ^1.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue