connectWithBunkerUrl method
Connects to a bunker using a bunker URL (bunker://) authCallback is called with the auth URL if the bunker requires authentication
Implementation
Future<BunkerConnection?> connectWithBunkerUrl(
String bunkerUrl, {
Function(String)? authCallback,
}) async {
final uri = Uri.parse(bunkerUrl);
if (uri.scheme != 'bunker') {
throw ArgumentError('Invalid bunker URL scheme');
}
final remotePubkey = uri.host;
final relays = uri.queryParametersAll['relay'] ?? [];
final secret = uri.queryParameters['secret'];
if (relays.isEmpty) {
throw ArgumentError('At least one relay is required in bunker URL');
}
if (secret == null) {
throw ArgumentError('Secret parameter is required in bunker URL');
}
final keyPair = Bip340.generatePrivateKey();
final localEventSigner = Bip340EventSigner(
privateKey: keyPair.privateKey,
publicKey: keyPair.publicKey,
);
final request = BunkerRequest(
method: BunkerRequestMethods.connect,
params: [remotePubkey, secret],
);
final encryptedRequest = await localEventSigner.encryptNip44(
plaintext: jsonEncode(request),
recipientPubKey: remotePubkey,
);
final requestEvent = Nip01Event(
pubKey: localEventSigner.publicKey,
kind: BunkerRequest.kKind,
tags: [
["p", remotePubkey],
],
content: encryptedRequest!,
);
await localEventSigner.sign(requestEvent);
final broadcastRes =
_broadcast.broadcast(nostrEvent: requestEvent, specificRelays: relays);
await broadcastRes.broadcastDoneFuture;
final subscription = _requests.subscription(
explicitRelays: relays,
filters: [
Filter(
authors: [remotePubkey],
kinds: [BunkerRequest.kKind],
pTags: [localEventSigner.publicKey],
since: someTimeAgo(),
),
],
);
BunkerConnection? result;
await for (final event in subscription.stream
.timeout(Duration(seconds: kMaxWaitingTimeForConnectionSeconds))) {
final decryptedContent = await localEventSigner.decryptNip44(
ciphertext: event.content,
senderPubKey: remotePubkey,
);
final response = jsonDecode(decryptedContent!);
if (response["id"] != request.id) continue;
if (response["result"] == "auth_url") {
if (authCallback != null) {
authCallback(response["error"]);
}
continue;
}
if (response["result"] == "ack") {
result = BunkerConnection(
privateKey: localEventSigner.privateKey!,
remotePubkey: remotePubkey,
relays: relays,
);
break;
}
}
await _requests.closeSubscription(subscription.requestId);
return result;
}