@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.
package/lib/index.js ADDED
@@ -0,0 +1,267 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MatrixCrypto = void 0;
4
+ const react_native_1 = require("react-native");
5
+ const LINKING_ERROR = `The package 'react-native-matrix-crypto' doesn't seem to be linked. Make sure: \n\n` +
6
+ react_native_1.Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
7
+ '- You rebuilt the app after installing the package\n' +
8
+ '- You are not using Expo Go\n';
9
+ const MatrixCryptoModule = react_native_1.NativeModules.MatrixCrypto
10
+ ? react_native_1.NativeModules.MatrixCrypto
11
+ : new Proxy({}, {
12
+ get() {
13
+ throw new Error(LINKING_ERROR);
14
+ },
15
+ });
16
+ class MatrixCrypto {
17
+ constructor() {
18
+ this.handle = null;
19
+ }
20
+ /**
21
+ * Get or create singleton instance
22
+ */
23
+ static getInstance() {
24
+ if (!MatrixCrypto.instance) {
25
+ MatrixCrypto.instance = new MatrixCrypto();
26
+ }
27
+ return MatrixCrypto.instance;
28
+ }
29
+ /**
30
+ * Initialize the crypto machine
31
+ */
32
+ async initialize(userId, deviceId, pickleKey) {
33
+ try {
34
+ this.handle = await MatrixCryptoModule.initialize(userId, deviceId, pickleKey);
35
+ }
36
+ catch (error) {
37
+ throw new Error(`Failed to initialize Matrix crypto: ${error}`);
38
+ }
39
+ }
40
+ /**
41
+ * Get the device fingerprint
42
+ */
43
+ async getDeviceFingerprint() {
44
+ if (!this.handle) {
45
+ throw new Error('Crypto not initialized');
46
+ }
47
+ try {
48
+ return await MatrixCryptoModule.getDeviceFingerprint(this.handle);
49
+ }
50
+ catch (error) {
51
+ throw new Error(`Failed to get device fingerprint: ${error}`);
52
+ }
53
+ }
54
+ /**
55
+ * Get the user ID
56
+ */
57
+ async getUserId() {
58
+ if (!this.handle) {
59
+ throw new Error('Crypto not initialized');
60
+ }
61
+ try {
62
+ return await MatrixCryptoModule.getUserId(this.handle);
63
+ }
64
+ catch (error) {
65
+ throw new Error(`Failed to get user ID: ${error}`);
66
+ }
67
+ }
68
+ /**
69
+ * Get the device ID
70
+ */
71
+ async getDeviceId() {
72
+ if (!this.handle) {
73
+ throw new Error('Crypto not initialized');
74
+ }
75
+ try {
76
+ return await MatrixCryptoModule.getDeviceId(this.handle);
77
+ }
78
+ catch (error) {
79
+ throw new Error(`Failed to get device ID: ${error}`);
80
+ }
81
+ }
82
+ /**
83
+ * Get devices for a user
84
+ */
85
+ async getUserDevices(userId) {
86
+ if (!this.handle) {
87
+ throw new Error('Crypto not initialized');
88
+ }
89
+ try {
90
+ return await MatrixCryptoModule.getUserDevices(this.handle, userId);
91
+ }
92
+ catch (error) {
93
+ throw new Error(`Failed to get user devices: ${error}`);
94
+ }
95
+ }
96
+ /**
97
+ * Add a device
98
+ */
99
+ async addDevice(device) {
100
+ if (!this.handle) {
101
+ throw new Error('Crypto not initialized');
102
+ }
103
+ try {
104
+ await MatrixCryptoModule.addDevice(this.handle, device);
105
+ }
106
+ catch (error) {
107
+ throw new Error(`Failed to add device: ${error}`);
108
+ }
109
+ }
110
+ /**
111
+ * Start device verification
112
+ */
113
+ async startVerification(otherUserId, otherDeviceId) {
114
+ if (!this.handle) {
115
+ throw new Error('Crypto not initialized');
116
+ }
117
+ try {
118
+ return await MatrixCryptoModule.startVerification(this.handle, otherUserId, otherDeviceId);
119
+ }
120
+ catch (error) {
121
+ throw new Error(`Failed to start verification: ${error}`);
122
+ }
123
+ }
124
+ /**
125
+ * Get SAS emojis
126
+ */
127
+ async getSASEmojis(verificationId) {
128
+ if (!this.handle) {
129
+ throw new Error('Crypto not initialized');
130
+ }
131
+ try {
132
+ return await MatrixCryptoModule.getSASEmojis(this.handle, verificationId);
133
+ }
134
+ catch (error) {
135
+ throw new Error(`Failed to get SAS emojis: ${error}`);
136
+ }
137
+ }
138
+ /**
139
+ * Confirm SAS
140
+ */
141
+ async confirmSAS(verificationId) {
142
+ if (!this.handle) {
143
+ throw new Error('Crypto not initialized');
144
+ }
145
+ try {
146
+ await MatrixCryptoModule.confirmSAS(this.handle, verificationId);
147
+ }
148
+ catch (error) {
149
+ throw new Error(`Failed to confirm SAS: ${error}`);
150
+ }
151
+ }
152
+ /**
153
+ * Complete verification
154
+ */
155
+ async completeVerification(verificationId) {
156
+ if (!this.handle) {
157
+ throw new Error('Crypto not initialized');
158
+ }
159
+ try {
160
+ await MatrixCryptoModule.completeVerification(this.handle, verificationId);
161
+ }
162
+ catch (error) {
163
+ throw new Error(`Failed to complete verification: ${error}`);
164
+ }
165
+ }
166
+ /**
167
+ * Cancel verification
168
+ */
169
+ async cancelVerification(verificationId) {
170
+ if (!this.handle) {
171
+ throw new Error('Crypto not initialized');
172
+ }
173
+ try {
174
+ await MatrixCryptoModule.cancelVerification(this.handle, verificationId);
175
+ }
176
+ catch (error) {
177
+ throw new Error(`Failed to cancel verification: ${error}`);
178
+ }
179
+ }
180
+ /**
181
+ * Get verification state
182
+ */
183
+ async getVerificationState(verificationId) {
184
+ if (!this.handle) {
185
+ throw new Error('Crypto not initialized');
186
+ }
187
+ try {
188
+ return await MatrixCryptoModule.getVerificationState(this.handle, verificationId);
189
+ }
190
+ catch (error) {
191
+ throw new Error(`Failed to get verification state: ${error}`);
192
+ }
193
+ }
194
+ /**
195
+ * Enable room encryption
196
+ */
197
+ async enableRoomEncryption(roomId, algorithm) {
198
+ if (!this.handle) {
199
+ throw new Error('Crypto not initialized');
200
+ }
201
+ try {
202
+ await MatrixCryptoModule.enableRoomEncryption(this.handle, roomId, algorithm);
203
+ }
204
+ catch (error) {
205
+ throw new Error(`Failed to enable room encryption: ${error}`);
206
+ }
207
+ }
208
+ /**
209
+ * Get room encryption state
210
+ */
211
+ async getRoomEncryptionState(roomId) {
212
+ if (!this.handle) {
213
+ throw new Error('Crypto not initialized');
214
+ }
215
+ try {
216
+ return await MatrixCryptoModule.getRoomEncryptionState(this.handle, roomId);
217
+ }
218
+ catch (error) {
219
+ throw new Error(`Failed to get room encryption state: ${error}`);
220
+ }
221
+ }
222
+ /**
223
+ * Encrypt event
224
+ */
225
+ async encryptEvent(roomId, eventType, content) {
226
+ if (!this.handle) {
227
+ throw new Error('Crypto not initialized');
228
+ }
229
+ try {
230
+ return await MatrixCryptoModule.encryptEvent(this.handle, roomId, eventType, content);
231
+ }
232
+ catch (error) {
233
+ throw new Error(`Failed to encrypt event: ${error}`);
234
+ }
235
+ }
236
+ /**
237
+ * Decrypt event
238
+ */
239
+ async decryptEvent(roomId, encryptedContent) {
240
+ if (!this.handle) {
241
+ throw new Error('Crypto not initialized');
242
+ }
243
+ try {
244
+ return await MatrixCryptoModule.decryptEvent(this.handle, roomId, encryptedContent);
245
+ }
246
+ catch (error) {
247
+ throw new Error(`Failed to decrypt event: ${error}`);
248
+ }
249
+ }
250
+ /**
251
+ * Cleanup
252
+ */
253
+ async destroy() {
254
+ if (this.handle) {
255
+ try {
256
+ await MatrixCryptoModule.destroy(this.handle);
257
+ }
258
+ catch (error) {
259
+ console.error(`Failed to destroy crypto: ${error}`);
260
+ }
261
+ this.handle = null;
262
+ }
263
+ }
264
+ }
265
+ exports.MatrixCrypto = MatrixCrypto;
266
+ MatrixCrypto.instance = null;
267
+ exports.default = MatrixCrypto.getInstance();
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@k9o/react-native-matrix-crypto",
3
+ "version": "1.0.0",
4
+ "description": "Native Rust crypto bridge for React Native Matrix client with End-to-End Encryption support",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "files": [
8
+ "lib",
9
+ "src",
10
+ "ios",
11
+ "android",
12
+ "react-native-matrix-crypto.podspec"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "test": "jest",
17
+ "prepare": "npm run build",
18
+ "type-check": "tsc --noEmit",
19
+ "lint": "eslint src --ext .ts,.tsx"
20
+ },
21
+ "keywords": [
22
+ "matrix",
23
+ "crypto",
24
+ "e2ee",
25
+ "encryption",
26
+ "react-native",
27
+ "ios",
28
+ "android",
29
+ "rust",
30
+ "uniffi"
31
+ ],
32
+ "author": "Matrix Chat Contributors",
33
+ "license": "Apache-2.0",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/k9o-dev/matrix-crypto-bridge.git",
37
+ "directory": "react-native-matrix-crypto"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/k9o-dev/matrix-crypto-bridge/issues"
41
+ },
42
+ "homepage": "https://github.com/k9o-dev/matrix-crypto-bridge#readme",
43
+ "peerDependencies": {
44
+ "react": ">=16.8.0",
45
+ "react-native": ">=0.71.0"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "react": {
49
+ "optional": true
50
+ },
51
+ "react-native": {
52
+ "optional": true
53
+ }
54
+ },
55
+ "devDependencies": {
56
+ "react": "^19.2.4",
57
+ "react-native": "^0.84.1",
58
+ "@types/react": "^19.2.0",
59
+ "@types/react-native": "^0.73.0",
60
+ "typescript": "^5.3.3",
61
+ "jest": "^29.7.0",
62
+ "eslint": "^8.50.0",
63
+ "@typescript-eslint/eslint-plugin": "^6.7.0",
64
+ "@typescript-eslint/parser": "^6.7.0"
65
+ },
66
+ "engines": {
67
+ "node": ">=16.0.0",
68
+ "npm": ">=8.0.0"
69
+ },
70
+ "publishConfig": {
71
+ "access": "public",
72
+ "registry": "https://registry.npmjs.org/"
73
+ }
74
+ }
@@ -0,0 +1,25 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "react-native-matrix-crypto"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+ s.platforms = { :ios => "11.0" }
13
+ s.source = { :git => package["repository"]["url"], :tag => "#{s.version}" }
14
+
15
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
16
+ s.requires_arc = true
17
+
18
+ s.dependency "React-Core"
19
+ s.dependency "MatrixCryptoBridge"
20
+
21
+ s.pod_target_xcconfig = {
22
+ "DEFINES_MODULE" => "YES",
23
+ "SWIFT_VERSION" => "5.9"
24
+ }
25
+ end
@@ -0,0 +1,256 @@
1
+ import { NativeMatrixCrypto } from './NativeMatrixCrypto';
2
+ import {
3
+ DeviceInfo,
4
+ EmojiSASPair,
5
+ VerificationState,
6
+ RoomEncryptionState,
7
+ } from './index';
8
+
9
+ /**
10
+ * High-level API for Matrix crypto operations
11
+ * Provides a clean, easy-to-use interface for encryption, device verification, and key management
12
+ */
13
+ export class CryptoAPI {
14
+ private initialized: boolean = false;
15
+ private userId: string = '';
16
+ private deviceId: string = '';
17
+
18
+ /**
19
+ * Initialize the crypto API
20
+ */
21
+ async initialize(
22
+ userId: string,
23
+ deviceId: string,
24
+ pickleKey: string
25
+ ): Promise<void> {
26
+ try {
27
+ await NativeMatrixCrypto.initialize(userId, deviceId, pickleKey);
28
+ this.initialized = true;
29
+ this.userId = userId;
30
+ this.deviceId = deviceId;
31
+ } catch (error) {
32
+ throw new Error(`Failed to initialize crypto: ${error}`);
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Check if crypto is initialized
38
+ */
39
+ isInitialized(): boolean {
40
+ return this.initialized;
41
+ }
42
+
43
+ /**
44
+ * Get device information
45
+ */
46
+ async getDeviceInfo(): Promise<{
47
+ fingerprint: string;
48
+ userId: string;
49
+ deviceId: string;
50
+ }> {
51
+ this.assertInitialized();
52
+ try {
53
+ const [fingerprint, userId, deviceId] = await Promise.all([
54
+ NativeMatrixCrypto.getDeviceFingerprint(),
55
+ NativeMatrixCrypto.getUserId(),
56
+ NativeMatrixCrypto.getDeviceId(),
57
+ ]);
58
+ return { fingerprint, userId, deviceId };
59
+ } catch (error) {
60
+ throw new Error(`Failed to get device info: ${error}`);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Get all devices for a user
66
+ */
67
+ async getUserDevices(userId: string): Promise<DeviceInfo[]> {
68
+ this.assertInitialized();
69
+ try {
70
+ return await NativeMatrixCrypto.getUserDevices(userId);
71
+ } catch (error) {
72
+ throw new Error(`Failed to get user devices: ${error}`);
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Add a device to the device store
78
+ */
79
+ async addDevice(device: DeviceInfo): Promise<void> {
80
+ this.assertInitialized();
81
+ try {
82
+ await NativeMatrixCrypto.addDevice(device);
83
+ } catch (error) {
84
+ throw new Error(`Failed to add device: ${error}`);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Start device verification with another device
90
+ */
91
+ async startVerification(
92
+ otherUserId: string,
93
+ otherDeviceId: string
94
+ ): Promise<VerificationState> {
95
+ this.assertInitialized();
96
+ try {
97
+ const result = await NativeMatrixCrypto.startVerification(
98
+ otherUserId,
99
+ otherDeviceId
100
+ );
101
+ return result as VerificationState;
102
+ } catch (error) {
103
+ throw new Error(`Failed to start verification: ${error}`);
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Get SAS emoji pairs for verification
109
+ */
110
+ async getSASEmojis(verificationId: string): Promise<EmojiSASPair[]> {
111
+ this.assertInitialized();
112
+ try {
113
+ return await NativeMatrixCrypto.getSASEmojis(verificationId);
114
+ } catch (error) {
115
+ throw new Error(`Failed to get SAS emojis: ${error}`);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Confirm SAS verification
121
+ */
122
+ async confirmSAS(verificationId: string): Promise<void> {
123
+ this.assertInitialized();
124
+ try {
125
+ await NativeMatrixCrypto.confirmSAS(verificationId);
126
+ } catch (error) {
127
+ throw new Error(`Failed to confirm SAS: ${error}`);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Complete device verification
133
+ */
134
+ async completeVerification(verificationId: string): Promise<void> {
135
+ this.assertInitialized();
136
+ try {
137
+ await NativeMatrixCrypto.completeVerification(verificationId);
138
+ } catch (error) {
139
+ throw new Error(`Failed to complete verification: ${error}`);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Cancel device verification
145
+ */
146
+ async cancelVerification(verificationId: string): Promise<void> {
147
+ this.assertInitialized();
148
+ try {
149
+ await NativeMatrixCrypto.cancelVerification(verificationId);
150
+ } catch (error) {
151
+ throw new Error(`Failed to cancel verification: ${error}`);
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Get the current state of a verification
157
+ */
158
+ async getVerificationState(
159
+ verificationId: string
160
+ ): Promise<VerificationState> {
161
+ this.assertInitialized();
162
+ try {
163
+ const result = await NativeMatrixCrypto.getVerificationState(verificationId);
164
+ return result as VerificationState;
165
+ } catch (error) {
166
+ throw new Error(`Failed to get verification state: ${error}`);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Enable encryption for a room
172
+ */
173
+ async enableRoomEncryption(
174
+ roomId: string,
175
+ algorithm: string = 'm.megolm.v1.aes-sha2'
176
+ ): Promise<void> {
177
+ this.assertInitialized();
178
+ try {
179
+ await NativeMatrixCrypto.enableRoomEncryption(roomId, algorithm);
180
+ } catch (error) {
181
+ throw new Error(`Failed to enable room encryption: ${error}`);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Get encryption state for a room
187
+ */
188
+ async getRoomEncryptionState(roomId: string): Promise<RoomEncryptionState> {
189
+ this.assertInitialized();
190
+ try {
191
+ return await NativeMatrixCrypto.getRoomEncryptionState(roomId);
192
+ } catch (error) {
193
+ throw new Error(`Failed to get room encryption state: ${error}`);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Encrypt an event
199
+ */
200
+ async encryptEvent(
201
+ roomId: string,
202
+ eventType: string,
203
+ content: string
204
+ ): Promise<string> {
205
+ this.assertInitialized();
206
+ try {
207
+ return await NativeMatrixCrypto.encryptEvent(
208
+ roomId,
209
+ eventType,
210
+ content
211
+ );
212
+ } catch (error) {
213
+ throw new Error(`Failed to encrypt event: ${error}`);
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Decrypt an event
219
+ */
220
+ async decryptEvent(
221
+ roomId: string,
222
+ encryptedContent: string
223
+ ): Promise<string> {
224
+ this.assertInitialized();
225
+ try {
226
+ return await NativeMatrixCrypto.decryptEvent(roomId, encryptedContent);
227
+ } catch (error) {
228
+ throw new Error(`Failed to decrypt event: ${error}`);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Cleanup and destroy the crypto instance
234
+ */
235
+ async destroy(): Promise<void> {
236
+ try {
237
+ await NativeMatrixCrypto.destroy();
238
+ this.initialized = false;
239
+ } catch (error) {
240
+ throw new Error(`Failed to destroy crypto: ${error}`);
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Helper method to ensure crypto is initialized
246
+ */
247
+ private assertInitialized(): void {
248
+ if (!this.initialized) {
249
+ throw new Error(
250
+ 'Crypto not initialized. Call initialize() first.'
251
+ );
252
+ }
253
+ }
254
+ }
255
+
256
+ export default CryptoAPI;