AtClientSecretSharing class

Ready-made composition of the same-atSign secret-sharing mixins, for apps that don't want to mix them into their own classes.

final sharing = AtClientSecretSharing.forClient(atClient);
await sharing.register();
await sharing.startListening();
sharing.receivedSecrets.listen((r) => ...);

Prefer AtClientSecretSharing.forClient over the plain constructor: a secret-sharing instance is this APKAM keypair's recipient identity (its X-Wing enc keypair, registered key package, and envelope listener) plus its SecretStore. Reusing one instance per AtClient lets every consumer (the app and SDK-internal ones, e.g. a future CryptoProvider that distributes its keys as secrets) share a single store and a single registration rather than minting duplicate enc keypairs. (Correctness does not depend on it — kpid-addressed envelopes converge idempotently via SecretStore.putIfNewer — but a single instance avoids redundant registration and double delivery.)

⚠ Not yet suitable for production secrets. The recipient key package a sender seals to is discovered via the gated enroll:listns verb and is not yet APKAM-signed or verified, so sealing currently trusts the atServer to return the genuine key package — a tampering atServer could substitute the encapsulation target and read the secret. This caveat lifts once advertised key packages are signed by their generating enrollment and verified against its _apsk before sealing.

Mixed-in types
Annotations
  • @experimental

Constructors

AtClientSecretSharing(AtClient atClient, {({Duration cacheExpiry, bool resetOnLookup})? publicKeyCacheSettings = (cacheExpiry: Duration(minutes: 5), resetOnLookup: true)})
Direct construction creates an independent instance with its own enc keypair. Use forClient unless that is what you want (tests, custom compositions).
AtClientSecretSharing.forClient(AtClient atClient, {SecretStorePersistence? persistence, ({Duration cacheExpiry, bool resetOnLookup})? publicKeyCacheSettings = (cacheExpiry: Duration(minutes: 5), resetOnLookup: true)})
The shared secret-sharing instance for atClient, created on first call. persistence and publicKeyCacheSettings take effect only on the creating call; later calls return the cached instance unchanged (one SecretStorePersistence per APKAM keypair — see SecretStore.persistence).
factory

Properties

answerSecretRequests ↔ SecretRequestPolicy?
Optional app override for the kind:'request' answer decision. Null = the default policy (answer any requester that resolves to an authorized key package of the request's namespace).
getter/setter pairinherited
atClient → AtClient
final
directory ↔ EnrollmentDirectory
The atServer-backed key-package directory. Defaults to a verb-backed implementation; tests assign a fake.
getter/setter pairinherited
enrollmentId → String
no setterinherited
envelopeTtl ↔ Duration
How long an unconsumed envelope lives on the atServer.
getter/setter pairinherited
hashCode → int
The hash code for this object.
no setterinherited
isRegistered → bool
no setterinherited
kpid → String
This key package's addressing id (KeyPackage.kpid) — the SHA-256 prefix of the X-Wing public key. Throws StateError until register completes.
no setterinherited
loadApkamKeys ↔ Future<PersistedApkamKeys?> Function()?
Supply to give this APKAM keypair a stable enc keypair across restarts. Called once, before generating a fresh one; return null to generate fresh.
getter/setter pairinherited
logger → AtSignLogger
final
myKeyPackage → KeyPackage
This APKAM keypair's key package (the one registered for discovery). Throws StateError until register has generated the enc keypair.
no setterinherited
privateSigningKey → String
the private key used to sign things this application sends
no setterinherited
pubKeyCache → Map<String, (String, Timer)>
finalinherited
publicKeyCacheSettings → ({Duration cacheExpiry, bool resetOnLookup})?
How to handle caching of public keys used for verification
final
publicSigningKey → String
the public key which can be used to verify signatures made using privateSigningKey
no setterinherited
publicSigningKeyUri → String
the uri (e.g. public:apsk.<enrollment_id>.__wa@atsign) of the publicSigningKey
no setterinherited
receivedEnvelopes → Stream<ReceivedEnvelope>
Decrypted, verified payloads addressed to this client. Listen, then call startListening.
no setterinherited
receivedSecrets → Stream<ReceivedSecret>
Secrets shared with this client by other APKAM keypairs (already verified, decrypted, and stored in secretStore). Listen, then call startListening.
no setterinherited
requestAnswerMinInterval ↔ Duration
Anti-storm floor: the same (requester, secret-name) is answered at most once per this interval. A burst of duplicate requests collapses to one share.
getter/setter pairinherited
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
saveApkamKeys ↔ Future<void> Function(PersistedApkamKeys keys)?
Supply to persist a freshly generated enc keypair (e.g. to the keyfile / platform keystore — the app's concern).
getter/setter pairinherited
secretStore → SecretStore
The secrets this client holds: what it created via SecretStore.putSecret, plus what other APKAM keypairs shared with it (received secrets are stored automatically, newest wins).
finalinherited
sendWakeUpNotification ↔ bool
Whether sendEnvelope also fires a best-effort wake-up notification (default on) after the put. Clients that run sync receive envelopes via sync without it; sync-less clients rely on it (their startListening monitors for it and does a remote sweep). It is best-effort: the envelope is already durably stored, so a failed wake-up never fails the send. A future atServer enhancement will emit this notification itself on a put to an __ssenv key, at which point senders can leave it off.
getter/setter pairinherited
sweepInterval ↔ Duration
How often startListening sweeps the local store for envelopes, in addition to sweeping when sync delivers one.
getter/setter pairinherited
xWingPublicKey → Uint8List
This APKAM keypair's X-Wing public key (raw bytes). Throws StateError until register has completed.
no setterinherited
xWingSeed → Uint8List
This APKAM keypair's X-Wing secret seed — for decapsulation by composing mixins, not for application use.
no setterinherited

Methods

cachePubKey(String atSign, String enrollmentId, String pubKey) → void
inherited
getApkamPublicKey(String atSign, String enrollmentId) → Future<String>
Fetch the APKAM public signing key which enrollmentId of atSign has published in its per-enrollment namespace. See ApkamSigning.publicSigningKeyUri.
inherited
lookupPubKey(String atSign, String enrollmentId) → String?
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
publishPublicSigningKey() → Future
inherited
pushSecretToNamespaceMembers(Secret secret, {Set<String> excludeEnrollmentIds = const {}}) → Future<int>
Pushes one secret to every key package registered for its namespace (minus this client). This is the mint/rotation push: it enumerates the namespace's members via the directory, seals once per key package, and puts the kpid-addressed envelope. excludeEnrollmentIds drops revoked enrollments. Returns the number of key packages it was pushed to.
inherited
register() → Future<KeyPackage>
Generates (or loads, via loadApkamKeys) this APKAM keypair's X-Wing enc keypair and publishes its APKAM signing key (so peers can verify its envelopes), then returns this client's KeyPackage. Idempotent.
inherited
requestSecret(String namespace, String name, {Duration timeout = const Duration(seconds: 30), Set<String> excludeEnrollmentIds = const {}}) → Future<Secret>
Requests a single named secret from the holders in namespace, then resolves when it arrives (waitForSecret).
inherited
requestSecretsFromNamespace(String namespace, {List<String>? names, String? namePrefix, Set<String> excludeEnrollmentIds = const {}}) → Future<int>
Broadcasts a pull request for held secrets to every key package registered for namespace (minus this client). Holders that pass the answer policy reply by sharing the matching secrets; the caller typically then waitForSecrets. Filter the request by exact names and/or a namePrefix (e.g. __rk. for epoch keys). excludeEnrollmentIds drops revoked enrollments. Returns the number of key packages the request was sent to.
inherited
sendEnvelope(KeyPackage to, String appNamespace, Map<String, dynamic> payload) → Future<void>
Encrypts payload to to's key package and stores it for delivery, addressed through appNamespace.
inherited
shareAllSecretsWith(KeyPackage to, {Map<String, dynamic>? approvedNamespaces, Set<String>? excludeEnrollmentIds}) → Future<int>
Shares every secret in secretStore with to, filtered — when approvedNamespaces is given — to secrets whose namespace that enrollment is authorized for (SecretStore.namespaceAuthorizes).
inherited
shareAllSecretsWithEnrollment(String enrollmentId, Map<String, dynamic> approvedNamespaces, {Set<String>? excludeEnrollmentIds}) → Future<int>
For use by an enrollment approver, after approving enrollmentId with approvedNamespaces (both available from the enrollment request): shares with each of the newly-approved enrollment's key packages every held secret the enrollment's namespaces authorize.
inherited
shareSecretWith(KeyPackage to, Secret secret) → Future<void>
Shares one secret with one key package.
inherited
startListening() → Future<void>
Starts watching for envelopes addressed to this client: sweeps the local store now, after every sync that delivers an envelope key, and every sweepInterval; and subscribes to wake-up notifications, doing a remote sweep on each (which is how a sync-less client receives envelopes at all). Requires register to have completed.
inherited
stopListening() → void
Stops watching. The receivedEnvelopes stream stays open; a later startListening resumes.
inherited
sweepOnce({bool fromRemote = false}) → Future<int>
Scans for envelopes addressed to this client; verifies, decrypts, emits and deletes each. Returns how many envelopes were consumed. Safe to call concurrently with the periodic sweep, a sync-triggered sweep, and a wake-up sweep — each envelope key is claimed synchronously before any await, so the same payload is never emitted twice.
inherited
toString() → String
A string representation of this object.
inherited
verifyEnvelopeSignature(Map envelope, {required String signerAtSign}) → Future<void>
Verify an envelope created by wrapAndSign or wrapAndSignAndJsonEncode.
inherited
waitForSecret(String namespace, String name, {Duration timeout = const Duration(seconds: 30)}) → Future<Secret>
Returns the secret (namespace, name) as soon as this client holds it: immediately from secretStore when already present, otherwise the first matching arrival on receivedSecrets — subscription is set up before the store check, so an arrival between the two cannot be missed. startListening must be active for arrivals to be observed.
inherited
wrapAndSign(Object? payload, {Object? toEncodable(Object? nonEncodable)?}) → FutureOr<Map<String, Object?>>
Create a json envelope around payload in a format that can be verified by verifyEnvelopeSignature.
inherited
wrapAndSignAndJsonEncode(Object? payload, {Object? toEncodable(Object? nonEncodable)?}) → FutureOr<String>
Same as wrapAndSign but we also call jsonEncode for you :)
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited