@meshwhisper/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +138 -0
  2. package/dist/browser/index.d.ts +4 -0
  3. package/dist/browser/index.d.ts.map +1 -0
  4. package/dist/browser/index.js +19 -0
  5. package/dist/browser/index.js.map +1 -0
  6. package/dist/chaff/index.d.ts +91 -0
  7. package/dist/chaff/index.d.ts.map +1 -0
  8. package/dist/chaff/index.js +268 -0
  9. package/dist/chaff/index.js.map +1 -0
  10. package/dist/cluster/index.d.ts +159 -0
  11. package/dist/cluster/index.d.ts.map +1 -0
  12. package/dist/cluster/index.js +393 -0
  13. package/dist/cluster/index.js.map +1 -0
  14. package/dist/compliance/index.d.ts +129 -0
  15. package/dist/compliance/index.d.ts.map +1 -0
  16. package/dist/compliance/index.js +315 -0
  17. package/dist/compliance/index.js.map +1 -0
  18. package/dist/crypto/index.d.ts +65 -0
  19. package/dist/crypto/index.d.ts.map +1 -0
  20. package/dist/crypto/index.js +146 -0
  21. package/dist/crypto/index.js.map +1 -0
  22. package/dist/group/index.d.ts +155 -0
  23. package/dist/group/index.d.ts.map +1 -0
  24. package/dist/group/index.js +560 -0
  25. package/dist/group/index.js.map +1 -0
  26. package/dist/index.d.ts +7 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +11 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/namespace/index.d.ts +155 -0
  31. package/dist/namespace/index.d.ts.map +1 -0
  32. package/dist/namespace/index.js +278 -0
  33. package/dist/namespace/index.js.map +1 -0
  34. package/dist/node/index.d.ts +4 -0
  35. package/dist/node/index.d.ts.map +1 -0
  36. package/dist/node/index.js +19 -0
  37. package/dist/node/index.js.map +1 -0
  38. package/dist/packet/index.d.ts +63 -0
  39. package/dist/packet/index.d.ts.map +1 -0
  40. package/dist/packet/index.js +244 -0
  41. package/dist/packet/index.js.map +1 -0
  42. package/dist/permissions/index.d.ts +107 -0
  43. package/dist/permissions/index.d.ts.map +1 -0
  44. package/dist/permissions/index.js +282 -0
  45. package/dist/permissions/index.js.map +1 -0
  46. package/dist/persistence/idb-storage.d.ts +27 -0
  47. package/dist/persistence/idb-storage.d.ts.map +1 -0
  48. package/dist/persistence/idb-storage.js +75 -0
  49. package/dist/persistence/idb-storage.js.map +1 -0
  50. package/dist/persistence/index.d.ts +4 -0
  51. package/dist/persistence/index.d.ts.map +1 -0
  52. package/dist/persistence/index.js +3 -0
  53. package/dist/persistence/index.js.map +1 -0
  54. package/dist/persistence/node-storage.d.ts +33 -0
  55. package/dist/persistence/node-storage.d.ts.map +1 -0
  56. package/dist/persistence/node-storage.js +90 -0
  57. package/dist/persistence/node-storage.js.map +1 -0
  58. package/dist/persistence/serialization.d.ts +4 -0
  59. package/dist/persistence/serialization.d.ts.map +1 -0
  60. package/dist/persistence/serialization.js +49 -0
  61. package/dist/persistence/serialization.js.map +1 -0
  62. package/dist/persistence/types.d.ts +29 -0
  63. package/dist/persistence/types.d.ts.map +1 -0
  64. package/dist/persistence/types.js +5 -0
  65. package/dist/persistence/types.js.map +1 -0
  66. package/dist/ratchet/index.d.ts +80 -0
  67. package/dist/ratchet/index.d.ts.map +1 -0
  68. package/dist/ratchet/index.js +259 -0
  69. package/dist/ratchet/index.js.map +1 -0
  70. package/dist/reciprocity/index.d.ts +109 -0
  71. package/dist/reciprocity/index.d.ts.map +1 -0
  72. package/dist/reciprocity/index.js +311 -0
  73. package/dist/reciprocity/index.js.map +1 -0
  74. package/dist/relay/index.d.ts +87 -0
  75. package/dist/relay/index.d.ts.map +1 -0
  76. package/dist/relay/index.js +286 -0
  77. package/dist/relay/index.js.map +1 -0
  78. package/dist/routing/index.d.ts +136 -0
  79. package/dist/routing/index.d.ts.map +1 -0
  80. package/dist/routing/index.js +478 -0
  81. package/dist/routing/index.js.map +1 -0
  82. package/dist/sdk/index.d.ts +322 -0
  83. package/dist/sdk/index.d.ts.map +1 -0
  84. package/dist/sdk/index.js +1530 -0
  85. package/dist/sdk/index.js.map +1 -0
  86. package/dist/sybil/index.d.ts +123 -0
  87. package/dist/sybil/index.d.ts.map +1 -0
  88. package/dist/sybil/index.js +491 -0
  89. package/dist/sybil/index.js.map +1 -0
  90. package/dist/transport/browser/index.d.ts +34 -0
  91. package/dist/transport/browser/index.d.ts.map +1 -0
  92. package/dist/transport/browser/index.js +176 -0
  93. package/dist/transport/browser/index.js.map +1 -0
  94. package/dist/transport/local/index.d.ts +57 -0
  95. package/dist/transport/local/index.d.ts.map +1 -0
  96. package/dist/transport/local/index.js +442 -0
  97. package/dist/transport/local/index.js.map +1 -0
  98. package/dist/transport/negotiator/index.d.ts +79 -0
  99. package/dist/transport/negotiator/index.d.ts.map +1 -0
  100. package/dist/transport/negotiator/index.js +289 -0
  101. package/dist/transport/negotiator/index.js.map +1 -0
  102. package/dist/transport/node/index.d.ts +56 -0
  103. package/dist/transport/node/index.d.ts.map +1 -0
  104. package/dist/transport/node/index.js +209 -0
  105. package/dist/transport/node/index.js.map +1 -0
  106. package/dist/transport/noop/index.d.ts +11 -0
  107. package/dist/transport/noop/index.d.ts.map +1 -0
  108. package/dist/transport/noop/index.js +20 -0
  109. package/dist/transport/noop/index.js.map +1 -0
  110. package/dist/transport/p2p/index.d.ts +109 -0
  111. package/dist/transport/p2p/index.d.ts.map +1 -0
  112. package/dist/transport/p2p/index.js +237 -0
  113. package/dist/transport/p2p/index.js.map +1 -0
  114. package/dist/transport/websocket/index.d.ts +89 -0
  115. package/dist/transport/websocket/index.d.ts.map +1 -0
  116. package/dist/transport/websocket/index.js +498 -0
  117. package/dist/transport/websocket/index.js.map +1 -0
  118. package/dist/transport/websocket/serialize.d.ts +5 -0
  119. package/dist/transport/websocket/serialize.d.ts.map +1 -0
  120. package/dist/transport/websocket/serialize.js +55 -0
  121. package/dist/transport/websocket/serialize.js.map +1 -0
  122. package/dist/types.d.ts +215 -0
  123. package/dist/types.d.ts.map +1 -0
  124. package/dist/types.js +15 -0
  125. package/dist/types.js.map +1 -0
  126. package/dist/x3dh/index.d.ts +120 -0
  127. package/dist/x3dh/index.d.ts.map +1 -0
  128. package/dist/x3dh/index.js +290 -0
  129. package/dist/x3dh/index.js.map +1 -0
  130. package/package.json +59 -0
  131. package/src/browser/index.ts +19 -0
  132. package/src/chaff/index.ts +340 -0
  133. package/src/cluster/index.ts +482 -0
  134. package/src/compliance/index.ts +407 -0
  135. package/src/crypto/index.ts +193 -0
  136. package/src/group/index.ts +719 -0
  137. package/src/index.ts +87 -0
  138. package/src/lz4js.d.ts +58 -0
  139. package/src/namespace/index.ts +336 -0
  140. package/src/node/index.ts +19 -0
  141. package/src/packet/index.ts +326 -0
  142. package/src/permissions/index.ts +405 -0
  143. package/src/persistence/idb-storage.ts +83 -0
  144. package/src/persistence/index.ts +3 -0
  145. package/src/persistence/node-storage.ts +96 -0
  146. package/src/persistence/serialization.ts +75 -0
  147. package/src/persistence/types.ts +33 -0
  148. package/src/ratchet/index.ts +363 -0
  149. package/src/reciprocity/index.ts +371 -0
  150. package/src/relay/index.ts +382 -0
  151. package/src/routing/index.ts +577 -0
  152. package/src/sdk/index.ts +1994 -0
  153. package/src/sybil/index.ts +661 -0
  154. package/src/transport/browser/index.ts +201 -0
  155. package/src/transport/local/index.ts +540 -0
  156. package/src/transport/negotiator/index.ts +397 -0
  157. package/src/transport/node/index.ts +234 -0
  158. package/src/transport/noop/index.ts +22 -0
  159. package/src/transport/p2p/index.ts +345 -0
  160. package/src/transport/websocket/index.ts +660 -0
  161. package/src/transport/websocket/serialize.ts +68 -0
  162. package/src/types.ts +275 -0
  163. package/src/x3dh/index.ts +388 -0
@@ -0,0 +1,244 @@
1
+ // ============================================================
2
+ // MeshWhisper SDK — Binary Packet Codec
3
+ // Encodes/decodes the wire format defined in PRD section 9.
4
+ // ============================================================
5
+ import { PacketFlags } from '../types.js';
6
+ import lz4 from 'lz4js';
7
+ import { randomBytes } from 'node:crypto';
8
+ // ---------------------------------------------------------------------------
9
+ // Constants
10
+ // ---------------------------------------------------------------------------
11
+ /** Current protocol wire version. */
12
+ export const PROTOCOL_VERSION = 0x01;
13
+ /** Fixed header size in bytes (version + flags + dest_hash + sender_eph_id + ttl + payload_length). */
14
+ export const HEADER_SIZE = 29;
15
+ /** Maximum hop count. */
16
+ export const MAX_TTL = 7;
17
+ /** Maximum encrypted payload size (uint16 max). */
18
+ export const MAX_PAYLOAD_SIZE = 65535;
19
+ // Internal field offsets within the header.
20
+ const OFF_VERSION = 0;
21
+ const OFF_FLAGS = 1;
22
+ const OFF_DEST_HASH = 2;
23
+ const OFF_SENDER_EPH_ID = 10; // 2 + 8
24
+ const OFF_TTL = 26; // 10 + 16
25
+ const OFF_PAYLOAD_LEN = 27; // 26 + 1
26
+ // ---------------------------------------------------------------------------
27
+ // Validation helpers
28
+ // ---------------------------------------------------------------------------
29
+ function assertUint8Array(value, expectedLen, name) {
30
+ if (!(value instanceof Uint8Array)) {
31
+ throw new TypeError(`${name} must be a Uint8Array`);
32
+ }
33
+ if (value.length !== expectedLen) {
34
+ throw new RangeError(`${name} must be exactly ${expectedLen} bytes, got ${value.length}`);
35
+ }
36
+ }
37
+ function assertValidFlags(flags) {
38
+ const valid = [
39
+ PacketFlags.DATA,
40
+ PacketFlags.ACK,
41
+ PacketFlags.CHAFF,
42
+ PacketFlags.HANDSHAKE,
43
+ PacketFlags.ROUTE_REQUEST,
44
+ PacketFlags.ROUTE_OFFER,
45
+ ];
46
+ if (!valid.includes(flags)) {
47
+ throw new RangeError(`Invalid packet flags: 0x${flags.toString(16).padStart(2, '0')}`);
48
+ }
49
+ }
50
+ // ---------------------------------------------------------------------------
51
+ // Encoding
52
+ // ---------------------------------------------------------------------------
53
+ /**
54
+ * Serialize a {@link Packet} into its binary wire representation.
55
+ *
56
+ * Layout (29-byte header + variable payload):
57
+ * | version (1) | flags (1) | dest_hash (8) | sender_ephemeral_id (16) | ttl (1) | payload_length (2 BE) | encrypted_payload (N) |
58
+ */
59
+ export function encodePacket(packet) {
60
+ // --- Field validation ---
61
+ if (packet.version !== PROTOCOL_VERSION) {
62
+ throw new RangeError(`Unsupported protocol version: ${packet.version}`);
63
+ }
64
+ assertValidFlags(packet.flags);
65
+ assertUint8Array(packet.destHash, 8, 'destHash');
66
+ assertUint8Array(packet.senderEphemeralId, 16, 'senderEphemeralId');
67
+ if (!Number.isInteger(packet.ttl) || packet.ttl < 0 || packet.ttl > MAX_TTL) {
68
+ throw new RangeError(`ttl must be an integer between 0 and ${MAX_TTL}, got ${packet.ttl}`);
69
+ }
70
+ if (!(packet.encryptedPayload instanceof Uint8Array)) {
71
+ throw new TypeError('encryptedPayload must be a Uint8Array');
72
+ }
73
+ if (packet.encryptedPayload.length > MAX_PAYLOAD_SIZE) {
74
+ throw new RangeError(`encryptedPayload exceeds maximum size of ${MAX_PAYLOAD_SIZE} bytes (got ${packet.encryptedPayload.length})`);
75
+ }
76
+ // --- Serialise ---
77
+ const payloadLen = packet.encryptedPayload.length;
78
+ const buf = new Uint8Array(HEADER_SIZE + payloadLen);
79
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
80
+ buf[OFF_VERSION] = packet.version;
81
+ buf[OFF_FLAGS] = packet.flags;
82
+ buf.set(packet.destHash, OFF_DEST_HASH);
83
+ buf.set(packet.senderEphemeralId, OFF_SENDER_EPH_ID);
84
+ buf[OFF_TTL] = packet.ttl;
85
+ view.setUint16(OFF_PAYLOAD_LEN, payloadLen, false); // big-endian
86
+ buf.set(packet.encryptedPayload, HEADER_SIZE);
87
+ return buf;
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // Decoding
91
+ // ---------------------------------------------------------------------------
92
+ /**
93
+ * Deserialize a binary buffer into a {@link Packet}.
94
+ *
95
+ * @throws on malformed input (too short, wrong version, invalid flags, length mismatch).
96
+ */
97
+ export function decodePacket(data) {
98
+ if (!(data instanceof Uint8Array)) {
99
+ throw new TypeError('data must be a Uint8Array');
100
+ }
101
+ if (data.length < HEADER_SIZE) {
102
+ throw new RangeError(`Packet too short: expected at least ${HEADER_SIZE} bytes, got ${data.length}`);
103
+ }
104
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
105
+ const version = data[OFF_VERSION];
106
+ if (version !== PROTOCOL_VERSION) {
107
+ throw new RangeError(`Unsupported protocol version: ${version}`);
108
+ }
109
+ const flags = data[OFF_FLAGS];
110
+ assertValidFlags(flags);
111
+ const destHash = data.slice(OFF_DEST_HASH, OFF_DEST_HASH + 8);
112
+ const senderEphemeralId = data.slice(OFF_SENDER_EPH_ID, OFF_SENDER_EPH_ID + 16);
113
+ const ttl = data[OFF_TTL];
114
+ if (ttl > MAX_TTL) {
115
+ throw new RangeError(`ttl exceeds maximum of ${MAX_TTL}: got ${ttl}`);
116
+ }
117
+ const payloadLength = view.getUint16(OFF_PAYLOAD_LEN, false); // big-endian
118
+ if (data.length < HEADER_SIZE + payloadLength) {
119
+ throw new RangeError(`Packet truncated: header declares ${payloadLength} payload bytes, but only ${data.length - HEADER_SIZE} available`);
120
+ }
121
+ const encryptedPayload = data.slice(HEADER_SIZE, HEADER_SIZE + payloadLength);
122
+ return {
123
+ version,
124
+ flags,
125
+ destHash,
126
+ senderEphemeralId,
127
+ ttl,
128
+ payloadLength,
129
+ encryptedPayload,
130
+ };
131
+ }
132
+ // ---------------------------------------------------------------------------
133
+ // LZ4 Compression (applied to plaintext BEFORE encryption)
134
+ // ---------------------------------------------------------------------------
135
+ /**
136
+ * Compress a plaintext payload with LZ4 (frame format).
137
+ */
138
+ export function compressPayload(plaintext) {
139
+ if (!(plaintext instanceof Uint8Array)) {
140
+ throw new TypeError('plaintext must be a Uint8Array');
141
+ }
142
+ // lz4js.compress returns a Buffer/Uint8Array of the compressed frame.
143
+ const compressed = lz4.compress(plaintext);
144
+ return new Uint8Array(compressed);
145
+ }
146
+ /**
147
+ * Decompress an LZ4 compressed payload back to plaintext.
148
+ */
149
+ export function decompressPayload(compressed) {
150
+ if (!(compressed instanceof Uint8Array)) {
151
+ throw new TypeError('compressed must be a Uint8Array');
152
+ }
153
+ const decompressed = lz4.decompress(compressed);
154
+ return new Uint8Array(decompressed);
155
+ }
156
+ // ---------------------------------------------------------------------------
157
+ // Packet builders
158
+ // ---------------------------------------------------------------------------
159
+ /**
160
+ * Build a DATA packet.
161
+ *
162
+ * @param destHash 8-byte truncated BLAKE3 destination hash
163
+ * @param senderEphId 16-byte rotating ephemeral sender identifier
164
+ * @param payload Encrypted payload bytes
165
+ * @param ttl Hop count (0-7, defaults to {@link MAX_TTL})
166
+ */
167
+ export function createDataPacket(destHash, senderEphId, payload, ttl = MAX_TTL) {
168
+ return buildPacket(PacketFlags.DATA, destHash, senderEphId, payload, ttl);
169
+ }
170
+ /**
171
+ * Build an ACK packet (ttl fixed at 0 since ACKs are single-hop).
172
+ */
173
+ export function createAckPacket(destHash, senderEphId, ackPayload) {
174
+ return buildPacket(PacketFlags.ACK, destHash, senderEphId, ackPayload, 0);
175
+ }
176
+ /**
177
+ * Build a CHAFF (cover-traffic) packet with random destination and payload.
178
+ *
179
+ * The payload length is randomly chosen between 32 and 256 bytes to mimic
180
+ * realistic traffic without being trivially distinguishable.
181
+ */
182
+ export function createChaffPacket(senderEphId) {
183
+ const destHash = randomUint8Array(8);
184
+ const payloadLen = 32 + (randomUint8Array(1)[0] % 225); // 32..256
185
+ const payload = randomUint8Array(payloadLen);
186
+ return buildPacket(PacketFlags.CHAFF, destHash, senderEphId, payload, 0);
187
+ }
188
+ /**
189
+ * Build a ROUTE_REQUEST packet.
190
+ */
191
+ export function createRouteRequestPacket(destHash, senderEphId, requestPayload) {
192
+ return buildPacket(PacketFlags.ROUTE_REQUEST, destHash, senderEphId, requestPayload, MAX_TTL);
193
+ }
194
+ /**
195
+ * Build a ROUTE_OFFER packet.
196
+ */
197
+ export function createRouteOfferPacket(destHash, senderEphId, offerPayload) {
198
+ return buildPacket(PacketFlags.ROUTE_OFFER, destHash, senderEphId, offerPayload, MAX_TTL);
199
+ }
200
+ /**
201
+ * Build a HANDSHAKE packet.
202
+ */
203
+ export function createHandshakePacket(destHash, senderEphId, handshakePayload) {
204
+ return buildPacket(PacketFlags.HANDSHAKE, destHash, senderEphId, handshakePayload, MAX_TTL);
205
+ }
206
+ // ---------------------------------------------------------------------------
207
+ // Internal helpers
208
+ // ---------------------------------------------------------------------------
209
+ function buildPacket(flags, destHash, senderEphId, encryptedPayload, ttl) {
210
+ assertUint8Array(destHash, 8, 'destHash');
211
+ assertUint8Array(senderEphId, 16, 'senderEphemeralId');
212
+ if (!Number.isInteger(ttl) || ttl < 0 || ttl > MAX_TTL) {
213
+ throw new RangeError(`ttl must be an integer between 0 and ${MAX_TTL}, got ${ttl}`);
214
+ }
215
+ if (!(encryptedPayload instanceof Uint8Array)) {
216
+ throw new TypeError('payload must be a Uint8Array');
217
+ }
218
+ if (encryptedPayload.length > MAX_PAYLOAD_SIZE) {
219
+ throw new RangeError(`Payload exceeds maximum size of ${MAX_PAYLOAD_SIZE} bytes (got ${encryptedPayload.length})`);
220
+ }
221
+ return {
222
+ version: PROTOCOL_VERSION,
223
+ flags,
224
+ destHash,
225
+ senderEphemeralId: senderEphId,
226
+ ttl,
227
+ payloadLength: encryptedPayload.length,
228
+ encryptedPayload,
229
+ };
230
+ }
231
+ /**
232
+ * Generate a Uint8Array filled with cryptographically secure random bytes.
233
+ */
234
+ function randomUint8Array(length) {
235
+ // Works in both Node.js and browser contexts.
236
+ if (typeof globalThis.crypto !== 'undefined' && typeof globalThis.crypto.getRandomValues === 'function') {
237
+ const buf = new Uint8Array(length);
238
+ globalThis.crypto.getRandomValues(buf);
239
+ return buf;
240
+ }
241
+ // Fallback: Node.js crypto module (already imported).
242
+ return new Uint8Array(randomBytes(length));
243
+ }
244
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/packet/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ import type { PermissionModel } from '../types';
2
+ export interface ContactContext {
3
+ senderId: string;
4
+ senderPublicKey: Uint8Array;
5
+ timestamp: number;
6
+ introductionBy?: string;
7
+ transactionEvent?: string;
8
+ }
9
+ export interface PermissionOptions {
10
+ customHandler?: (senderId: string, context: ContactContext) => boolean | Promise<boolean>;
11
+ transactionVerifier?: (senderId: string, event: string) => boolean | Promise<boolean>;
12
+ allowList?: Set<string>;
13
+ blockList?: Set<string>;
14
+ }
15
+ export interface ContactRequest {
16
+ id: string;
17
+ fromPeerId: string;
18
+ toPeerId: string;
19
+ timestamp: number;
20
+ status: 'pending' | 'accepted' | 'rejected';
21
+ }
22
+ export interface IntroductionRequest {
23
+ id: string;
24
+ fromPeerId: string;
25
+ toPeerId: string;
26
+ introducerPeerId: string;
27
+ timestamp: number;
28
+ status: 'pending' | 'introduced' | 'accepted' | 'rejected';
29
+ }
30
+ export declare class PermissionManager {
31
+ private model;
32
+ private readonly customHandler?;
33
+ private readonly transactionVerifier?;
34
+ private readonly contacts;
35
+ private readonly blocked;
36
+ private readonly allowed;
37
+ /** Peers who have sent us a contact request (mutual model). */
38
+ private readonly inboundRequests;
39
+ /** Peers we have sent a contact request to (mutual model). */
40
+ private readonly outboundRequests;
41
+ /** Introduction requests keyed by request id. */
42
+ private readonly introductionRequests;
43
+ /** Peers whose mutual contact has been confirmed (both sides accepted). */
44
+ private readonly mutualConfirmed;
45
+ /** Peers introduced to us via a trusted intermediary. */
46
+ private readonly introducedPeers;
47
+ constructor(model: PermissionModel, options?: PermissionOptions);
48
+ setModel(model: PermissionModel): void;
49
+ getModel(): PermissionModel;
50
+ addContact(peerId: string): void;
51
+ removeContact(peerId: string): void;
52
+ isContact(peerId: string): boolean;
53
+ getContacts(): string[];
54
+ loadContacts(contacts: string[]): void;
55
+ blockPeer(peerId: string): void;
56
+ unblockPeer(peerId: string): void;
57
+ isBlocked(peerId: string): boolean;
58
+ /**
59
+ * Main inbound permission check.
60
+ * Order: blockList -> allowList -> model-specific logic.
61
+ */
62
+ canReceiveFrom(senderId: string, context: ContactContext): Promise<boolean>;
63
+ /**
64
+ * Outbound permission check — can we send to this recipient?
65
+ * Primarily relevant for the mutual model where both sides
66
+ * need to have each other as contacts.
67
+ */
68
+ canSendTo(recipientId: string): Promise<boolean>;
69
+ /**
70
+ * Create a contact request to send to a peer (mutual model).
71
+ * The caller is responsible for transmitting the request over the wire.
72
+ */
73
+ requestMutualContact(peerId: string): ContactRequest;
74
+ /**
75
+ * Handle an inbound contact request from a peer.
76
+ * Returns true if the request is accepted (i.e. we already have an
77
+ * outbound request to that peer, achieving mutual consent), false
78
+ * if the request is stored as pending.
79
+ */
80
+ handleContactRequest(request: ContactRequest): boolean;
81
+ /**
82
+ * Explicitly confirm mutual contact with a peer.
83
+ * Adds the peer to contacts and the mutualConfirmed set.
84
+ */
85
+ confirmMutualContact(peerId: string): void;
86
+ /**
87
+ * Request an introduction to a target peer through a mutual contact.
88
+ * The caller is responsible for transmitting the request to the introducer.
89
+ */
90
+ requestIntroduction(targetPeerId: string, introducerPeerId: string): IntroductionRequest;
91
+ /**
92
+ * Handle an introduction request as the intermediary.
93
+ * Returns true if the introducer is a known contact of ours (trusted),
94
+ * false otherwise (the intermediary should only broker introductions
95
+ * between their own contacts).
96
+ */
97
+ handleIntroductionRequest(request: IntroductionRequest): boolean;
98
+ /**
99
+ * Confirm an introduction — called on the receiving end once the
100
+ * introduction has been brokered by the intermediary.
101
+ */
102
+ confirmIntroduction(request: IntroductionRequest): void;
103
+ private checkIntroduction;
104
+ private checkTransaction;
105
+ private checkCustom;
106
+ }
107
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/permissions/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,282 @@
1
+ // ============================================================
2
+ // MeshWhisper SDK — Contact Permissions Module
3
+ // Endpoint-side permission enforcement for P2P contact initiation.
4
+ // ============================================================
5
+ // --- Helpers ---
6
+ function generateId() {
7
+ const bytes = new Uint8Array(16);
8
+ crypto.getRandomValues(bytes);
9
+ return Array.from(bytes)
10
+ .map((b) => b.toString(16).padStart(2, '0'))
11
+ .join('');
12
+ }
13
+ // --- PermissionManager ---
14
+ export class PermissionManager {
15
+ model;
16
+ customHandler;
17
+ transactionVerifier;
18
+ contacts = new Set();
19
+ blocked = new Set();
20
+ allowed = new Set();
21
+ /** Peers who have sent us a contact request (mutual model). */
22
+ inboundRequests = new Map();
23
+ /** Peers we have sent a contact request to (mutual model). */
24
+ outboundRequests = new Map();
25
+ /** Introduction requests keyed by request id. */
26
+ introductionRequests = new Map();
27
+ /** Peers whose mutual contact has been confirmed (both sides accepted). */
28
+ mutualConfirmed = new Set();
29
+ /** Peers introduced to us via a trusted intermediary. */
30
+ introducedPeers = new Set();
31
+ constructor(model, options) {
32
+ this.model = model;
33
+ if (options?.customHandler) {
34
+ this.customHandler = options.customHandler;
35
+ }
36
+ if (options?.transactionVerifier) {
37
+ this.transactionVerifier = options.transactionVerifier;
38
+ }
39
+ if (options?.allowList) {
40
+ for (const id of options.allowList) {
41
+ this.allowed.add(id);
42
+ }
43
+ }
44
+ if (options?.blockList) {
45
+ for (const id of options.blockList) {
46
+ this.blocked.add(id);
47
+ }
48
+ }
49
+ }
50
+ // ------------------------------------------------------------------
51
+ // Model switching
52
+ // ------------------------------------------------------------------
53
+ setModel(model) {
54
+ this.model = model;
55
+ }
56
+ getModel() {
57
+ return this.model;
58
+ }
59
+ // ------------------------------------------------------------------
60
+ // Contact management
61
+ // ------------------------------------------------------------------
62
+ addContact(peerId) {
63
+ this.contacts.add(peerId);
64
+ }
65
+ removeContact(peerId) {
66
+ this.contacts.delete(peerId);
67
+ this.mutualConfirmed.delete(peerId);
68
+ }
69
+ isContact(peerId) {
70
+ return this.contacts.has(peerId);
71
+ }
72
+ getContacts() {
73
+ return Array.from(this.contacts);
74
+ }
75
+ loadContacts(contacts) {
76
+ for (const id of contacts)
77
+ this.contacts.add(id);
78
+ }
79
+ blockPeer(peerId) {
80
+ this.blocked.add(peerId);
81
+ }
82
+ unblockPeer(peerId) {
83
+ this.blocked.delete(peerId);
84
+ }
85
+ isBlocked(peerId) {
86
+ return this.blocked.has(peerId);
87
+ }
88
+ // ------------------------------------------------------------------
89
+ // Permission checks
90
+ // ------------------------------------------------------------------
91
+ /**
92
+ * Main inbound permission check.
93
+ * Order: blockList -> allowList -> model-specific logic.
94
+ */
95
+ async canReceiveFrom(senderId, context) {
96
+ // Always deny blocked peers.
97
+ if (this.blocked.has(senderId)) {
98
+ return false;
99
+ }
100
+ // Always allow explicitly allowed peers.
101
+ if (this.allowed.has(senderId)) {
102
+ return true;
103
+ }
104
+ // Existing contacts are always permitted regardless of model.
105
+ if (this.contacts.has(senderId)) {
106
+ return true;
107
+ }
108
+ switch (this.model) {
109
+ case 'open':
110
+ return true;
111
+ case 'mutual':
112
+ return this.mutualConfirmed.has(senderId);
113
+ case 'introduction':
114
+ return this.introducedPeers.has(senderId) || this.checkIntroduction(senderId, context);
115
+ case 'transactional':
116
+ return this.checkTransaction(senderId, context);
117
+ case 'custom':
118
+ return this.checkCustom(senderId, context);
119
+ default:
120
+ return false;
121
+ }
122
+ }
123
+ /**
124
+ * Outbound permission check — can we send to this recipient?
125
+ * Primarily relevant for the mutual model where both sides
126
+ * need to have each other as contacts.
127
+ */
128
+ async canSendTo(recipientId) {
129
+ // Never send to blocked peers.
130
+ if (this.blocked.has(recipientId)) {
131
+ return false;
132
+ }
133
+ // Always allowed peers.
134
+ if (this.allowed.has(recipientId)) {
135
+ return true;
136
+ }
137
+ switch (this.model) {
138
+ case 'open':
139
+ return true;
140
+ case 'mutual':
141
+ // Can only send if mutual contact has been confirmed or they are
142
+ // already a known contact.
143
+ return this.contacts.has(recipientId) || this.mutualConfirmed.has(recipientId);
144
+ case 'introduction':
145
+ return (this.contacts.has(recipientId) || this.introducedPeers.has(recipientId));
146
+ case 'transactional':
147
+ // For outbound in transactional model, allow if they are a contact.
148
+ return this.contacts.has(recipientId);
149
+ case 'custom':
150
+ // Custom model defers to the handler for inbound only;
151
+ // outbound is permitted to any non-blocked peer.
152
+ return true;
153
+ default:
154
+ return false;
155
+ }
156
+ }
157
+ // ------------------------------------------------------------------
158
+ // Mutual model logic
159
+ // ------------------------------------------------------------------
160
+ /**
161
+ * Create a contact request to send to a peer (mutual model).
162
+ * The caller is responsible for transmitting the request over the wire.
163
+ */
164
+ requestMutualContact(peerId) {
165
+ const request = {
166
+ id: generateId(),
167
+ fromPeerId: '', // Will be filled by the caller with own peer ID
168
+ toPeerId: peerId,
169
+ timestamp: Date.now(),
170
+ status: 'pending',
171
+ };
172
+ this.outboundRequests.set(peerId, request);
173
+ return request;
174
+ }
175
+ /**
176
+ * Handle an inbound contact request from a peer.
177
+ * Returns true if the request is accepted (i.e. we already have an
178
+ * outbound request to that peer, achieving mutual consent), false
179
+ * if the request is stored as pending.
180
+ */
181
+ handleContactRequest(request) {
182
+ if (this.blocked.has(request.fromPeerId)) {
183
+ request.status = 'rejected';
184
+ return false;
185
+ }
186
+ this.inboundRequests.set(request.fromPeerId, request);
187
+ // If we already sent a request to this peer, auto-confirm mutual contact.
188
+ if (this.outboundRequests.has(request.fromPeerId)) {
189
+ request.status = 'accepted';
190
+ const outbound = this.outboundRequests.get(request.fromPeerId);
191
+ outbound.status = 'accepted';
192
+ this.confirmMutualContact(request.fromPeerId);
193
+ return true;
194
+ }
195
+ return false;
196
+ }
197
+ /**
198
+ * Explicitly confirm mutual contact with a peer.
199
+ * Adds the peer to contacts and the mutualConfirmed set.
200
+ */
201
+ confirmMutualContact(peerId) {
202
+ this.mutualConfirmed.add(peerId);
203
+ this.contacts.add(peerId);
204
+ }
205
+ // ------------------------------------------------------------------
206
+ // Introduction model logic
207
+ // ------------------------------------------------------------------
208
+ /**
209
+ * Request an introduction to a target peer through a mutual contact.
210
+ * The caller is responsible for transmitting the request to the introducer.
211
+ */
212
+ requestIntroduction(targetPeerId, introducerPeerId) {
213
+ const request = {
214
+ id: generateId(),
215
+ fromPeerId: '', // Will be filled by the caller with own peer ID
216
+ toPeerId: targetPeerId,
217
+ introducerPeerId,
218
+ timestamp: Date.now(),
219
+ status: 'pending',
220
+ };
221
+ this.introductionRequests.set(request.id, request);
222
+ return request;
223
+ }
224
+ /**
225
+ * Handle an introduction request as the intermediary.
226
+ * Returns true if the introducer is a known contact of ours (trusted),
227
+ * false otherwise (the intermediary should only broker introductions
228
+ * between their own contacts).
229
+ */
230
+ handleIntroductionRequest(request) {
231
+ if (this.blocked.has(request.fromPeerId)) {
232
+ request.status = 'rejected';
233
+ return false;
234
+ }
235
+ // The intermediary should know both parties as contacts.
236
+ const knowsSender = this.contacts.has(request.fromPeerId);
237
+ const knowsTarget = this.contacts.has(request.toPeerId);
238
+ if (knowsSender && knowsTarget) {
239
+ request.status = 'introduced';
240
+ this.introductionRequests.set(request.id, request);
241
+ return true;
242
+ }
243
+ request.status = 'rejected';
244
+ this.introductionRequests.set(request.id, request);
245
+ return false;
246
+ }
247
+ /**
248
+ * Confirm an introduction — called on the receiving end once the
249
+ * introduction has been brokered by the intermediary.
250
+ */
251
+ confirmIntroduction(request) {
252
+ request.status = 'accepted';
253
+ this.introductionRequests.set(request.id, request);
254
+ this.introducedPeers.add(request.fromPeerId);
255
+ this.contacts.add(request.fromPeerId);
256
+ }
257
+ // ------------------------------------------------------------------
258
+ // Private model-specific checks
259
+ // ------------------------------------------------------------------
260
+ checkIntroduction(senderId, context) {
261
+ // If the context carries a valid introduction reference, check it.
262
+ if (context.introductionBy) {
263
+ // The introducer must be one of our contacts.
264
+ return this.contacts.has(context.introductionBy);
265
+ }
266
+ return false;
267
+ }
268
+ async checkTransaction(senderId, context) {
269
+ if (!this.transactionVerifier || !context.transactionEvent) {
270
+ return false;
271
+ }
272
+ return this.transactionVerifier(senderId, context.transactionEvent);
273
+ }
274
+ async checkCustom(senderId, context) {
275
+ if (!this.customHandler) {
276
+ // No custom handler configured — deny by default for safety.
277
+ return false;
278
+ }
279
+ return this.customHandler(senderId, context);
280
+ }
281
+ }
282
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/permissions/index.ts"],"names":[],"mappings":"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"}