mirror of
https://github.com/kuhyx/todo-app.git
synced 2026-11-13 21:30:57 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file-length / file length <= 250 lines (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
The wrapper serves ~/.config/crdt-sync/password once on /sync-e2e-passphrase; the web app stores it in its keystore, so desktop todo never asks. Android still unlocks via the lock tile. Todo: fda71ed1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
39 lines
1.5 KiB
Dart
39 lines
1.5 KiB
Dart
/// Where todo gets the shared crdt-sync passphrase its E2E key comes from.
|
|
///
|
|
/// The keystore first. On the desktop (a web build behind the local
|
|
/// wrapper) an empty keystore adopts the wrapper's one-shot
|
|
/// `/sync-e2e-passphrase` route, which serves `~/.config/crdt-sync/password`,
|
|
/// so the desktop app never asks. Android has no wrapper (`Uri.base` is
|
|
/// `file:///`) and is unlocked through the settings lock tile instead.
|
|
library;
|
|
|
|
import 'package:crdt_sync_flutter/crdt_sync_flutter.dart'
|
|
show kE2ePassphraseKey, kSecureStorage, saveE2ePassphrase;
|
|
import 'package:http/http.dart' as http;
|
|
|
|
/// Path of the wrapper's one-shot passphrase route.
|
|
const kSyncE2ePassphrasePath = '/sync-e2e-passphrase';
|
|
|
|
/// Returns the passphrase, adopting the wrapper's once; null when none.
|
|
Future<String?> readE2ePassphrase({Uri? base, http.Client? client}) async {
|
|
final stored = await kSecureStorage.read(key: kE2ePassphraseKey);
|
|
if (stored != null && stored.isNotEmpty) return stored;
|
|
final origin = base ?? Uri.base;
|
|
if (origin.scheme != 'http' && origin.scheme != 'https') return null;
|
|
final httpClient = client ?? http.Client();
|
|
try {
|
|
final response = await httpClient.get(
|
|
origin.resolve(kSyncE2ePassphrasePath),
|
|
);
|
|
final text = response.body.trim();
|
|
if (response.statusCode != 200 || text.isEmpty) return null;
|
|
await saveE2ePassphrase(text);
|
|
return text;
|
|
} on Object {
|
|
// No wrapper, or it already served: this device is simply locked.
|
|
return null;
|
|
} finally {
|
|
if (client == null) httpClient.close();
|
|
}
|
|
}
|