Merge branch 'staging' into fix_1061

This commit is contained in:
julian-CStack 2025-01-13 14:35:20 -06:00 committed by GitHub
commit 22f9d4c653
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 67 additions and 54 deletions

View file

@ -12,6 +12,9 @@ import 'dart:convert';
import 'dart:io';
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:tor_ffi_plugin/socks_socket.dart';
@ -27,11 +30,18 @@ class MoneroNodeConnectionResponse {
final int? port;
final bool success;
MoneroNodeConnectionResponse(this.cert, this.url, this.port, this.success);
MoneroNodeConnectionResponse(
this.cert,
this.url,
this.port,
this.success,
);
}
Future<MoneroNodeConnectionResponse> testMoneroNodeConnection(
Uri uri,
String? username,
String? password,
bool allowBadX509Certificate, {
required ({
InternetAddress host,
@ -59,36 +69,37 @@ Future<MoneroNodeConnectionResponse> testMoneroNodeConnection(
await socket.connect();
await socket.connectTo(uri.host, uri.port);
final body = jsonEncode({
"jsonrpc": "2.0",
"id": "0",
"method": "get_info",
});
final request = 'POST /json_rpc HTTP/1.1\r\n'
'Host: ${uri.host}\r\n'
'Content-Type: application/json\r\n'
'Content-Length: ${body.length}\r\n'
'\r\n'
'$body';
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;
final rawRequest = DaemonRpc.rawRequestRpc(uri, 'get_info', {});
var response = await socket.send(rawRequest);
// check if we need authentication
String? authenticateHeaderValue;
for (final line in response.split('\r\n')) {
if (line.contains('WWW-authenticate: ')) {
// both the password and username needs to be
if (username == null || password == null) {
// node asking us for authentication, but we don't have any crendentials.
return MoneroNodeConnectionResponse(null, null, null, false);
}
authenticateHeaderValue =
line.replaceFirst('WWW-authenticate: ', '').trim();
}
}
// 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();
print("Response received: $result");
// generate the Authorization header for the second request.
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"
final success =
result.contains('"result":') && !result.contains('"error"');
response.contains('"result":') && !response.contains('"error"');
return MoneroNodeConnectionResponse(null, null, null, success);
} catch (e, s) {
@ -124,36 +135,15 @@ Future<MoneroNodeConnectionResponse> testMoneroNodeConnection(
return false;
};
final request = await httpClient.postUrl(uri);
final body = utf8.encode(
jsonEncode({
"jsonrpc": "2.0",
"id": "0",
"method": "get_info",
}),
final daemonRpc = DaemonRpc(
IOClient(httpClient),
'$uri',
username: username,
password: password,
);
final result = await daemonRpc.call('get_info', {});
request.headers.add(
'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"');
final success = result.containsKey('status') && result['status'] == 'OK';
return MoneroNodeConnectionResponse(null, null, null, success);
} catch (e, s) {
@ -210,3 +200,18 @@ Future<bool> showBadX509CertificateDialog(
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();
}
}

View file

@ -38,6 +38,8 @@ Future<bool> _xmrHelper(
final data = nodeFormData;
final url = data.host!;
final port = data.port;
final username = data.login;
final password = data.password;
final uri = Uri.parse(url);
@ -51,6 +53,8 @@ Future<bool> _xmrHelper(
final response = await testMoneroNodeConnection(
Uri.parse(uriString),
username,
password,
false,
proxyInfo: proxyInfo,
).timeout(Duration(seconds: proxyInfo != null ? 30 : 10));
@ -67,6 +71,8 @@ Future<bool> _xmrHelper(
if (shouldAllowBadCert) {
final response = await testMoneroNodeConnection(
Uri.parse(uriString),
username,
password,
true,
proxyInfo: proxyInfo,
);

View file

@ -229,7 +229,7 @@ class Namecoin extends Bip39HDCurrency with ElectrumXCurrencyInterface {
bool get hasMnemonicPassphraseSupport => true;
@override
List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 12];
List<int> get possibleMnemonicLengths => [defaultSeedPhraseLength, 24];
@override
AddressType get defaultAddressType => defaultDerivePathType.getAddressType();

View file

@ -204,6 +204,8 @@ dependencies:
cbor: ^6.3.3
cs_monero: 1.0.0-pre.1
cs_monero_flutter_libs: 1.0.0-pre.0
monero_rpc: ^2.0.0
digest_auth: ^1.0.1
dev_dependencies:
flutter_test: