Merge branch 'spike/block2-derisking'

This commit is contained in:
vjrj 2026-07-10 11:24:40 +02:00
commit 49a43722eb
12 changed files with 131 additions and 66 deletions

View file

@ -1,12 +1,21 @@
import '../security/secret_store.dart';
/// A suggested community server the user can join with one tap.
class RelayPreset {
const RelayPreset(this.name, this.url);
final String name;
final String url;
}
/// User choices for the (Block 2) social layer: the coarse area to publish/
/// browse offers in, and which community relays to talk to. Backed by the OS
/// keystore (via [SecretStore]) to honour "no plaintext at rest" no
/// shared_preferences.
///
/// Both default to "unset": empty area and no relays mean the social layer is
/// simply unavailable, and the app stays fully usable offline.
/// Relays default to a small set of well-known public servers so the market
/// works out of the box; the exposure is minimal (offers are opt-in and carry
/// only a coarse geohash) and the user can swap them for a community server.
/// The area stays unset until the user picks one (it's inherently personal).
class SocialSettings {
SocialSettings(this._store);
@ -15,6 +24,17 @@ class SocialSettings {
static const _areaKey = 'tane.social.area_geohash';
static const _relaysKey = 'tane.social.relays';
/// Suggested servers shown as one-tap options in the sharing setup.
static const List<RelayPreset> presets = [
RelayPreset('nos.lol', 'wss://nos.lol'),
RelayPreset('Damus', 'wss://relay.damus.io'),
RelayPreset('Primal', 'wss://relay.primal.net'),
];
/// Applied automatically for new users (a subset of [presets]) so sharing
/// works from the first launch, until the user changes it.
static const List<String> defaultRelays = ['wss://nos.lol', 'wss://relay.damus.io'];
/// The user's coarse area as a low-precision geohash (may be empty). Set
/// manually or from device location; the transport coarsens it further.
Future<String> areaGeohash() async => (await _store.read(_areaKey)) ?? '';
@ -22,11 +42,12 @@ class SocialSettings {
Future<void> setAreaGeohash(String geohash) =>
_store.write(_areaKey, geohash.trim().toLowerCase());
/// Configured community relay URLs (empty by default the user adds their
/// own; we bundle none, to avoid leaking metadata to third-party relays).
/// The relays to talk to. When the user has never configured any, falls back
/// to [defaultRelays]. Once they save a choice (even an empty one), that wins
/// so a privacy-minded user can turn the network off entirely.
Future<List<String>> relayUrls() async {
final raw = await _store.read(_relaysKey);
if (raw == null || raw.isEmpty) return const [];
if (raw == null) return const [...defaultRelays]; // never configured
return raw.split('\n').where((s) => s.trim().isNotEmpty).toList();
}