/** * 错误类型。消息里绝不包含密钥、令牌或明文。 */ export class WebDropError extends Error { readonly code: string; constructor(code: string, message: string) { super(message); this.name = new.target.name; this.code = code; } } /** 接收方校验失败的原因,与 test-vectors 的 expect 字段对应。 */ export type IntegrityReason = | 'auth_failed' // GCM 认证失败:内容被篡改、头部被改、换了频道或条目 | 'bad_envelope' // 封装格式不合法 | 'wrong_mode' // enc 会话收到没有 ENC 标志的帧,或 raw 会话收到 ENC 帧 | 'bad_padding' // 明文长度字段或填充不合法 | 'bad_meta' // 条目元数据不合法 | 'gap' // 帧序号不连续 | 'item_mismatch' // 同一个流里混入了别的条目的帧 | 'flags_changed' // 同一条目内 SNAPSHOT / GATED 标志不一致 | 'duplicate_mismatch' // 同一 (条目, 序号) 出现了不同内容 | 'frame_after_final' // FINAL 之后又出现了帧 | 'final_conflict' // FINAL 的位置前后矛盾 | 'incomplete'; // 流结束时条目还没有已认证的 FINAL /** 数据被篡改或不符合协议。接收方应丢弃整个条目。 */ export class IntegrityError extends WebDropError { readonly reason: IntegrityReason; constructor(reason: IntegrityReason) { super('integrity', `完整性校验失败: ${reason}`); this.reason = reason; } } export class LinkError extends WebDropError { constructor(message: string) { super('link', message); } } /** 服务端报告的频道模式与链接不符(降级攻击或链接损坏)。 */ export class ModeMismatchError extends WebDropError { constructor() { super('mode_mismatch', '频道模式与链接不一致,已拒绝'); } } /** 当前会话没有这个能力(例如成员链接没有所有者令牌)。 */ export class CapabilityError extends WebDropError { constructor(what: string) { super('capability', `当前链接不具备 ${what} 权限`); } } export class LimitError extends WebDropError { constructor(message: string) { super('limit', message); } }