import type { DevicePublicKeys } from '../interfaces/CryptoLib.mjs'; /** * The most devices a vault's stored device list may hold. * * Counted on the STORED list, which includes this device's own record -- * `SyncManager.getSyncDevices()` filters that one out, so the number a user * sees is one lower. Both places that enforce the cap (the load path in * creationUtils and `SyncManager.addSyncDevice`) count the stored list, so they * agree about the same vault. * * Not a capacity limit -- it is a bound on how much damage one malformed or * hostile vault state can do. Every outgoing command is sealed and signed once * per device (`SyncManager.sendCommand`), so an unbounded list is an unbounded * amount of work per keystroke. */ export declare const MAX_SYNC_DEVICES = 64; /** * How long a base64 public key is: 32 raw bytes, so 44 characters including the * single padding character. * * An exact length, where storage version 1's RSA PEMs could only be given an * upper bound. X25519 and Ed25519 keys are both exactly this size, which is * also why nothing but the field name and the branded type keeps the two roles * apart -- there is no length to tell them by. */ export declare const PUBLIC_KEY_LENGTH = 44; /** * The most removal tombstones a vault may keep. * * Four times the device cap, and the slack is the point. Pruning a tombstone * lets that device be introduced again, so unlike `15`'s replay floors -- where * pruning an id raises a floor and never weakens anything -- there is nothing * here to fall back on when an entry is dropped. A tight cap would therefore be * a way to forget a revocation by making enough other removals. * * It is capped at all for the reason MAX_SYNC_DEVICES exists: the record is * re-serialised and re-encrypted on every save, so an unbounded one is * unbounded work per keystroke. */ export declare const MAX_REMOVED_DEVICES = 256; /** * Checks the parts of a sync device without which it is simply unusable. * * A *shape* gate, and since storage version 2 an exact one: both public keys * are 32 raw bytes, so this checks the length and the base64 rather than * bounding a PEM the way it had to when the keys were RSA. * * It is still **not** the check that makes device enrolment safe, and never * was: a well formed record carrying an attacker's public keys passes every * test here. What decides whether one gets this far lives in * `SyncManager.addSyncDevice` and the signature check above it -- the sender * must already be a peer, keys are pinned on first receipt, a removed device * cannot be reintroduced, and a peer-introduced device is announced rather than * added quietly. * @param raw - The device to check, which may be anything at all. * @returns Null when the device is usable, otherwise the reason it is not. */ export declare const validateSyncDevice: (raw: unknown) => string | null; /** * Checks a vault's removal tombstones. * * Refused rather than reset when malformed, like the replay record and for the * same reason: starting over is the repair whose cost is invisible. A vault * that has forgotten what it removed works perfectly and quietly accepts a * device the user revoked. * @param raw - The value to check, which may be anything at all. * @returns Null when it is usable or absent, otherwise the reason it is not. */ export declare const validateRemovedDevices: (raw: unknown) => string | null; /** * Reads a peer's two public keys out of the pairing handshake. * * They arrive encrypted under the JPAKE-derived sync key, so this is not a * trust boundary -- it is what makes a peer on a build that sends a different * shape fail here, while the user is still standing in front of both devices, * rather than at the first command it tries to verify. * @param serialised - The decrypted JSON from the handshake. * @returns The peer's public keys. * @throws {SyncError} If the payload is not a pair of usable public keys. */ export declare const parseDevicePublicKeys: (serialised: string) => DevicePublicKeys;