557 lines
19 KiB
TypeScript
557 lines
19 KiB
TypeScript
|
|
/**
|
|||
|
|
* V4.6 — Broadcast channels for one-to-many fan-out.
|
|||
|
|
*
|
|||
|
|
* Wraps the Signal-style sender-key primitives (`@shade/core/sender-keys`)
|
|||
|
|
* in a persistent, app-friendly handle. The crypto is unchanged from
|
|||
|
|
* `sender-keys.ts`; this module wires it into:
|
|||
|
|
*
|
|||
|
|
* - `StorageProvider.{save,get,list,remove}BroadcastChannel` for state
|
|||
|
|
* - `Shade.send` for distribution (sealed by the bilateral ratchet)
|
|||
|
|
* - `@shade/proto.encodeBroadcast` for the on-wire broadcast envelope
|
|||
|
|
*
|
|||
|
|
* The model is **strictly one-to-many**: the channel owner is the only
|
|||
|
|
* sender. Members hold a tracking copy of the chain key (no signing
|
|||
|
|
* privkey) and can decrypt — they cannot send into the channel. This
|
|||
|
|
* matches the Prism use case (PC desktop fans output frames out to
|
|||
|
|
* paired peers); a future symmetric-group API would build on the same
|
|||
|
|
* persistence layer.
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import {
|
|||
|
|
type CryptoProvider,
|
|||
|
|
type StorageProvider,
|
|||
|
|
type BroadcastChannelRecord,
|
|||
|
|
type BroadcastMemberRecord,
|
|||
|
|
type GroupSession,
|
|||
|
|
type SenderKeyState,
|
|||
|
|
buildDistribution,
|
|||
|
|
createSenderKey,
|
|||
|
|
installDistribution,
|
|||
|
|
senderKeyEncrypt,
|
|||
|
|
senderKeyDecrypt,
|
|||
|
|
toBase64,
|
|||
|
|
fromBase64,
|
|||
|
|
} from '@shade/core';
|
|||
|
|
import {
|
|||
|
|
encodeBroadcast,
|
|||
|
|
decodeBroadcast,
|
|||
|
|
inspectEnvelopeType,
|
|||
|
|
type BroadcastWire,
|
|||
|
|
} from '@shade/proto';
|
|||
|
|
import type { ShadeEnvelope } from '@shade/core';
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Magic prefix used to embed broadcast control messages inside a regular
|
|||
|
|
* bilateral plaintext (so they ride the existing `shade.send` /
|
|||
|
|
* `shade.receive` path without a new ratchet wire type). The leading
|
|||
|
|
* NULs make a collision with user-app text astronomically unlikely.
|
|||
|
|
*/
|
|||
|
|
const CONTROL_MAGIC = ' |