Third slice: bridge Block 1's root seed to the Block 2 transport foundation. - SocialService: derives the secp256k1 Nostr identity from the SAME root seed the recovery QR backs up (no extra backup), exposes npub/pubkey, and opens a SocialSession = one shared connection carrying all three transports. - injector.dart: registers SocialService in get_it. Local-first — derivation is cheap + offline; no relay is contacted at startup. Replaces the old "nodeId slice of the seed is the social pubkey" placeholder; keeps the CRDT author id distinct (unifying it would rewrite authorship — a later decision). - Test: deterministic identity from the seed hex, matches commons_core, rejects malformed hex. 5 tests green; app_seeds analyzes clean (0 errors).
48 lines
1.8 KiB
Dart
48 lines
1.8 KiB
Dart
import 'package:commons_core/commons_core.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:tane/services/social_service.dart';
|
|
|
|
/// Wiring test: the app derives its social identity from the SAME root seed the
|
|
/// recovery QR backs up, deterministically and without any network.
|
|
void main() {
|
|
// A fixed 32-byte seed (64 hex chars).
|
|
const seedHex =
|
|
'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f';
|
|
|
|
test('derives a stable Nostr identity from the root-seed hex', () async {
|
|
final service = await SocialService.fromRootSeedHex(seedHex);
|
|
expect(service.npub, startsWith('npub1'));
|
|
expect(service.publicKeyHex, matches(RegExp(r'^[0-9a-f]{64}$')));
|
|
});
|
|
|
|
test('is deterministic: same seed → same public identity', () async {
|
|
final a = await SocialService.fromRootSeedHex(seedHex);
|
|
final b = await SocialService.fromRootSeedHex(seedHex);
|
|
expect(a.publicKeyHex, b.publicKeyHex);
|
|
expect(a.npub, b.npub);
|
|
});
|
|
|
|
test('matches commons_core derivation on the same bytes', () async {
|
|
final service = await SocialService.fromRootSeedHex(seedHex);
|
|
final direct = await NostrKeyDerivation.deriveFromSeed([
|
|
for (var i = 0; i < seedHex.length; i += 2)
|
|
int.parse(seedHex.substring(i, i + 2), radix: 16),
|
|
]);
|
|
expect(service.publicKeyHex, direct.publicKeyHex);
|
|
});
|
|
|
|
test('a different seed yields a different identity', () async {
|
|
final a = await SocialService.fromRootSeedHex(seedHex);
|
|
final b = await SocialService.fromRootSeedHex(
|
|
'ff${seedHex.substring(2)}',
|
|
);
|
|
expect(a.publicKeyHex, isNot(b.publicKeyHex));
|
|
});
|
|
|
|
test('rejects a malformed (odd-length) seed hex', () async {
|
|
await expectLater(
|
|
SocialService.fromRootSeedHex('abc'),
|
|
throwsA(isA<ArgumentError>()),
|
|
);
|
|
});
|
|
}
|