mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-12 09:27:01 +00:00
feat: xmrrpc (and wowrpc) uri parsing + tests
This commit is contained in:
parent
2873595e40
commit
4af7243265
2 changed files with 236 additions and 0 deletions
132
lib/utilities/node_uri_util.dart
Normal file
132
lib/utilities/node_uri_util.dart
Normal file
|
@ -0,0 +1,132 @@
|
|||
abstract interface class NodeQrData {
|
||||
final String host;
|
||||
final int port;
|
||||
final String? label;
|
||||
|
||||
NodeQrData({required this.host, required this.port, this.label});
|
||||
|
||||
String encode();
|
||||
String get scheme;
|
||||
}
|
||||
|
||||
abstract class LibMoneroNodeQrData extends NodeQrData {
|
||||
final String user;
|
||||
final String password;
|
||||
|
||||
LibMoneroNodeQrData({
|
||||
required super.host,
|
||||
required super.port,
|
||||
super.label,
|
||||
required this.user,
|
||||
required this.password,
|
||||
});
|
||||
|
||||
@override
|
||||
String encode() {
|
||||
String? userInfo;
|
||||
if (user.isNotEmpty) {
|
||||
userInfo = user;
|
||||
if (password.isNotEmpty) {
|
||||
userInfo += ":$password";
|
||||
}
|
||||
}
|
||||
|
||||
final uri = Uri(
|
||||
scheme: scheme,
|
||||
userInfo: userInfo,
|
||||
port: port,
|
||||
host: host,
|
||||
queryParameters: {"label": label},
|
||||
);
|
||||
|
||||
return uri.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "$runtimeType {"
|
||||
"scheme: $scheme, "
|
||||
"host: $host, "
|
||||
"port: $port, "
|
||||
"user: $user, "
|
||||
"password: $password, "
|
||||
"label: $label"
|
||||
"}";
|
||||
}
|
||||
}
|
||||
|
||||
class MoneroNodeQrData extends LibMoneroNodeQrData {
|
||||
MoneroNodeQrData({
|
||||
required super.host,
|
||||
required super.port,
|
||||
required super.user,
|
||||
required super.password,
|
||||
super.label,
|
||||
});
|
||||
|
||||
@override
|
||||
String get scheme => "xmrrpc";
|
||||
}
|
||||
|
||||
class WowneroNodeQrData extends LibMoneroNodeQrData {
|
||||
WowneroNodeQrData({
|
||||
required super.host,
|
||||
required super.port,
|
||||
required super.user,
|
||||
required super.password,
|
||||
super.label,
|
||||
});
|
||||
|
||||
@override
|
||||
String get scheme => "wowrpc";
|
||||
}
|
||||
|
||||
abstract final class NodeQrUtil {
|
||||
static ({String? user, String? password}) _parseUserInfo(String? userInfo) {
|
||||
if (userInfo == null || userInfo.isEmpty) {
|
||||
return (user: null, password: null);
|
||||
}
|
||||
|
||||
final splitIndex = userInfo.indexOf(":");
|
||||
if (splitIndex == -1) {
|
||||
return (user: userInfo, password: null);
|
||||
}
|
||||
|
||||
return (
|
||||
user: userInfo.substring(0, splitIndex),
|
||||
password: userInfo.substring(splitIndex + 1),
|
||||
);
|
||||
}
|
||||
|
||||
static NodeQrData decodeUri(String uriString) {
|
||||
final uri = Uri.tryParse(uriString);
|
||||
if (uri == null) throw Exception("Invalid uri string.");
|
||||
if (!uri.hasAuthority) throw Exception("Uri has no authority.");
|
||||
|
||||
final userInfo = _parseUserInfo(uri.userInfo);
|
||||
|
||||
final query = uri.queryParameters;
|
||||
|
||||
switch (uri.scheme) {
|
||||
case "xmrrpc":
|
||||
return MoneroNodeQrData(
|
||||
host: uri.host,
|
||||
port: uri.port,
|
||||
user: userInfo.user ?? "",
|
||||
password: userInfo.password ?? "",
|
||||
label: query["label"],
|
||||
);
|
||||
case "wowrpc":
|
||||
return WowneroNodeQrData(
|
||||
host: uri.host,
|
||||
port: uri.port,
|
||||
user: userInfo.user ?? "",
|
||||
password: userInfo.password ?? "",
|
||||
label: query["label"],
|
||||
);
|
||||
|
||||
default:
|
||||
throw Exception("Unknown node uri scheme \"${uri.scheme}\" found.");
|
||||
}
|
||||
}
|
||||
}
|
104
test/utilities/node_uri_util_test.dart
Normal file
104
test/utilities/node_uri_util_test.dart
Normal file
|
@ -0,0 +1,104 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stackwallet/utilities/node_uri_util.dart';
|
||||
|
||||
void main() {
|
||||
test("Valid xmrrpc scheme node uri", () {
|
||||
expect(
|
||||
NodeQrUtil.decodeUri(
|
||||
"xmrrpc://nodo:password@bob.onion:18083?label=Nodo Tor Node",
|
||||
),
|
||||
isA<MoneroNodeQrData>(),
|
||||
);
|
||||
});
|
||||
|
||||
test("Valid wowrpc scheme node uri", () {
|
||||
expect(
|
||||
NodeQrUtil.decodeUri(
|
||||
"wowrpc://nodo:password@10.0.0.10:18083",
|
||||
),
|
||||
isA<WowneroNodeQrData>(),
|
||||
);
|
||||
});
|
||||
|
||||
test("Invalid authority node uri", () {
|
||||
String? message;
|
||||
try {
|
||||
NodeQrUtil.decodeUri(
|
||||
"nodo:password@bob.onion:18083?label=Nodo Tor Node",
|
||||
);
|
||||
} catch (e) {
|
||||
message = e.toString();
|
||||
}
|
||||
expect(message, "Exception: Uri has no authority.");
|
||||
});
|
||||
|
||||
test("Empty uri string", () {
|
||||
String? message;
|
||||
try {
|
||||
NodeQrUtil.decodeUri("");
|
||||
} catch (e) {
|
||||
message = e.toString();
|
||||
}
|
||||
expect(message, "Exception: Uri has no authority.");
|
||||
});
|
||||
|
||||
test("Invalid uri string", () {
|
||||
String? message;
|
||||
try {
|
||||
NodeQrUtil.decodeUri("::invalid@@@.ok");
|
||||
} catch (e) {
|
||||
message = e.toString();
|
||||
}
|
||||
expect(message, "Exception: Invalid uri string.");
|
||||
});
|
||||
|
||||
test("Unknown uri string", () {
|
||||
String? message;
|
||||
try {
|
||||
NodeQrUtil.decodeUri("http://u:p@host.com:80/lol?hmm=42");
|
||||
} catch (e) {
|
||||
message = e.toString();
|
||||
}
|
||||
expect(message, "Exception: Unknown node uri scheme \"http\" found.");
|
||||
});
|
||||
|
||||
test("decoding to model", () {
|
||||
final data = NodeQrUtil.decodeUri(
|
||||
"xmrrpc://nodo:password@bob.onion:18083?label=Nodo+Tor+Node",
|
||||
);
|
||||
expect(data.scheme, "xmrrpc");
|
||||
expect(data.host, "bob.onion");
|
||||
expect(data.port, 18083);
|
||||
expect(data.label, "Nodo Tor Node");
|
||||
expect((data as MoneroNodeQrData?)?.user, "nodo");
|
||||
expect((data as MoneroNodeQrData?)?.password, "password");
|
||||
});
|
||||
|
||||
test("encoding to string", () {
|
||||
const validString =
|
||||
"xmrrpc://nodo:password@bob.onion:18083?label=Nodo+Tor+Node";
|
||||
final data = NodeQrUtil.decodeUri(
|
||||
validString,
|
||||
);
|
||||
expect(data.encode(), validString);
|
||||
});
|
||||
|
||||
test("normal to string", () {
|
||||
const validString =
|
||||
"xmrrpc://nodo:password@bob.onion:18083?label=Nodo+Tor+Node";
|
||||
final data = NodeQrUtil.decodeUri(
|
||||
validString,
|
||||
);
|
||||
expect(
|
||||
data.toString(),
|
||||
"MoneroNodeQrData {"
|
||||
"scheme: xmrrpc, "
|
||||
"host: bob.onion, "
|
||||
"port: 18083, "
|
||||
"user: nodo, "
|
||||
"password: password, "
|
||||
"label: Nodo Tor Node"
|
||||
"}",
|
||||
);
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue