The global membership rule (curated bootstrap referents + sigQty/stepMax parameters) solved sybil-proof identity for a UBI — a problem this app doesn't have — and its screen leaked graph jargon (npub roots, parameter steppers). Trust is now computed from the user's own position only: you vouch / vouched by people you know (distance <=2) / vouched by N. - TrustCubit: drop networkMember tier, referents and params; keep the circle rule and the 365-day vouch expiry (renewable, self-pruning). - Delete TrustReferents, WotSettings, TrustNetworkScreen and the bundled referents asset; unwire injector/bootstrap/app/chat. - New 'Your people' screen (/your-people, from the profile): who you vouch for (revocable) and who vouches for you, names via ProfileCache. - i18n: wot.* removed, yourPeople.* added (en/es/pt/ast); trust.member removed. Kind 30777 events on relays stay fully compatible — only the interpretation changes.
128 lines
4.1 KiB
Dart
128 lines
4.1 KiB
Dart
import 'package:commons_core/commons_core.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:tane/state/trust_cubit.dart';
|
|
|
|
/// In-memory [TrustTransport]: certify/revoke act as this device's identity.
|
|
class FakeTrustTransport implements TrustTransport {
|
|
FakeTrustTransport(this.selfId);
|
|
final String selfId;
|
|
final Map<String, Set<String>> _certs = {}; // subject -> issuers
|
|
|
|
/// Test helper: record an arbitrary issuer→subject vouch (to build a graph).
|
|
void addCert(String issuer, String subject) =>
|
|
(_certs[subject] ??= {}).add(issuer);
|
|
|
|
@override
|
|
Future<Set<String>> certifiersOf(String subjectPubkey) async =>
|
|
_certs[subjectPubkey] ?? <String>{};
|
|
|
|
@override
|
|
Future<void> certify({
|
|
required String subjectPubkey,
|
|
Duration validity = const Duration(days: 365),
|
|
String note = '',
|
|
}) async =>
|
|
addCert(selfId, subjectPubkey);
|
|
|
|
@override
|
|
Future<void> revoke({required String subjectPubkey}) async =>
|
|
_certs[subjectPubkey]?.remove(selfId);
|
|
|
|
@override
|
|
Future<List<Certification>> allCertifications() async => [
|
|
for (final entry in _certs.entries)
|
|
for (final issuer in entry.value)
|
|
Certification(
|
|
issuer: issuer,
|
|
subject: entry.key,
|
|
issuedAt: DateTime(2026),
|
|
),
|
|
];
|
|
|
|
@override
|
|
Future<void> close() async {}
|
|
}
|
|
|
|
void main() {
|
|
const me = 'me';
|
|
const peer = 'peer';
|
|
|
|
test('loads certifier count and whether I vouch', () async {
|
|
final transport = FakeTrustTransport(me);
|
|
await transport.certify(subjectPubkey: peer); // I already vouch
|
|
final cubit = TrustCubit(transport, peerPubkey: peer, selfPubkey: me);
|
|
await cubit.load();
|
|
expect(cubit.state.certifierCount, 1);
|
|
expect(cubit.state.iVouch, isTrue);
|
|
expect(cubit.state.loading, isFalse);
|
|
await cubit.close();
|
|
});
|
|
|
|
test('toggleVouch certifies then revokes', () async {
|
|
final cubit =
|
|
TrustCubit(FakeTrustTransport(me), peerPubkey: peer, selfPubkey: me);
|
|
await cubit.load();
|
|
expect(cubit.state.iVouch, isFalse);
|
|
|
|
await cubit.toggleVouch();
|
|
expect(cubit.state.iVouch, isTrue);
|
|
expect(cubit.state.certifierCount, 1);
|
|
|
|
await cubit.toggleVouch();
|
|
expect(cubit.state.iVouch, isFalse);
|
|
expect(cubit.state.certifierCount, 0);
|
|
await cubit.close();
|
|
});
|
|
|
|
test('a friend-of-a-friend is in your circle; a stranger is not', () async {
|
|
final transport = FakeTrustTransport(me)
|
|
..addCert(me, 'friend') // you vouch for a friend
|
|
..addCert('friend', peer) // your friend vouches for the peer
|
|
..addCert('stranger', 'other'); // unrelated to you
|
|
|
|
final inCircle = TrustCubit(transport, peerPubkey: peer, selfPubkey: me);
|
|
await inCircle.load();
|
|
expect(inCircle.state.knownToYou, isTrue);
|
|
expect(inCircle.state.tier, TrustTier.inYourCircle);
|
|
await inCircle.close();
|
|
|
|
final outside = TrustCubit(transport, peerPubkey: 'other', selfPubkey: me);
|
|
await outside.load();
|
|
expect(outside.state.knownToYou, isFalse);
|
|
await outside.close();
|
|
});
|
|
|
|
test('tier falls back to vouched, then unknown', () async {
|
|
final vouched = TrustCubit(
|
|
FakeTrustTransport(me)..addCert('someone', peer),
|
|
peerPubkey: peer,
|
|
selfPubkey: me);
|
|
await vouched.load();
|
|
expect(vouched.state.tier, TrustTier.vouched);
|
|
await vouched.close();
|
|
|
|
final unknown = TrustCubit(FakeTrustTransport(me),
|
|
peerPubkey: 'nobody', selfPubkey: me);
|
|
await unknown.load();
|
|
expect(unknown.state.tier, TrustTier.unknown);
|
|
await unknown.close();
|
|
});
|
|
|
|
test('never vouches for self', () async {
|
|
final cubit =
|
|
TrustCubit(FakeTrustTransport(me), peerPubkey: me, selfPubkey: me);
|
|
await cubit.load();
|
|
await cubit.toggleVouch();
|
|
expect(cubit.state.iVouch, isFalse);
|
|
await cubit.close();
|
|
});
|
|
|
|
test('offline (no transport) never throws', () async {
|
|
final cubit = TrustCubit(null, peerPubkey: peer, selfPubkey: me);
|
|
expect(cubit.isOnline, isFalse);
|
|
await cubit.load();
|
|
await cubit.toggleVouch();
|
|
expect(cubit.state.loading, isFalse);
|
|
await cubit.close();
|
|
});
|
|
}
|