@quilibrium/quorum-shared 2.1.0-1
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.
- package/dist/index.d.mts +2414 -0
- package/dist/index.d.ts +2414 -0
- package/dist/index.js +2788 -0
- package/dist/index.mjs +2678 -0
- package/package.json +49 -0
- package/src/api/client.ts +86 -0
- package/src/api/endpoints.ts +87 -0
- package/src/api/errors.ts +179 -0
- package/src/api/index.ts +35 -0
- package/src/crypto/encryption-state.ts +249 -0
- package/src/crypto/index.ts +55 -0
- package/src/crypto/types.ts +307 -0
- package/src/crypto/wasm-provider.ts +298 -0
- package/src/hooks/index.ts +31 -0
- package/src/hooks/keys.ts +62 -0
- package/src/hooks/mutations/index.ts +15 -0
- package/src/hooks/mutations/useDeleteMessage.ts +67 -0
- package/src/hooks/mutations/useEditMessage.ts +87 -0
- package/src/hooks/mutations/useReaction.ts +163 -0
- package/src/hooks/mutations/useSendMessage.ts +131 -0
- package/src/hooks/useChannels.ts +49 -0
- package/src/hooks/useMessages.ts +77 -0
- package/src/hooks/useSpaces.ts +60 -0
- package/src/index.ts +32 -0
- package/src/signing/index.ts +10 -0
- package/src/signing/types.ts +83 -0
- package/src/signing/wasm-provider.ts +75 -0
- package/src/storage/adapter.ts +118 -0
- package/src/storage/index.ts +9 -0
- package/src/sync/index.ts +83 -0
- package/src/sync/service.test.ts +822 -0
- package/src/sync/service.ts +947 -0
- package/src/sync/types.ts +267 -0
- package/src/sync/utils.ts +588 -0
- package/src/transport/browser-websocket.ts +299 -0
- package/src/transport/index.ts +34 -0
- package/src/transport/rn-websocket.ts +321 -0
- package/src/transport/types.ts +56 -0
- package/src/transport/websocket.ts +212 -0
- package/src/types/bookmark.ts +29 -0
- package/src/types/conversation.ts +25 -0
- package/src/types/index.ts +57 -0
- package/src/types/message.ts +178 -0
- package/src/types/space.ts +75 -0
- package/src/types/user.ts +72 -0
- package/src/utils/encoding.ts +106 -0
- package/src/utils/formatting.ts +139 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/logger.ts +141 -0
- package/src/utils/mentions.ts +135 -0
- package/src/utils/validation.ts +84 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crypto module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
// Key types
|
|
7
|
+
Ed448Keypair,
|
|
8
|
+
X448Keypair,
|
|
9
|
+
Keypair,
|
|
10
|
+
// Message types
|
|
11
|
+
MessageCiphertext,
|
|
12
|
+
P2PChannelEnvelope,
|
|
13
|
+
// X3DH
|
|
14
|
+
SenderX3DHParams,
|
|
15
|
+
ReceiverX3DHParams,
|
|
16
|
+
// Double ratchet
|
|
17
|
+
NewDoubleRatchetParams,
|
|
18
|
+
DoubleRatchetStateAndMessage,
|
|
19
|
+
DoubleRatchetStateAndEnvelope,
|
|
20
|
+
// Triple ratchet
|
|
21
|
+
PeerInfo,
|
|
22
|
+
NewTripleRatchetParams,
|
|
23
|
+
TripleRatchetStateAndMetadata,
|
|
24
|
+
TripleRatchetStateAndMessage,
|
|
25
|
+
TripleRatchetStateAndEnvelope,
|
|
26
|
+
// Initialization envelope
|
|
27
|
+
InitializationEnvelope,
|
|
28
|
+
// Inbox encryption
|
|
29
|
+
InboxMessageEncryptRequest,
|
|
30
|
+
InboxMessageDecryptRequest,
|
|
31
|
+
// Provider interface
|
|
32
|
+
CryptoProvider,
|
|
33
|
+
} from './types';
|
|
34
|
+
|
|
35
|
+
// Encryption state types and storage interface
|
|
36
|
+
export type {
|
|
37
|
+
// Device and recipient types
|
|
38
|
+
DeviceKeys,
|
|
39
|
+
RecipientInfo,
|
|
40
|
+
EncryptedEnvelope,
|
|
41
|
+
// Storage types
|
|
42
|
+
KeyValueStorageProvider,
|
|
43
|
+
SendingInbox,
|
|
44
|
+
ReceivingInbox,
|
|
45
|
+
EncryptionState,
|
|
46
|
+
InboxMapping,
|
|
47
|
+
LatestState,
|
|
48
|
+
ConversationInboxKeypair,
|
|
49
|
+
EncryptionStateStorageInterface,
|
|
50
|
+
} from './encryption-state';
|
|
51
|
+
export { ENCRYPTION_STORAGE_KEYS } from './encryption-state';
|
|
52
|
+
|
|
53
|
+
// WASM implementation (for desktop/web)
|
|
54
|
+
export { WasmCryptoProvider } from './wasm-provider';
|
|
55
|
+
export type { ChannelWasmModule } from './wasm-provider';
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Crypto types and CryptoProvider interface
|
|
3
|
+
*
|
|
4
|
+
* Platform-agnostic cryptographic operations for E2E encryption.
|
|
5
|
+
* Implementations:
|
|
6
|
+
* - WASM (desktop/web): Uses channel-wasm bindings
|
|
7
|
+
* - Native (iOS/Android): Uses uniffi-generated bindings
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============ Key Types ============
|
|
11
|
+
|
|
12
|
+
export interface Ed448Keypair {
|
|
13
|
+
type: 'ed448';
|
|
14
|
+
public_key: number[];
|
|
15
|
+
private_key: number[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface X448Keypair {
|
|
19
|
+
type: 'x448';
|
|
20
|
+
public_key: number[];
|
|
21
|
+
private_key: number[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type Keypair = Ed448Keypair | X448Keypair;
|
|
25
|
+
|
|
26
|
+
// ============ Message Ciphertext ============
|
|
27
|
+
|
|
28
|
+
export interface MessageCiphertext {
|
|
29
|
+
ciphertext: string;
|
|
30
|
+
initialization_vector: string;
|
|
31
|
+
associated_data?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface P2PChannelEnvelope {
|
|
35
|
+
protocol_identifier: number;
|
|
36
|
+
message_header: MessageCiphertext;
|
|
37
|
+
message_body: MessageCiphertext;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ============ X3DH Key Agreement ============
|
|
41
|
+
|
|
42
|
+
export interface SenderX3DHParams {
|
|
43
|
+
sending_identity_private_key: number[];
|
|
44
|
+
sending_ephemeral_private_key: number[];
|
|
45
|
+
receiving_identity_key: number[];
|
|
46
|
+
receiving_signed_pre_key: number[];
|
|
47
|
+
session_key_length: number;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ReceiverX3DHParams {
|
|
51
|
+
sending_identity_private_key: number[];
|
|
52
|
+
sending_signed_private_key: number[];
|
|
53
|
+
receiving_identity_key: number[];
|
|
54
|
+
receiving_ephemeral_key: number[];
|
|
55
|
+
session_key_length: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ============ Double Ratchet ============
|
|
59
|
+
|
|
60
|
+
export interface NewDoubleRatchetParams {
|
|
61
|
+
session_key: number[];
|
|
62
|
+
sending_header_key: number[];
|
|
63
|
+
next_receiving_header_key: number[];
|
|
64
|
+
is_sender: boolean;
|
|
65
|
+
sending_ephemeral_private_key: number[];
|
|
66
|
+
receiving_ephemeral_key: number[];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface DoubleRatchetStateAndMessage {
|
|
70
|
+
ratchet_state: string;
|
|
71
|
+
message: number[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface DoubleRatchetStateAndEnvelope {
|
|
75
|
+
ratchet_state: string;
|
|
76
|
+
envelope: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ============ Triple Ratchet ============
|
|
80
|
+
|
|
81
|
+
export interface PeerInfo {
|
|
82
|
+
public_key: number[];
|
|
83
|
+
identity_public_key: number[];
|
|
84
|
+
signed_pre_public_key: number[];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface NewTripleRatchetParams {
|
|
88
|
+
peers: number[][];
|
|
89
|
+
peer_key: number[];
|
|
90
|
+
identity_key: number[];
|
|
91
|
+
signed_pre_key: number[];
|
|
92
|
+
threshold: number;
|
|
93
|
+
async_dkg_ratchet: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface TripleRatchetStateAndMetadata {
|
|
97
|
+
ratchet_state: string;
|
|
98
|
+
metadata: Record<string, string>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface TripleRatchetStateAndMessage {
|
|
102
|
+
ratchet_state: string;
|
|
103
|
+
message: number[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface TripleRatchetStateAndEnvelope {
|
|
107
|
+
ratchet_state: string;
|
|
108
|
+
envelope: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ============ Initialization Envelope ============
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* InitializationEnvelope - Contains sender info for first message in a session
|
|
115
|
+
*
|
|
116
|
+
* This is the format BEFORE sealing. The ephemeral_public_key is NOT included here -
|
|
117
|
+
* it goes at the TOP LEVEL of the SealedMessage, and the SAME ephemeral key is used for both:
|
|
118
|
+
* 1. Sealing the envelope (inbox encryption)
|
|
119
|
+
* 2. X3DH session establishment
|
|
120
|
+
*
|
|
121
|
+
* After unsealing, the ephemeral_public_key is added back to create UnsealedEnvelope
|
|
122
|
+
* (see transport/websocket.ts)
|
|
123
|
+
*/
|
|
124
|
+
export interface InitializationEnvelope {
|
|
125
|
+
/** Sender's user address */
|
|
126
|
+
user_address: string;
|
|
127
|
+
/** Sender's display name */
|
|
128
|
+
display_name?: string;
|
|
129
|
+
/** Sender's icon URL */
|
|
130
|
+
user_icon?: string;
|
|
131
|
+
/** Inbox address for sending replies */
|
|
132
|
+
return_inbox_address: string;
|
|
133
|
+
/** X448 encryption key for the return inbox (hex) */
|
|
134
|
+
return_inbox_encryption_key: string;
|
|
135
|
+
/** Ed448 public key for the return inbox (hex) */
|
|
136
|
+
return_inbox_public_key: string;
|
|
137
|
+
/** Ed448 private key for the return inbox (hex) - shared so recipient can sign replies */
|
|
138
|
+
return_inbox_private_key: string;
|
|
139
|
+
/** Sender's identity public key for X3DH (hex) */
|
|
140
|
+
identity_public_key: string;
|
|
141
|
+
/** Session/conversation tag (typically the return inbox address) */
|
|
142
|
+
tag: string;
|
|
143
|
+
/** The Double Ratchet encrypted message envelope */
|
|
144
|
+
message: string;
|
|
145
|
+
/** Message type (e.g., 'direct') */
|
|
146
|
+
type: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ============ Inbox Message Encryption ============
|
|
150
|
+
|
|
151
|
+
export interface InboxMessageEncryptRequest {
|
|
152
|
+
inbox_public_key: number[];
|
|
153
|
+
ephemeral_private_key: number[];
|
|
154
|
+
plaintext: number[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface InboxMessageDecryptRequest {
|
|
158
|
+
inbox_private_key: number[];
|
|
159
|
+
ephemeral_public_key: number[];
|
|
160
|
+
ciphertext: MessageCiphertext;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ============ CryptoProvider Interface ============
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* CryptoProvider - Platform-agnostic interface for cryptographic operations
|
|
167
|
+
*
|
|
168
|
+
* This interface abstracts the underlying crypto implementation,
|
|
169
|
+
* allowing the same code to work with WASM (desktop) or native modules (mobile).
|
|
170
|
+
*
|
|
171
|
+
* All methods are async to support both synchronous WASM and async native bridges.
|
|
172
|
+
* State is serialized as JSON strings for cross-platform compatibility.
|
|
173
|
+
*/
|
|
174
|
+
export interface CryptoProvider {
|
|
175
|
+
// ============ Key Generation ============
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Generate an X448 keypair for encryption
|
|
179
|
+
*/
|
|
180
|
+
generateX448(): Promise<X448Keypair>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Generate an Ed448 keypair for signing
|
|
184
|
+
*/
|
|
185
|
+
generateEd448(): Promise<Ed448Keypair>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Derive public key from X448 private key
|
|
189
|
+
* @param privateKey Base64-encoded private key
|
|
190
|
+
* @returns Base64-encoded public key
|
|
191
|
+
*/
|
|
192
|
+
getPublicKeyX448(privateKey: string): Promise<string>;
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Derive public key from Ed448 private key
|
|
196
|
+
* @param privateKey Base64-encoded private key
|
|
197
|
+
* @returns Base64-encoded public key
|
|
198
|
+
*/
|
|
199
|
+
getPublicKeyEd448(privateKey: string): Promise<string>;
|
|
200
|
+
|
|
201
|
+
// ============ X3DH Key Agreement ============
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Perform sender-side X3DH key agreement
|
|
205
|
+
* @returns Base64-encoded session key (96 bytes: 32 session + 32 sending header + 32 receiving header)
|
|
206
|
+
*/
|
|
207
|
+
senderX3DH(params: SenderX3DHParams): Promise<string>;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Perform receiver-side X3DH key agreement
|
|
211
|
+
* @returns Base64-encoded session key (96 bytes)
|
|
212
|
+
*/
|
|
213
|
+
receiverX3DH(params: ReceiverX3DHParams): Promise<string>;
|
|
214
|
+
|
|
215
|
+
// ============ Double Ratchet ============
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Initialize a new double ratchet session
|
|
219
|
+
* @returns JSON-serialized ratchet state
|
|
220
|
+
*/
|
|
221
|
+
newDoubleRatchet(params: NewDoubleRatchetParams): Promise<string>;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Encrypt a message using double ratchet
|
|
225
|
+
* @returns Updated state and encrypted envelope
|
|
226
|
+
*/
|
|
227
|
+
doubleRatchetEncrypt(
|
|
228
|
+
stateAndMessage: DoubleRatchetStateAndMessage
|
|
229
|
+
): Promise<DoubleRatchetStateAndEnvelope>;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Decrypt a message using double ratchet
|
|
233
|
+
* @returns Updated state and decrypted message
|
|
234
|
+
*/
|
|
235
|
+
doubleRatchetDecrypt(
|
|
236
|
+
stateAndEnvelope: DoubleRatchetStateAndEnvelope
|
|
237
|
+
): Promise<DoubleRatchetStateAndMessage>;
|
|
238
|
+
|
|
239
|
+
// ============ Triple Ratchet ============
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Initialize a new triple ratchet session for group messaging
|
|
243
|
+
* @returns Initial state and DKG metadata
|
|
244
|
+
*/
|
|
245
|
+
newTripleRatchet(params: NewTripleRatchetParams): Promise<TripleRatchetStateAndMetadata>;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Triple ratchet DKG round 1 - Generate polynomial fragments
|
|
249
|
+
*/
|
|
250
|
+
tripleRatchetInitRound1(
|
|
251
|
+
state: TripleRatchetStateAndMetadata
|
|
252
|
+
): Promise<TripleRatchetStateAndMetadata>;
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Triple ratchet DKG round 2 - Receive fragments, compute ZK commitment
|
|
256
|
+
*/
|
|
257
|
+
tripleRatchetInitRound2(
|
|
258
|
+
state: TripleRatchetStateAndMetadata
|
|
259
|
+
): Promise<TripleRatchetStateAndMetadata>;
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Triple ratchet DKG round 3 - Receive commitments, compute ZK reveal
|
|
263
|
+
*/
|
|
264
|
+
tripleRatchetInitRound3(
|
|
265
|
+
state: TripleRatchetStateAndMetadata
|
|
266
|
+
): Promise<TripleRatchetStateAndMetadata>;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Triple ratchet DKG round 4 - Verify proofs, reconstruct group key
|
|
270
|
+
*/
|
|
271
|
+
tripleRatchetInitRound4(
|
|
272
|
+
state: TripleRatchetStateAndMetadata
|
|
273
|
+
): Promise<TripleRatchetStateAndMetadata>;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Encrypt a message for the group using triple ratchet
|
|
277
|
+
*/
|
|
278
|
+
tripleRatchetEncrypt(
|
|
279
|
+
stateAndMessage: TripleRatchetStateAndMessage
|
|
280
|
+
): Promise<TripleRatchetStateAndEnvelope>;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Decrypt a group message using triple ratchet
|
|
284
|
+
*/
|
|
285
|
+
tripleRatchetDecrypt(
|
|
286
|
+
stateAndEnvelope: TripleRatchetStateAndEnvelope
|
|
287
|
+
): Promise<TripleRatchetStateAndMessage>;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Handle group membership changes
|
|
291
|
+
*/
|
|
292
|
+
tripleRatchetResize(state: TripleRatchetStateAndMetadata): Promise<TripleRatchetStateAndMetadata>;
|
|
293
|
+
|
|
294
|
+
// ============ Inbox Message Encryption ============
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Encrypt a message for an inbox (sealed sender / ECIES-style)
|
|
298
|
+
* @returns Base64-encoded sealed message
|
|
299
|
+
*/
|
|
300
|
+
encryptInboxMessage(request: InboxMessageEncryptRequest): Promise<string>;
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Decrypt a sealed inbox message
|
|
304
|
+
* @returns Decrypted plaintext as byte array
|
|
305
|
+
*/
|
|
306
|
+
decryptInboxMessage(request: InboxMessageDecryptRequest): Promise<number[]>;
|
|
307
|
+
}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM CryptoProvider implementation
|
|
3
|
+
*
|
|
4
|
+
* Wraps the channel-wasm WASM module to implement the CryptoProvider interface.
|
|
5
|
+
* Used by desktop/web applications.
|
|
6
|
+
*
|
|
7
|
+
* Note: This file imports from the WASM module dynamically to avoid bundling
|
|
8
|
+
* issues in environments that don't support WASM.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
CryptoProvider,
|
|
13
|
+
Ed448Keypair,
|
|
14
|
+
X448Keypair,
|
|
15
|
+
SenderX3DHParams,
|
|
16
|
+
ReceiverX3DHParams,
|
|
17
|
+
NewDoubleRatchetParams,
|
|
18
|
+
DoubleRatchetStateAndMessage,
|
|
19
|
+
DoubleRatchetStateAndEnvelope,
|
|
20
|
+
NewTripleRatchetParams,
|
|
21
|
+
TripleRatchetStateAndMetadata,
|
|
22
|
+
TripleRatchetStateAndMessage,
|
|
23
|
+
TripleRatchetStateAndEnvelope,
|
|
24
|
+
InboxMessageEncryptRequest,
|
|
25
|
+
InboxMessageDecryptRequest,
|
|
26
|
+
} from './types';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Interface for the WASM module functions
|
|
30
|
+
* This matches the exports from channel-wasm
|
|
31
|
+
*/
|
|
32
|
+
export interface ChannelWasmModule {
|
|
33
|
+
js_generate_x448(): string;
|
|
34
|
+
js_generate_ed448(): string;
|
|
35
|
+
js_get_pubkey_x448(key: string): string;
|
|
36
|
+
js_get_pubkey_ed448(key: string): string;
|
|
37
|
+
js_sign_ed448(key: string, message: string): string;
|
|
38
|
+
js_verify_ed448(publicKey: string, message: string, signature: string): string;
|
|
39
|
+
js_sender_x3dh(input: string): string;
|
|
40
|
+
js_receiver_x3dh(input: string): string;
|
|
41
|
+
js_new_double_ratchet(params: string): string;
|
|
42
|
+
js_double_ratchet_encrypt(params: string): string;
|
|
43
|
+
js_double_ratchet_decrypt(params: string): string;
|
|
44
|
+
js_new_triple_ratchet(params: string): string;
|
|
45
|
+
js_triple_ratchet_init_round_1(params: string): string;
|
|
46
|
+
js_triple_ratchet_init_round_2(params: string): string;
|
|
47
|
+
js_triple_ratchet_init_round_3(params: string): string;
|
|
48
|
+
js_triple_ratchet_init_round_4(params: string): string;
|
|
49
|
+
js_triple_ratchet_encrypt(params: string): string;
|
|
50
|
+
js_triple_ratchet_decrypt(params: string): string;
|
|
51
|
+
js_triple_ratchet_resize(params: string): string;
|
|
52
|
+
js_encrypt_inbox_message(input: string): string;
|
|
53
|
+
js_decrypt_inbox_message(input: string): string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Parse WASM result and check for errors
|
|
58
|
+
* WASM functions return error strings on failure
|
|
59
|
+
*/
|
|
60
|
+
function parseWasmResult<T>(result: string): T {
|
|
61
|
+
// Check for common error patterns
|
|
62
|
+
if (
|
|
63
|
+
result.startsWith('invalid') ||
|
|
64
|
+
result.startsWith('error') ||
|
|
65
|
+
result.includes('failed') ||
|
|
66
|
+
result.includes('Error')
|
|
67
|
+
) {
|
|
68
|
+
throw new Error(result);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(result) as T;
|
|
73
|
+
} catch {
|
|
74
|
+
// If it's not JSON, it might be a quoted string or error
|
|
75
|
+
if (result.startsWith('"') && result.endsWith('"')) {
|
|
76
|
+
// Remove quotes from string results
|
|
77
|
+
return result.slice(1, -1) as unknown as T;
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`Failed to parse WASM result: ${result}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* WasmCryptoProvider - Implements CryptoProvider using channel-wasm
|
|
85
|
+
*/
|
|
86
|
+
export class WasmCryptoProvider implements CryptoProvider {
|
|
87
|
+
private wasm: ChannelWasmModule;
|
|
88
|
+
|
|
89
|
+
constructor(wasmModule: ChannelWasmModule) {
|
|
90
|
+
this.wasm = wasmModule;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ============ Key Generation ============
|
|
94
|
+
|
|
95
|
+
async generateX448(): Promise<X448Keypair> {
|
|
96
|
+
const result = this.wasm.js_generate_x448();
|
|
97
|
+
const keypair = parseWasmResult<{ public_key: number[]; private_key: number[] }>(result);
|
|
98
|
+
return {
|
|
99
|
+
type: 'x448',
|
|
100
|
+
public_key: keypair.public_key,
|
|
101
|
+
private_key: keypair.private_key,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async generateEd448(): Promise<Ed448Keypair> {
|
|
106
|
+
const result = this.wasm.js_generate_ed448();
|
|
107
|
+
const keypair = parseWasmResult<{ public_key: number[]; private_key: number[] }>(result);
|
|
108
|
+
return {
|
|
109
|
+
type: 'ed448',
|
|
110
|
+
public_key: keypair.public_key,
|
|
111
|
+
private_key: keypair.private_key,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async getPublicKeyX448(privateKey: string): Promise<string> {
|
|
116
|
+
const result = this.wasm.js_get_pubkey_x448(privateKey);
|
|
117
|
+
return parseWasmResult<string>(result);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async getPublicKeyEd448(privateKey: string): Promise<string> {
|
|
121
|
+
const result = this.wasm.js_get_pubkey_ed448(privateKey);
|
|
122
|
+
return parseWasmResult<string>(result);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ============ X3DH Key Agreement ============
|
|
126
|
+
|
|
127
|
+
async senderX3DH(params: SenderX3DHParams): Promise<string> {
|
|
128
|
+
const input = JSON.stringify({
|
|
129
|
+
sending_identity_private_key: params.sending_identity_private_key,
|
|
130
|
+
sending_ephemeral_private_key: params.sending_ephemeral_private_key,
|
|
131
|
+
receiving_identity_key: params.receiving_identity_key,
|
|
132
|
+
receiving_signed_pre_key: params.receiving_signed_pre_key,
|
|
133
|
+
session_key_length: params.session_key_length,
|
|
134
|
+
});
|
|
135
|
+
const result = this.wasm.js_sender_x3dh(input);
|
|
136
|
+
if (result.startsWith('invalid') || result.includes('error')) {
|
|
137
|
+
throw new Error(result);
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async receiverX3DH(params: ReceiverX3DHParams): Promise<string> {
|
|
143
|
+
const input = JSON.stringify({
|
|
144
|
+
sending_identity_private_key: params.sending_identity_private_key,
|
|
145
|
+
sending_signed_private_key: params.sending_signed_private_key,
|
|
146
|
+
receiving_identity_key: params.receiving_identity_key,
|
|
147
|
+
receiving_ephemeral_key: params.receiving_ephemeral_key,
|
|
148
|
+
session_key_length: params.session_key_length,
|
|
149
|
+
});
|
|
150
|
+
const result = this.wasm.js_receiver_x3dh(input);
|
|
151
|
+
if (result.startsWith('invalid') || result.includes('error')) {
|
|
152
|
+
throw new Error(result);
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ============ Double Ratchet ============
|
|
158
|
+
|
|
159
|
+
async newDoubleRatchet(params: NewDoubleRatchetParams): Promise<string> {
|
|
160
|
+
const input = JSON.stringify({
|
|
161
|
+
session_key: params.session_key,
|
|
162
|
+
sending_header_key: params.sending_header_key,
|
|
163
|
+
next_receiving_header_key: params.next_receiving_header_key,
|
|
164
|
+
is_sender: params.is_sender,
|
|
165
|
+
sending_ephemeral_private_key: params.sending_ephemeral_private_key,
|
|
166
|
+
receiving_ephemeral_key: params.receiving_ephemeral_key,
|
|
167
|
+
});
|
|
168
|
+
const result = this.wasm.js_new_double_ratchet(input);
|
|
169
|
+
if (result.startsWith('invalid') || result.includes('error')) {
|
|
170
|
+
throw new Error(result);
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async doubleRatchetEncrypt(
|
|
176
|
+
stateAndMessage: DoubleRatchetStateAndMessage
|
|
177
|
+
): Promise<DoubleRatchetStateAndEnvelope> {
|
|
178
|
+
const input = JSON.stringify({
|
|
179
|
+
ratchet_state: stateAndMessage.ratchet_state,
|
|
180
|
+
message: stateAndMessage.message,
|
|
181
|
+
});
|
|
182
|
+
const result = this.wasm.js_double_ratchet_encrypt(input);
|
|
183
|
+
return parseWasmResult<DoubleRatchetStateAndEnvelope>(result);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async doubleRatchetDecrypt(
|
|
187
|
+
stateAndEnvelope: DoubleRatchetStateAndEnvelope
|
|
188
|
+
): Promise<DoubleRatchetStateAndMessage> {
|
|
189
|
+
const input = JSON.stringify({
|
|
190
|
+
ratchet_state: stateAndEnvelope.ratchet_state,
|
|
191
|
+
envelope: stateAndEnvelope.envelope,
|
|
192
|
+
});
|
|
193
|
+
const result = this.wasm.js_double_ratchet_decrypt(input);
|
|
194
|
+
return parseWasmResult<DoubleRatchetStateAndMessage>(result);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ============ Triple Ratchet ============
|
|
198
|
+
|
|
199
|
+
async newTripleRatchet(params: NewTripleRatchetParams): Promise<TripleRatchetStateAndMetadata> {
|
|
200
|
+
const input = JSON.stringify({
|
|
201
|
+
peers: params.peers,
|
|
202
|
+
peer_key: params.peer_key,
|
|
203
|
+
identity_key: params.identity_key,
|
|
204
|
+
signed_pre_key: params.signed_pre_key,
|
|
205
|
+
threshold: params.threshold,
|
|
206
|
+
async_dkg_ratchet: params.async_dkg_ratchet,
|
|
207
|
+
});
|
|
208
|
+
const result = this.wasm.js_new_triple_ratchet(input);
|
|
209
|
+
return parseWasmResult<TripleRatchetStateAndMetadata>(result);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async tripleRatchetInitRound1(
|
|
213
|
+
state: TripleRatchetStateAndMetadata
|
|
214
|
+
): Promise<TripleRatchetStateAndMetadata> {
|
|
215
|
+
const input = JSON.stringify(state);
|
|
216
|
+
const result = this.wasm.js_triple_ratchet_init_round_1(input);
|
|
217
|
+
return parseWasmResult<TripleRatchetStateAndMetadata>(result);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async tripleRatchetInitRound2(
|
|
221
|
+
state: TripleRatchetStateAndMetadata
|
|
222
|
+
): Promise<TripleRatchetStateAndMetadata> {
|
|
223
|
+
const input = JSON.stringify(state);
|
|
224
|
+
const result = this.wasm.js_triple_ratchet_init_round_2(input);
|
|
225
|
+
return parseWasmResult<TripleRatchetStateAndMetadata>(result);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async tripleRatchetInitRound3(
|
|
229
|
+
state: TripleRatchetStateAndMetadata
|
|
230
|
+
): Promise<TripleRatchetStateAndMetadata> {
|
|
231
|
+
const input = JSON.stringify(state);
|
|
232
|
+
const result = this.wasm.js_triple_ratchet_init_round_3(input);
|
|
233
|
+
return parseWasmResult<TripleRatchetStateAndMetadata>(result);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async tripleRatchetInitRound4(
|
|
237
|
+
state: TripleRatchetStateAndMetadata
|
|
238
|
+
): Promise<TripleRatchetStateAndMetadata> {
|
|
239
|
+
const input = JSON.stringify(state);
|
|
240
|
+
const result = this.wasm.js_triple_ratchet_init_round_4(input);
|
|
241
|
+
return parseWasmResult<TripleRatchetStateAndMetadata>(result);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
async tripleRatchetEncrypt(
|
|
245
|
+
stateAndMessage: TripleRatchetStateAndMessage
|
|
246
|
+
): Promise<TripleRatchetStateAndEnvelope> {
|
|
247
|
+
const input = JSON.stringify({
|
|
248
|
+
ratchet_state: stateAndMessage.ratchet_state,
|
|
249
|
+
message: stateAndMessage.message,
|
|
250
|
+
});
|
|
251
|
+
const result = this.wasm.js_triple_ratchet_encrypt(input);
|
|
252
|
+
return parseWasmResult<TripleRatchetStateAndEnvelope>(result);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async tripleRatchetDecrypt(
|
|
256
|
+
stateAndEnvelope: TripleRatchetStateAndEnvelope
|
|
257
|
+
): Promise<TripleRatchetStateAndMessage> {
|
|
258
|
+
const input = JSON.stringify({
|
|
259
|
+
ratchet_state: stateAndEnvelope.ratchet_state,
|
|
260
|
+
envelope: stateAndEnvelope.envelope,
|
|
261
|
+
});
|
|
262
|
+
const result = this.wasm.js_triple_ratchet_decrypt(input);
|
|
263
|
+
return parseWasmResult<TripleRatchetStateAndMessage>(result);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async tripleRatchetResize(
|
|
267
|
+
state: TripleRatchetStateAndMetadata
|
|
268
|
+
): Promise<TripleRatchetStateAndMetadata> {
|
|
269
|
+
const input = JSON.stringify(state);
|
|
270
|
+
const result = this.wasm.js_triple_ratchet_resize(input);
|
|
271
|
+
return parseWasmResult<TripleRatchetStateAndMetadata>(result);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ============ Inbox Message Encryption ============
|
|
275
|
+
|
|
276
|
+
async encryptInboxMessage(request: InboxMessageEncryptRequest): Promise<string> {
|
|
277
|
+
const input = JSON.stringify({
|
|
278
|
+
inbox_public_key: request.inbox_public_key,
|
|
279
|
+
ephemeral_private_key: request.ephemeral_private_key,
|
|
280
|
+
plaintext: request.plaintext,
|
|
281
|
+
});
|
|
282
|
+
const result = this.wasm.js_encrypt_inbox_message(input);
|
|
283
|
+
if (result.startsWith('invalid') || result.includes('error')) {
|
|
284
|
+
throw new Error(result);
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async decryptInboxMessage(request: InboxMessageDecryptRequest): Promise<number[]> {
|
|
290
|
+
const input = JSON.stringify({
|
|
291
|
+
inbox_private_key: request.inbox_private_key,
|
|
292
|
+
ephemeral_public_key: request.ephemeral_public_key,
|
|
293
|
+
ciphertext: request.ciphertext,
|
|
294
|
+
});
|
|
295
|
+
const result = this.wasm.js_decrypt_inbox_message(input);
|
|
296
|
+
return parseWasmResult<number[]>(result);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared React Query hooks
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Query keys
|
|
6
|
+
export { queryKeys } from './keys';
|
|
7
|
+
export type {
|
|
8
|
+
SpacesKey,
|
|
9
|
+
SpaceDetailKey,
|
|
10
|
+
ChannelsKey,
|
|
11
|
+
MessagesInfiniteKey,
|
|
12
|
+
} from './keys';
|
|
13
|
+
|
|
14
|
+
// Space hooks
|
|
15
|
+
export { useSpaces, useSpace, useSpaceMembers } from './useSpaces';
|
|
16
|
+
export type { UseSpacesOptions, UseSpaceOptions } from './useSpaces';
|
|
17
|
+
|
|
18
|
+
// Channel hooks
|
|
19
|
+
export { useChannels, flattenChannels, findChannel } from './useChannels';
|
|
20
|
+
export type { UseChannelsOptions } from './useChannels';
|
|
21
|
+
|
|
22
|
+
// Message hooks
|
|
23
|
+
export {
|
|
24
|
+
useMessages,
|
|
25
|
+
flattenMessages,
|
|
26
|
+
useInvalidateMessages,
|
|
27
|
+
} from './useMessages';
|
|
28
|
+
export type { UseMessagesOptions } from './useMessages';
|
|
29
|
+
|
|
30
|
+
// Mutations (to be added)
|
|
31
|
+
export * from './mutations';
|