feat(block2): 'in your circle' trust — friend-of-a-friend, not a raw count
A network-wide 'N people vouch' count invites spam and means little. Now the
trust banner computes whether the peer is within YOUR circle — you vouch for
them, or someone you vouch for does (friend-of-a-friend) — via the pure
WebOfTrust rule (seeds={you}, threshold 1, distance 2). When known, the banner
turns green with 'In your circle' (else it falls back to the count).
The full member policy (threshold/distance/bootstrap) stays open (network-trust
§2); this is a deliberately loose 'people near you' heuristic.
Analyzer clean; trust cubit test adds a friend-of-a-friend vs stranger case
(run flutter test locally to confirm — the widget suite is too slow to run here).
This commit is contained in:
parent
46b5537a11
commit
f3a7ad198d
10 changed files with 96 additions and 16 deletions
|
|
@ -14,30 +14,43 @@ class TrustState extends Equatable {
|
|||
const TrustState({
|
||||
this.certifierCount = 0,
|
||||
this.iVouch = false,
|
||||
this.knownToYou = false,
|
||||
this.loading = true,
|
||||
this.busy = false,
|
||||
});
|
||||
|
||||
/// How many people (network-wide) vouch for the peer.
|
||||
final int certifierCount;
|
||||
|
||||
/// Whether this user vouches for the peer.
|
||||
final bool iVouch;
|
||||
|
||||
/// Whether the peer is within the user's own circle of trust — you vouch for
|
||||
/// them, or someone you vouch for does (friend-of-a-friend). This is the
|
||||
/// meaningful signal; a raw network count invites spam.
|
||||
final bool knownToYou;
|
||||
|
||||
final bool loading;
|
||||
final bool busy;
|
||||
|
||||
TrustState copyWith({
|
||||
int? certifierCount,
|
||||
bool? iVouch,
|
||||
bool? knownToYou,
|
||||
bool? loading,
|
||||
bool? busy,
|
||||
}) =>
|
||||
TrustState(
|
||||
certifierCount: certifierCount ?? this.certifierCount,
|
||||
iVouch: iVouch ?? this.iVouch,
|
||||
knownToYou: knownToYou ?? this.knownToYou,
|
||||
loading: loading ?? this.loading,
|
||||
busy: busy ?? this.busy,
|
||||
);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [certifierCount, iVouch, loading, busy];
|
||||
List<Object?> get props =>
|
||||
[certifierCount, iVouch, knownToYou, loading, busy];
|
||||
}
|
||||
|
||||
/// Reads and toggles this user's vouch for [peerPubkey] over a [TrustTransport].
|
||||
|
|
@ -57,7 +70,13 @@ class TrustCubit extends Cubit<TrustState> {
|
|||
|
||||
bool get isOnline => _transport != null;
|
||||
|
||||
/// Loads the current certifiers of the peer.
|
||||
/// Bootstrap "circle" rule: one vouch from your side, out to a friend-of-a-
|
||||
/// friend. Deliberately loose (the full member policy — threshold/distance —
|
||||
/// is still open, network-trust.md §2); this is just "people near you".
|
||||
static const _circleThreshold = 1;
|
||||
static const _circleDistance = 2;
|
||||
|
||||
/// Loads the peer's certifiers and whether they're within your circle.
|
||||
Future<void> load() async {
|
||||
final transport = _transport;
|
||||
if (transport == null) {
|
||||
|
|
@ -65,10 +84,20 @@ class TrustCubit extends Cubit<TrustState> {
|
|||
return;
|
||||
}
|
||||
emit(state.copyWith(loading: true));
|
||||
final certifiers = await transport.certifiersOf(peerPubkey);
|
||||
final wot = WebOfTrust.fromCertifications(
|
||||
await transport.allCertifications(),
|
||||
now: DateTime.now(),
|
||||
);
|
||||
final certifiers = wot.certifiersOf(peerPubkey);
|
||||
final circle = wot.members(
|
||||
seeds: {selfPubkey},
|
||||
threshold: _circleThreshold,
|
||||
maxDistance: _circleDistance,
|
||||
);
|
||||
emit(state.copyWith(
|
||||
certifierCount: certifiers.length,
|
||||
iVouch: certifiers.contains(selfPubkey),
|
||||
knownToYou: circle.contains(peerPubkey),
|
||||
loading: false,
|
||||
));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue