@k9o/react-native-matrix-crypto 1.0.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.
@@ -0,0 +1,157 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+
3
+ const LINKING_ERROR =
4
+ `The package 'react-native-matrix-crypto' doesn't seem to be linked. Make sure: \n\n` +
5
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
6
+ '- You rebuilt the app after installing the package\n' +
7
+ '- You are not using Expo Go\n';
8
+
9
+ const NativeMatrixCryptoModule = NativeModules.RNMatrixCrypto
10
+ ? NativeModules.RNMatrixCrypto
11
+ : new Proxy(
12
+ {},
13
+ {
14
+ get() {
15
+ throw new Error(LINKING_ERROR);
16
+ },
17
+ }
18
+ );
19
+
20
+ /**
21
+ * Native module interface for Matrix crypto
22
+ * This is the low-level binding to the native iOS/Android modules
23
+ */
24
+ export interface NativeMatrixCryptoInterface {
25
+ // Initialization
26
+ initialize(userId: string, deviceId: string, pickleKey: string): Promise<{ success: boolean }>;
27
+
28
+ // Device Information
29
+ getDeviceFingerprint(): Promise<string>;
30
+ getUserId(): Promise<string>;
31
+ getDeviceId(): Promise<string>;
32
+
33
+ // Device Management
34
+ getUserDevices(userId: string): Promise<Array<{
35
+ deviceId: string;
36
+ userId: string;
37
+ displayName?: string;
38
+ fingerprint: string;
39
+ isVerified: boolean;
40
+ isBlocked: boolean;
41
+ algorithm: string;
42
+ }>>;
43
+
44
+ addDevice(device: {
45
+ deviceId: string;
46
+ userId: string;
47
+ displayName?: string;
48
+ fingerprint: string;
49
+ isVerified: boolean;
50
+ isBlocked: boolean;
51
+ algorithm: string;
52
+ }): Promise<{ success: boolean }>;
53
+
54
+ // Device Verification
55
+ startVerification(otherUserId: string, otherDeviceId: string): Promise<{
56
+ verificationId: string;
57
+ state: string;
58
+ otherUserId: string;
59
+ otherDeviceId: string;
60
+ emojis: Array<{ emoji: string; name: string }>;
61
+ decimals: number[];
62
+ }>;
63
+
64
+ getSASEmojis(verificationId: string): Promise<Array<{ emoji: string; name: string }>>;
65
+
66
+ confirmSAS(verificationId: string): Promise<{ success: boolean }>;
67
+
68
+ completeVerification(verificationId: string): Promise<{ success: boolean }>;
69
+
70
+ cancelVerification(verificationId: string): Promise<{ success: boolean }>;
71
+
72
+ getVerificationState(verificationId: string): Promise<{
73
+ verificationId: string;
74
+ state: string;
75
+ otherUserId: string;
76
+ otherDeviceId: string;
77
+ emojis: Array<{ emoji: string; name: string }>;
78
+ decimals: number[];
79
+ }>;
80
+
81
+ // Room Encryption
82
+ enableRoomEncryption(roomId: string, algorithm: string): Promise<{ success: boolean }>;
83
+
84
+ getRoomEncryptionState(roomId: string): Promise<{
85
+ roomId: string;
86
+ isEncrypted: boolean;
87
+ algorithm?: string;
88
+ trustedDevices: string[];
89
+ untrustedDevices: string[];
90
+ }>;
91
+
92
+ // Event Encryption/Decryption
93
+ encryptEvent(roomId: string, eventType: string, content: string): Promise<string>;
94
+
95
+ decryptEvent(roomId: string, encryptedContent: string): Promise<string>;
96
+
97
+ // Cleanup
98
+ destroy(): Promise<{ success: boolean }>;
99
+ }
100
+
101
+ /**
102
+ * Native module proxy that delegates to the platform-specific implementation
103
+ */
104
+ export const NativeMatrixCrypto: NativeMatrixCryptoInterface = {
105
+ initialize: (userId: string, deviceId: string, pickleKey: string) =>
106
+ NativeMatrixCryptoModule.initialize(userId, deviceId, pickleKey),
107
+
108
+ getDeviceFingerprint: () =>
109
+ NativeMatrixCryptoModule.getDeviceFingerprint(),
110
+
111
+ getUserId: () =>
112
+ NativeMatrixCryptoModule.getUserId(),
113
+
114
+ getDeviceId: () =>
115
+ NativeMatrixCryptoModule.getDeviceId(),
116
+
117
+ getUserDevices: (userId: string) =>
118
+ NativeMatrixCryptoModule.getUserDevices(userId),
119
+
120
+ addDevice: (device) =>
121
+ NativeMatrixCryptoModule.addDevice(device),
122
+
123
+ startVerification: (otherUserId: string, otherDeviceId: string) =>
124
+ NativeMatrixCryptoModule.startVerification(otherUserId, otherDeviceId),
125
+
126
+ getSASEmojis: (verificationId: string) =>
127
+ NativeMatrixCryptoModule.getSASEmojis(verificationId),
128
+
129
+ confirmSAS: (verificationId: string) =>
130
+ NativeMatrixCryptoModule.confirmSAS(verificationId),
131
+
132
+ completeVerification: (verificationId: string) =>
133
+ NativeMatrixCryptoModule.completeVerification(verificationId),
134
+
135
+ cancelVerification: (verificationId: string) =>
136
+ NativeMatrixCryptoModule.cancelVerification(verificationId),
137
+
138
+ getVerificationState: (verificationId: string) =>
139
+ NativeMatrixCryptoModule.getVerificationState(verificationId),
140
+
141
+ enableRoomEncryption: (roomId: string, algorithm: string) =>
142
+ NativeMatrixCryptoModule.enableRoomEncryption(roomId, algorithm),
143
+
144
+ getRoomEncryptionState: (roomId: string) =>
145
+ NativeMatrixCryptoModule.getRoomEncryptionState(roomId),
146
+
147
+ encryptEvent: (roomId: string, eventType: string, content: string) =>
148
+ NativeMatrixCryptoModule.encryptEvent(roomId, eventType, content),
149
+
150
+ decryptEvent: (roomId: string, encryptedContent: string) =>
151
+ NativeMatrixCryptoModule.decryptEvent(roomId, encryptedContent),
152
+
153
+ destroy: () =>
154
+ NativeMatrixCryptoModule.destroy(),
155
+ };
156
+
157
+ export default NativeMatrixCrypto;
package/src/index.ts ADDED
@@ -0,0 +1,369 @@
1
+ import { NativeModules, Platform } from 'react-native';
2
+
3
+ const LINKING_ERROR =
4
+ `The package 'react-native-matrix-crypto' doesn't seem to be linked. Make sure: \n\n` +
5
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
6
+ '- You rebuilt the app after installing the package\n' +
7
+ '- You are not using Expo Go\n';
8
+
9
+ const MatrixCryptoModule = NativeModules.MatrixCrypto
10
+ ? NativeModules.MatrixCrypto
11
+ : new Proxy(
12
+ {},
13
+ {
14
+ get() {
15
+ throw new Error(LINKING_ERROR);
16
+ },
17
+ }
18
+ );
19
+
20
+ export interface DeviceInfo {
21
+ deviceId: string;
22
+ userId: string;
23
+ displayName?: string;
24
+ fingerprint: string;
25
+ isVerified: boolean;
26
+ isBlocked: boolean;
27
+ algorithm: string;
28
+ }
29
+
30
+ export interface EmojiSASPair {
31
+ emoji: string;
32
+ name: string;
33
+ }
34
+
35
+ export interface VerificationState {
36
+ verificationId: string;
37
+ state: 'pending' | 'sas_ready' | 'confirmed' | 'completed' | 'cancelled';
38
+ otherUserId: string;
39
+ otherDeviceId: string;
40
+ emojis: EmojiSASPair[];
41
+ decimals: number[];
42
+ }
43
+
44
+ export interface RoomEncryptionState {
45
+ roomId: string;
46
+ isEncrypted: boolean;
47
+ algorithm?: string;
48
+ trustedDevices: string[];
49
+ untrustedDevices: string[];
50
+ }
51
+
52
+ export interface EncryptionAlgorithm {
53
+ algorithm: string;
54
+ rotationPeriodMs: number;
55
+ rotationPeriodMsgs: number;
56
+ }
57
+
58
+ export interface UserDevices {
59
+ userId: string;
60
+ devices: DeviceInfo[];
61
+ }
62
+
63
+ export class MatrixCrypto {
64
+ private static instance: MatrixCrypto | null = null;
65
+ private handle: number | null = null;
66
+
67
+ private constructor() {}
68
+
69
+ /**
70
+ * Get or create singleton instance
71
+ */
72
+ static getInstance(): MatrixCrypto {
73
+ if (!MatrixCrypto.instance) {
74
+ MatrixCrypto.instance = new MatrixCrypto();
75
+ }
76
+ return MatrixCrypto.instance;
77
+ }
78
+
79
+ /**
80
+ * Initialize the crypto machine
81
+ */
82
+ async initialize(
83
+ userId: string,
84
+ deviceId: string,
85
+ pickleKey: string
86
+ ): Promise<void> {
87
+ try {
88
+ this.handle = await MatrixCryptoModule.initialize(
89
+ userId,
90
+ deviceId,
91
+ pickleKey
92
+ );
93
+ } catch (error) {
94
+ throw new Error(`Failed to initialize Matrix crypto: ${error}`);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Get the device fingerprint
100
+ */
101
+ async getDeviceFingerprint(): Promise<string> {
102
+ if (!this.handle) {
103
+ throw new Error('Crypto not initialized');
104
+ }
105
+ try {
106
+ return await MatrixCryptoModule.getDeviceFingerprint(this.handle);
107
+ } catch (error) {
108
+ throw new Error(`Failed to get device fingerprint: ${error}`);
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Get the user ID
114
+ */
115
+ async getUserId(): Promise<string> {
116
+ if (!this.handle) {
117
+ throw new Error('Crypto not initialized');
118
+ }
119
+ try {
120
+ return await MatrixCryptoModule.getUserId(this.handle);
121
+ } catch (error) {
122
+ throw new Error(`Failed to get user ID: ${error}`);
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Get the device ID
128
+ */
129
+ async getDeviceId(): Promise<string> {
130
+ if (!this.handle) {
131
+ throw new Error('Crypto not initialized');
132
+ }
133
+ try {
134
+ return await MatrixCryptoModule.getDeviceId(this.handle);
135
+ } catch (error) {
136
+ throw new Error(`Failed to get device ID: ${error}`);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Get devices for a user
142
+ */
143
+ async getUserDevices(userId: string): Promise<DeviceInfo[]> {
144
+ if (!this.handle) {
145
+ throw new Error('Crypto not initialized');
146
+ }
147
+ try {
148
+ return await MatrixCryptoModule.getUserDevices(this.handle, userId);
149
+ } catch (error) {
150
+ throw new Error(`Failed to get user devices: ${error}`);
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Add a device
156
+ */
157
+ async addDevice(device: DeviceInfo): Promise<void> {
158
+ if (!this.handle) {
159
+ throw new Error('Crypto not initialized');
160
+ }
161
+ try {
162
+ await MatrixCryptoModule.addDevice(this.handle, device);
163
+ } catch (error) {
164
+ throw new Error(`Failed to add device: ${error}`);
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Start device verification
170
+ */
171
+ async startVerification(
172
+ otherUserId: string,
173
+ otherDeviceId: string
174
+ ): Promise<VerificationState> {
175
+ if (!this.handle) {
176
+ throw new Error('Crypto not initialized');
177
+ }
178
+ try {
179
+ return await MatrixCryptoModule.startVerification(
180
+ this.handle,
181
+ otherUserId,
182
+ otherDeviceId
183
+ );
184
+ } catch (error) {
185
+ throw new Error(`Failed to start verification: ${error}`);
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Get SAS emojis
191
+ */
192
+ async getSASEmojis(verificationId: string): Promise<EmojiSASPair[]> {
193
+ if (!this.handle) {
194
+ throw new Error('Crypto not initialized');
195
+ }
196
+ try {
197
+ return await MatrixCryptoModule.getSASEmojis(this.handle, verificationId);
198
+ } catch (error) {
199
+ throw new Error(`Failed to get SAS emojis: ${error}`);
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Confirm SAS
205
+ */
206
+ async confirmSAS(verificationId: string): Promise<void> {
207
+ if (!this.handle) {
208
+ throw new Error('Crypto not initialized');
209
+ }
210
+ try {
211
+ await MatrixCryptoModule.confirmSAS(this.handle, verificationId);
212
+ } catch (error) {
213
+ throw new Error(`Failed to confirm SAS: ${error}`);
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Complete verification
219
+ */
220
+ async completeVerification(verificationId: string): Promise<void> {
221
+ if (!this.handle) {
222
+ throw new Error('Crypto not initialized');
223
+ }
224
+ try {
225
+ await MatrixCryptoModule.completeVerification(
226
+ this.handle,
227
+ verificationId
228
+ );
229
+ } catch (error) {
230
+ throw new Error(`Failed to complete verification: ${error}`);
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Cancel verification
236
+ */
237
+ async cancelVerification(verificationId: string): Promise<void> {
238
+ if (!this.handle) {
239
+ throw new Error('Crypto not initialized');
240
+ }
241
+ try {
242
+ await MatrixCryptoModule.cancelVerification(
243
+ this.handle,
244
+ verificationId
245
+ );
246
+ } catch (error) {
247
+ throw new Error(`Failed to cancel verification: ${error}`);
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Get verification state
253
+ */
254
+ async getVerificationState(
255
+ verificationId: string
256
+ ): Promise<VerificationState> {
257
+ if (!this.handle) {
258
+ throw new Error('Crypto not initialized');
259
+ }
260
+ try {
261
+ return await MatrixCryptoModule.getVerificationState(
262
+ this.handle,
263
+ verificationId
264
+ );
265
+ } catch (error) {
266
+ throw new Error(`Failed to get verification state: ${error}`);
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Enable room encryption
272
+ */
273
+ async enableRoomEncryption(
274
+ roomId: string,
275
+ algorithm: string
276
+ ): Promise<void> {
277
+ if (!this.handle) {
278
+ throw new Error('Crypto not initialized');
279
+ }
280
+ try {
281
+ await MatrixCryptoModule.enableRoomEncryption(
282
+ this.handle,
283
+ roomId,
284
+ algorithm
285
+ );
286
+ } catch (error) {
287
+ throw new Error(`Failed to enable room encryption: ${error}`);
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Get room encryption state
293
+ */
294
+ async getRoomEncryptionState(
295
+ roomId: string
296
+ ): Promise<RoomEncryptionState> {
297
+ if (!this.handle) {
298
+ throw new Error('Crypto not initialized');
299
+ }
300
+ try {
301
+ return await MatrixCryptoModule.getRoomEncryptionState(
302
+ this.handle,
303
+ roomId
304
+ );
305
+ } catch (error) {
306
+ throw new Error(`Failed to get room encryption state: ${error}`);
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Encrypt event
312
+ */
313
+ async encryptEvent(
314
+ roomId: string,
315
+ eventType: string,
316
+ content: string
317
+ ): Promise<string> {
318
+ if (!this.handle) {
319
+ throw new Error('Crypto not initialized');
320
+ }
321
+ try {
322
+ return await MatrixCryptoModule.encryptEvent(
323
+ this.handle,
324
+ roomId,
325
+ eventType,
326
+ content
327
+ );
328
+ } catch (error) {
329
+ throw new Error(`Failed to encrypt event: ${error}`);
330
+ }
331
+ }
332
+
333
+ /**
334
+ * Decrypt event
335
+ */
336
+ async decryptEvent(
337
+ roomId: string,
338
+ encryptedContent: string
339
+ ): Promise<string> {
340
+ if (!this.handle) {
341
+ throw new Error('Crypto not initialized');
342
+ }
343
+ try {
344
+ return await MatrixCryptoModule.decryptEvent(
345
+ this.handle,
346
+ roomId,
347
+ encryptedContent
348
+ );
349
+ } catch (error) {
350
+ throw new Error(`Failed to decrypt event: ${error}`);
351
+ }
352
+ }
353
+
354
+ /**
355
+ * Cleanup
356
+ */
357
+ async destroy(): Promise<void> {
358
+ if (this.handle) {
359
+ try {
360
+ await MatrixCryptoModule.destroy(this.handle);
361
+ } catch (error) {
362
+ console.error(`Failed to destroy crypto: ${error}`);
363
+ }
364
+ this.handle = null;
365
+ }
366
+ }
367
+ }
368
+
369
+ export default MatrixCrypto.getInstance();