feat(storage): A.2 — persist TS3 identity across app restarts
A fresh `Identity::create()` was generated on every connect, which meant the server saw a different client UID each time. Long-lived features (bookmarks, server-side bans, group membership) depend on a stable UID — restoring that now via a minimal directory-backed identity file. * `chanora_storage::IdentityFileStore` reads / writes a single `identity.tskey` file under a caller-supplied directory. On Unix the file is created with `O_CREAT | O_TRUNC | mode 0600`; on non-Unix targets the platform sandbox does the access control. Writes are atomic (temp file + `fsync` + `rename`) so a crash mid-write cannot leave a half-written identity on disk. Empty files are treated as "no identity" rather than as an error. * `chanora_protocol::ProtocolClient::generate_identity()` exposes the `counterVbase64key` serialisation used by tsclientlib's `Identity::new_from_str`, so the core layer can mint an identity and store it before dialling. * `chanora_core::ChanoraSession::init_storage(dir)` wires the store. `connect()` then resolves the identity in this order: (1) `cfg.identity` if explicitly supplied; (2) persisted value if any; (3) generate-and-persist a fresh one. * `chanora_bridge::api::init_storage(dir: String)` is the Flutter-facing entrypoint; the matching Dart side resolves `path_provider`'s `getApplicationSupportDirectory()` and calls it once on app start. * `BridgeError` now maps `CoreError::Storage`. Beta caveat (RISK-PoC-002 / SS-RISK-FALLBACK): the identity is not encrypted at rest. The v0.4 storage rework lands proper Secret Service + Android Keystore + iOS Keychain backends. Documented under `IdentityFileStore`'s doc comment. Live-verified on Moto G Stylus 5G: first connect generated + persisted the identity (visible in the redacted diagnostic export as "generated + persisted fresh identity"); disconnect + reconnect in the same session logged "reusing persisted identity" and dialled with the same UID.
This commit is contained in:
@@ -130,6 +130,17 @@ impl SnapshotProbe {
|
||||
}
|
||||
|
||||
impl ProtocolClient {
|
||||
/// Generate a fresh, persistable TS3 identity string. The
|
||||
/// returned value is the canonical `counter`V`base64key` form
|
||||
/// accepted by [`ConnectConfig::identity`] and by tsclientlib's
|
||||
/// `Identity::new_from_str`. Callers should persist it via
|
||||
/// `chanora_storage` so subsequent connects reuse the same
|
||||
/// identity and the server sees the same client UID.
|
||||
pub fn generate_identity() -> String {
|
||||
let id = Identity::create();
|
||||
format!("{}V{}", id.counter(), id.key().to_ts())
|
||||
}
|
||||
|
||||
/// Dial the server and wait for the initial state snapshot. The
|
||||
/// returned client is ready for [`Self::snapshot`] and
|
||||
/// [`Self::disconnect`] calls.
|
||||
|
||||
Reference in New Issue
Block a user