- nip19.dart: bech32 encodeNpub/encodeNsec for raw keys (no TLV entities), verified against the canonical NIP-19 test vectors. - nip05.dart: verifyNip05 with an injectable http.Client plus a pure nip05MatchesPubkey helper for the .well-known/nostr.json check. - fetchProfileFor(fetcher, pubkey): fetches and parses any user's kind-0 into a typed NostrProfile (newest-wins), generalizing the own-key FetchProfile. - Export all three from swarm.dart; unit tests for each (bech32 vectors, MockClient HTTP cases, fake-relay profile parsing). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
79 lines
2.4 KiB
Dart
79 lines
2.4 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:swarm/swarm.dart';
|
|
import 'package:test/test.dart';
|
|
|
|
import 'fake_relay_connection.dart';
|
|
|
|
Map<String, dynamic> _kind0(String id, int createdAt, Map<String, dynamic> profile) => {
|
|
'id': id,
|
|
'pubkey': 'pub',
|
|
'created_at': createdAt,
|
|
'kind': 0,
|
|
'tags': [],
|
|
'content': jsonEncode(profile),
|
|
'sig': 'sig',
|
|
};
|
|
|
|
void main() {
|
|
group('fetchProfileFor', () {
|
|
test('parses the kind-0 content into a NostrProfile (incl. nip05)', () async {
|
|
final fake = FakeRelayConnection();
|
|
addTearDown(fake.dispose);
|
|
fake.onReq = (subId) {
|
|
fake.push(jsonEncode([
|
|
'EVENT',
|
|
subId,
|
|
_kind0('e1', 100, {
|
|
'display_name': 'Alice',
|
|
'picture': 'https://cdn/x.jpg',
|
|
'nip05': 'alice@example.com',
|
|
}),
|
|
]));
|
|
fake.push(jsonEncode(['EOSE', subId]));
|
|
};
|
|
final fetcher = NostrFetchActor(
|
|
relayUrls: ['ws://relay1'],
|
|
connectionFactory: (_) => fake,
|
|
);
|
|
|
|
final profile = await fetchProfileFor(fetcher, 'pub');
|
|
|
|
expect(profile, isNotNull);
|
|
expect(profile!.displayName, equals('Alice'));
|
|
expect(profile.picture, equals('https://cdn/x.jpg'));
|
|
expect(profile.nip05, equals('alice@example.com'));
|
|
});
|
|
|
|
test('picks the newest profile when several are returned', () async {
|
|
final fake = FakeRelayConnection();
|
|
addTearDown(fake.dispose);
|
|
fake.onReq = (subId) {
|
|
fake.push(jsonEncode(
|
|
['EVENT', subId, _kind0('old', 100, {'display_name': 'Old'})]));
|
|
fake.push(jsonEncode(
|
|
['EVENT', subId, _kind0('new', 200, {'display_name': 'New'})]));
|
|
fake.push(jsonEncode(['EOSE', subId]));
|
|
};
|
|
final fetcher = NostrFetchActor(
|
|
relayUrls: ['ws://relay1'],
|
|
connectionFactory: (_) => fake,
|
|
);
|
|
|
|
final profile = await fetchProfileFor(fetcher, 'pub');
|
|
expect(profile!.displayName, equals('New'));
|
|
});
|
|
|
|
test('returns null when no profile exists', () async {
|
|
final fake = FakeRelayConnection();
|
|
addTearDown(fake.dispose);
|
|
fake.onReq = (subId) => fake.push(jsonEncode(['EOSE', subId]));
|
|
final fetcher = NostrFetchActor(
|
|
relayUrls: ['ws://relay1'],
|
|
connectionFactory: (_) => fake,
|
|
);
|
|
|
|
expect(await fetchProfileFor(fetcher, 'pub'), isNull);
|
|
});
|
|
});
|
|
}
|