Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
frnandu committed Dec 25, 2024
1 parent 49c9ff2 commit 787bffb
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 3 deletions.
4 changes: 3 additions & 1 deletion packages/ndk/lib/domain_layer/usecases/relay_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -385,13 +385,15 @@ class RelayManager<T> {
// nip 42 used to send authentication challenges
final challenge = eventJson[1];
Logger.log.d("AUTH: ${challenge}");
if (signer != null) {
if (signer != null && signer!.canSign()) {
final auth = AuthEvent(pubKey: signer!.getPublicKey(), tags: [
["relay", relayConnectivity.url],
["challenge", challenge]
]);
signer!.sign(auth);
send(relayConnectivity, ClientMsg(ClientMsgType.AUTH, event: auth));
} else {
Logger.log.w("Received an AUTH challenge but don't have a signer configured");
}
return;
}
Expand Down
20 changes: 20 additions & 0 deletions packages/ndk/test/mocks/mock_relay.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'dart:developer';
import 'dart:io';

import 'package:ndk/entities.dart';
import 'package:ndk/shared/nips/nip01/helpers.dart';
import 'package:ndk/shared/nips/nip01/key_pair.dart';

class MockRelay {
Expand All @@ -14,6 +15,7 @@ class MockRelay {
Map<KeyPair, Nip65>? nip65s;
Map<KeyPair, Nip01Event>? textNotes;
bool signEvents;
bool requireAuthForRequests;

static int startPort = 4040;

Expand All @@ -23,6 +25,7 @@ class MockRelay {
required this.name,
this.nip65s,
this.signEvents = true,
this.requireAuthForRequests = false,
int? explicitPort,
}) {
if (explicitPort != null) {
Expand Down Expand Up @@ -51,15 +54,32 @@ class MockRelay {
this.server = server;

var stream = server.transform(WebSocketTransformer());
String challenge;

bool signedChallenge=false;
stream.listen((webSocket) {
this.webSocket = webSocket;
if (requireAuthForRequests && !signedChallenge) {
challenge = Helpers.getRandomString(10);
webSocket.add(jsonEncode(["AUTH", challenge]));
}
webSocket.listen((message) {
if (message == "ping") {
webSocket.add("pong");
return;
}
var eventJson = json.decode(message);
if (eventJson[0] == "AUTH") {
Nip01Event event = Nip01Event.fromJson(eventJson[1]);
// TODO check signature
if (event.)
signedChallenge = true;
print(event);
}
if (requireAuthForRequests && !signedChallenge) {
webSocket.add(jsonEncode(["CLOSED", "sub_1","auth-required: we can't serve requests to unauthenticated users"]));
return;
}
if (eventJson[0] == "REQ") {
String requestId = eventJson[1];
log('Received: $eventJson');
Expand Down
87 changes: 87 additions & 0 deletions packages/ndk/test/relays/nip42_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// ignore_for_file: avoid_print

import 'dart:async';

import 'package:ndk/data_layer/repositories/nostr_transport/websocket_client_nostr_transport_factory.dart';
import 'package:ndk/data_layer/repositories/signers/bip340_event_signer.dart';
import 'package:ndk/domain_layer/entities/global_state.dart';
import 'package:ndk/domain_layer/usecases/relay_manager.dart';
import 'package:ndk/entities.dart';
import 'package:ndk/ndk.dart';
import 'package:ndk/shared/nips/nip01/bip340.dart';
import 'package:ndk/shared/nips/nip01/key_pair.dart';
import 'package:test/test.dart';

import '../mocks/mock_relay.dart';

void main() async {
group('NIP-42', () {

KeyPair key1 = Bip340.generatePrivateKey();

Map<KeyPair, String> keyNames = {
key1: "key1",
};

Nip01Event textNote(KeyPair key2) {
return Nip01Event(
kind: Nip01Event.TEXT_NODE_KIND,
pubKey: key2.publicKey,
content: "some note from key ${keyNames[key1]}",
tags: [],
createdAt: DateTime.now().millisecondsSinceEpoch ~/ 1000);
}

Map<KeyPair, Nip01Event> key1TextNotes = {key1: textNote(key1)};

test('respond to auth challenge', () async {
MockRelay relay1 = MockRelay(name: "relay 1", explicitPort: 3900, requireAuthForRequests: true);
await relay1.startServer(textNotes: key1TextNotes);

final ndk = Ndk(
NdkConfig(
eventVerifier: Bip340EventVerifier(),
eventSigner: Bip340EventSigner(
privateKey: key1.privateKey,
publicKey: key1.publicKey,
),
cache: MemCacheManager(),
logLevel: Logger.logLevels.trace,
bootstrapRelays: [relay1.url]),
);

await Future.delayed(Duration(seconds: 3));
final response = ndk.requests.query(filters: [
Filter(kinds: [Nip01Event.TEXT_NODE_KIND], authors: [key1.publicKey])
]);
await expectLater(response.stream, emitsInAnyOrder(key1TextNotes.values));

// TODO write some events
// TODO do some requests
await ndk.destroy();
await relay1.stopServer();
});

test("check that relay does not return events if we don't provide a signer", () async {
MockRelay relay1 = MockRelay(name: "relay 1", explicitPort: 3900, requireAuthForRequests: true);
await relay1.startServer(textNotes: key1TextNotes);

final ndk = Ndk(
NdkConfig(
eventVerifier: Bip340EventVerifier(),
cache: MemCacheManager(),
logLevel: Logger.logLevels.trace,
bootstrapRelays: [relay1.url]),
);

await Future.delayed(Duration(seconds: 1));
final response = ndk.requests.query(filters: [
Filter(kinds: [Nip01Event.TEXT_NODE_KIND], authors: [key1.publicKey])
]);
List<Nip01Event> events = await response.future;
expect(events, isEmpty);
await ndk.destroy();
await relay1.stopServer();
});
});
}
3 changes: 1 addition & 2 deletions packages/ndk/test/relays/relay_manager_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
import 'dart:async';

import 'package:ndk/data_layer/repositories/nostr_transport/websocket_client_nostr_transport_factory.dart';
import 'package:ndk/domain_layer/entities/global_state.dart';
import 'package:ndk/domain_layer/usecases/relay_manager.dart';
import 'package:ndk/entities.dart';
import 'package:test/test.dart';
import 'package:ndk/data_layer/repositories/nostr_transport/websocket_nostr_transport_factory.dart';

import '../mocks/mock_relay.dart';

Expand Down Expand Up @@ -38,6 +36,7 @@ void main() async {
test('Try to connect to dead relay', () async {
RelayManager manager = RelayManager(
nostrTransportFactory: webSocketNostrTransportFactory,
bootstrapRelays: [],
globalState: GlobalState(),
);

Expand Down

0 comments on commit 787bffb

Please sign in to comment.