@towns-protocol/encryption 0.0.191

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 (99) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +3 -0
  3. package/dist/base.d.ts +64 -0
  4. package/dist/base.d.ts.map +1 -0
  5. package/dist/base.js +44 -0
  6. package/dist/base.js.map +1 -0
  7. package/dist/cryptoAesGcm.d.ts +9 -0
  8. package/dist/cryptoAesGcm.d.ts.map +1 -0
  9. package/dist/cryptoAesGcm.js +30 -0
  10. package/dist/cryptoAesGcm.js.map +1 -0
  11. package/dist/cryptoStore.d.ts +52 -0
  12. package/dist/cryptoStore.d.ts.map +1 -0
  13. package/dist/cryptoStore.js +131 -0
  14. package/dist/cryptoStore.js.map +1 -0
  15. package/dist/decryptionExtensions.d.ts +200 -0
  16. package/dist/decryptionExtensions.d.ts.map +1 -0
  17. package/dist/decryptionExtensions.js +687 -0
  18. package/dist/decryptionExtensions.js.map +1 -0
  19. package/dist/derivedEncryption.d.ts +2 -0
  20. package/dist/derivedEncryption.d.ts.map +1 -0
  21. package/dist/derivedEncryption.js +2 -0
  22. package/dist/derivedEncryption.js.map +1 -0
  23. package/dist/encryptionDelegate.d.ts +20 -0
  24. package/dist/encryptionDelegate.d.ts.map +1 -0
  25. package/dist/encryptionDelegate.js +86 -0
  26. package/dist/encryptionDelegate.js.map +1 -0
  27. package/dist/encryptionDevice.d.ts +264 -0
  28. package/dist/encryptionDevice.d.ts.map +1 -0
  29. package/dist/encryptionDevice.js +742 -0
  30. package/dist/encryptionDevice.js.map +1 -0
  31. package/dist/encryptionTypes.d.ts +20 -0
  32. package/dist/encryptionTypes.d.ts.map +1 -0
  33. package/dist/encryptionTypes.js +2 -0
  34. package/dist/encryptionTypes.js.map +1 -0
  35. package/dist/groupDecryption.d.ts +34 -0
  36. package/dist/groupDecryption.d.ts.map +1 -0
  37. package/dist/groupDecryption.js +84 -0
  38. package/dist/groupDecryption.js.map +1 -0
  39. package/dist/groupEncryption.d.ts +36 -0
  40. package/dist/groupEncryption.d.ts.map +1 -0
  41. package/dist/groupEncryption.js +90 -0
  42. package/dist/groupEncryption.js.map +1 -0
  43. package/dist/groupEncryptionCrypto.d.ts +119 -0
  44. package/dist/groupEncryptionCrypto.d.ts.map +1 -0
  45. package/dist/groupEncryptionCrypto.js +256 -0
  46. package/dist/groupEncryptionCrypto.js.map +1 -0
  47. package/dist/hybridGroupDecryption.d.ts +33 -0
  48. package/dist/hybridGroupDecryption.d.ts.map +1 -0
  49. package/dist/hybridGroupDecryption.js +84 -0
  50. package/dist/hybridGroupDecryption.js.map +1 -0
  51. package/dist/hybridGroupEncryption.d.ts +30 -0
  52. package/dist/hybridGroupEncryption.d.ts.map +1 -0
  53. package/dist/hybridGroupEncryption.js +92 -0
  54. package/dist/hybridGroupEncryption.js.map +1 -0
  55. package/dist/index.d.ts +19 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +19 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/olmLib.d.ts +35 -0
  60. package/dist/olmLib.d.ts.map +1 -0
  61. package/dist/olmLib.js +37 -0
  62. package/dist/olmLib.js.map +1 -0
  63. package/dist/storeTypes.d.ts +27 -0
  64. package/dist/storeTypes.d.ts.map +1 -0
  65. package/dist/storeTypes.js +2 -0
  66. package/dist/storeTypes.js.map +1 -0
  67. package/dist/tests/cryptoAesGcm.test.d.ts +2 -0
  68. package/dist/tests/cryptoAesGcm.test.d.ts.map +1 -0
  69. package/dist/tests/cryptoAesGcm.test.js +71 -0
  70. package/dist/tests/cryptoAesGcm.test.js.map +1 -0
  71. package/dist/tests/cryptoStore.test.d.ts +5 -0
  72. package/dist/tests/cryptoStore.test.d.ts.map +1 -0
  73. package/dist/tests/cryptoStore.test.js +114 -0
  74. package/dist/tests/cryptoStore.test.js.map +1 -0
  75. package/dist/tests/decryptionExtensions.test.d.ts +2 -0
  76. package/dist/tests/decryptionExtensions.test.d.ts.map +1 -0
  77. package/dist/tests/decryptionExtensions.test.js +355 -0
  78. package/dist/tests/decryptionExtensions.test.js.map +1 -0
  79. package/dist/tests/encryption-protocol.test.d.ts +2 -0
  80. package/dist/tests/encryption-protocol.test.d.ts.map +1 -0
  81. package/dist/tests/encryption-protocol.test.js +150 -0
  82. package/dist/tests/encryption-protocol.test.js.map +1 -0
  83. package/dist/tests/encryptionDelegate.test.d.ts +2 -0
  84. package/dist/tests/encryptionDelegate.test.d.ts.map +1 -0
  85. package/dist/tests/encryptionDelegate.test.js +78 -0
  86. package/dist/tests/encryptionDelegate.test.js.map +1 -0
  87. package/dist/tests/group-encryption-protocol.test.d.ts +2 -0
  88. package/dist/tests/group-encryption-protocol.test.d.ts.map +1 -0
  89. package/dist/tests/group-encryption-protocol.test.js +103 -0
  90. package/dist/tests/group-encryption-protocol.test.js.map +1 -0
  91. package/dist/tests/group-encryptionDelegate.test.d.ts +2 -0
  92. package/dist/tests/group-encryptionDelegate.test.d.ts.map +1 -0
  93. package/dist/tests/group-encryptionDelegate.test.js +23 -0
  94. package/dist/tests/group-encryptionDelegate.test.js.map +1 -0
  95. package/dist/tests/pk.test.d.ts +2 -0
  96. package/dist/tests/pk.test.d.ts.map +1 -0
  97. package/dist/tests/pk.test.js +103 -0
  98. package/dist/tests/pk.test.js.map +1 -0
  99. package/package.json +54 -0
@@ -0,0 +1,256 @@
1
+ import { GroupEncryptionAlgorithmId, parseGroupEncryptionAlgorithmId, } from './olmLib';
2
+ import { DecryptionError, } from './base';
3
+ import { GroupDecryption } from './groupDecryption';
4
+ import { GroupEncryption } from './groupEncryption';
5
+ import { EncryptionDevice } from './encryptionDevice';
6
+ import { EncryptionDelegate } from './encryptionDelegate';
7
+ import { check, dlog } from '@towns-protocol/dlog';
8
+ import { HybridGroupEncryption } from './hybridGroupEncryption';
9
+ import { HybridGroupDecryption } from './hybridGroupDecryption';
10
+ const log = dlog('csb:encryption:groupEncryptionCrypto');
11
+ export class GroupEncryptionCrypto {
12
+ delegate;
13
+ encryptionDevice;
14
+ groupEncryption;
15
+ groupDecryption;
16
+ cryptoStore;
17
+ globalBlacklistUnverifiedDevices = false;
18
+ globalErrorOnUnknownDevices = true;
19
+ constructor(client, cryptoStore) {
20
+ this.cryptoStore = cryptoStore;
21
+ // initialize Olm library
22
+ this.delegate = new EncryptionDelegate();
23
+ // olm lib returns a Promise<void> on init, hence the catch if it rejects
24
+ this.delegate.init().catch((e) => {
25
+ log('error initializing olm', e);
26
+ throw e;
27
+ });
28
+ this.encryptionDevice = new EncryptionDevice(this.delegate, cryptoStore);
29
+ this.groupEncryption = {
30
+ [GroupEncryptionAlgorithmId.GroupEncryption]: new GroupEncryption({
31
+ device: this.encryptionDevice,
32
+ client,
33
+ }),
34
+ [GroupEncryptionAlgorithmId.HybridGroupEncryption]: new HybridGroupEncryption({
35
+ device: this.encryptionDevice,
36
+ client,
37
+ }),
38
+ };
39
+ this.groupDecryption = {
40
+ [GroupEncryptionAlgorithmId.GroupEncryption]: new GroupDecryption({
41
+ device: this.encryptionDevice,
42
+ }),
43
+ [GroupEncryptionAlgorithmId.HybridGroupEncryption]: new HybridGroupDecryption({
44
+ device: this.encryptionDevice,
45
+ }),
46
+ };
47
+ }
48
+ /** Iniitalize crypto module prior to usage
49
+ *
50
+ */
51
+ async init(opts) {
52
+ // initialize deviceKey and fallbackKey
53
+ await this.encryptionDevice.init(opts);
54
+ // build device keys to upload
55
+ if (!this.encryptionDevice.deviceCurve25519Key ||
56
+ !this.encryptionDevice.deviceDoNotUseKey) {
57
+ log('device keys not initialized, cannot encrypt event');
58
+ }
59
+ }
60
+ /**
61
+ * Encrypt an event using the device keys
62
+ *
63
+ * @param payload - string to be encrypted
64
+ * @param deviceKeys - recipients to encrypt message for
65
+ *
66
+ * @returns Promise which resolves when the event has been
67
+ * encrypted, or null if nothing was needed
68
+ */
69
+ async encryptWithDeviceKeys(payload, deviceKeys) {
70
+ const ciphertextRecord = {};
71
+ await Promise.all(deviceKeys.map(async (deviceKey) => {
72
+ const encrypted = await this.encryptionDevice.encryptUsingFallbackKey(deviceKey.deviceKey, deviceKey.fallbackKey, payload);
73
+ check(encrypted.type === 0, 'expecting only prekey messages at this time');
74
+ ciphertextRecord[deviceKey.deviceKey] = encrypted.body;
75
+ }));
76
+ return ciphertextRecord;
77
+ }
78
+ /**
79
+ * Decrypt a received event using the device key
80
+ *
81
+ * @returns a promise which resolves once we have finished decrypting.
82
+ * Rejects with an error if there is a problem decrypting the event.
83
+ */
84
+ async decryptWithDeviceKey(ciphertext, senderDeviceKey) {
85
+ return await this.encryptionDevice.decryptMessage(ciphertext, senderDeviceKey);
86
+ }
87
+ /**
88
+ * Ensure that we have an outbound group session key for the given stream
89
+ *
90
+ * @returns Promise which resolves when the event has been
91
+ * created, use options to await the initial share
92
+ */
93
+ async ensureOutboundSession(streamId, algorithm, opts) {
94
+ return this.groupEncryption[algorithm].ensureOutboundSession(streamId, opts);
95
+ }
96
+ /**
97
+ * Encrypt an event using group encryption algorithm
98
+ *
99
+ * @returns Promise which resolves when the event has been
100
+ * encrypted, or null if nothing was needed
101
+ */
102
+ async encryptGroupEvent(streamId, payload, algorithm) {
103
+ return this.groupEncryption[algorithm].encrypt(streamId, payload);
104
+ }
105
+ /**
106
+ * Deprecated uses v0 encryption version
107
+ *
108
+ * @returns Promise which resolves when the event has been
109
+ * encrypted, or null if nothing was needed
110
+ */
111
+ async encryptGroupEvent_deprecated_v0(streamId, payload, algorithm) {
112
+ return this.groupEncryption[algorithm].encrypt_deprecated_v0(streamId, payload);
113
+ }
114
+ /**
115
+ * Decrypt a received event using group encryption algorithm
116
+ *
117
+ * @returns a promise which resolves once we have finished decrypting.
118
+ * Rejects with an error if there is a problem decrypting the event.
119
+ */
120
+ async decryptGroupEvent(streamId, content) {
121
+ // parse the algorithm, if value is not set, parsing function will throw
122
+ const algorithm = parseGroupEncryptionAlgorithmId(content.algorithm);
123
+ if (algorithm.kind === 'unrecognized') {
124
+ throw new DecryptionError('GROUP_DECRYPTION_UNKNOWN_ALGORITHM', content.algorithm);
125
+ }
126
+ return this.groupDecryption[algorithm.value].decrypt(streamId, content);
127
+ }
128
+ async exportGroupSession(streamId, sessionId) {
129
+ for (const algorithm of Object.values(GroupEncryptionAlgorithmId)) {
130
+ const session = await this.groupDecryption[algorithm].exportGroupSession(streamId, sessionId);
131
+ if (session) {
132
+ return session;
133
+ }
134
+ }
135
+ return undefined;
136
+ }
137
+ /** */
138
+ async exportRoomKeys() {
139
+ const retVal = [];
140
+ for (const algorithm of Object.values(GroupEncryptionAlgorithmId)) {
141
+ const sessions = await this.groupDecryption[algorithm].exportGroupSessions();
142
+ retVal.push(...sessions);
143
+ }
144
+ return retVal;
145
+ }
146
+ /** */
147
+ async getGroupSessionIds(streamId) {
148
+ const retVal = [];
149
+ for (const algorithm of Object.values(GroupEncryptionAlgorithmId)) {
150
+ const sessions = await this.groupDecryption[algorithm].exportGroupSessionIds(streamId);
151
+ retVal.push(...sessions);
152
+ }
153
+ return retVal;
154
+ }
155
+ /** */
156
+ async hasSessionKey(streamId, sessionId, algorithm) {
157
+ return this.groupDecryption[algorithm].hasSessionKey(streamId, sessionId);
158
+ }
159
+ /** */
160
+ getUserDevice() {
161
+ return {
162
+ deviceKey: this.encryptionDevice.deviceCurve25519Key,
163
+ fallbackKey: this.encryptionDevice.fallbackKey.key,
164
+ };
165
+ }
166
+ /** */
167
+ async exportDevice() {
168
+ return this.encryptionDevice.exportDevice();
169
+ }
170
+ /**
171
+ * Import a list of group session keys previously exported by exportRoomKeys
172
+ *
173
+ * @param streamId - the id of the stream the keys are for
174
+ * @param keys - a list of session export objects
175
+ * @returns a promise which resolves once the keys have been imported
176
+ */
177
+ async importSessionKeys(streamId, keys) {
178
+ await this.cryptoStore.withGroupSessions(async () => Promise.all(keys.map(async (key) => {
179
+ const algorithm = key.algorithm;
180
+ if (algorithm in this.groupDecryption) {
181
+ try {
182
+ await this.groupDecryption[algorithm].importStreamKey(streamId, key);
183
+ }
184
+ catch (error) {
185
+ log(`failed to import key`, error);
186
+ }
187
+ }
188
+ else {
189
+ log(`unknown algorithm ${algorithm}`);
190
+ }
191
+ })));
192
+ }
193
+ /**
194
+ * Import a list of room keys previously exported by exportRoomKeys
195
+ *
196
+ * @param keys - a list of session export objects
197
+ * @returns a promise which resolves once the keys have been imported
198
+ */
199
+ importRoomKeys(keys, opts = {}) {
200
+ let successes = 0;
201
+ let failures = 0;
202
+ const total = keys.length;
203
+ function updateProgress() {
204
+ opts.progressCallback?.({
205
+ stage: 'load_keys',
206
+ successes,
207
+ failures,
208
+ total,
209
+ });
210
+ }
211
+ return Promise.all(keys.map(async (key) => {
212
+ if (!key.streamId || !key.algorithm) {
213
+ log('ignoring room key entry with missing fields', key);
214
+ failures++;
215
+ if (opts.progressCallback) {
216
+ updateProgress();
217
+ }
218
+ return;
219
+ }
220
+ const algorithm = key.algorithm;
221
+ if (algorithm in this.groupDecryption) {
222
+ try {
223
+ await this.groupDecryption[algorithm].importStreamKey(key.streamId, key);
224
+ successes++;
225
+ if (opts.progressCallback) {
226
+ updateProgress();
227
+ }
228
+ }
229
+ catch (error) {
230
+ log('failed to import key', error);
231
+ failures++;
232
+ if (opts.progressCallback) {
233
+ updateProgress();
234
+ }
235
+ }
236
+ }
237
+ else {
238
+ log(`unknown algorithm ${algorithm}`);
239
+ }
240
+ })).then();
241
+ }
242
+ /**
243
+ * Import a JSON string encoding a list of room keys previously
244
+ * exported by exportRoomKeysAsJson
245
+ *
246
+ * @param keys - a JSON string encoding a list of session export
247
+ * objects, each of which is an GroupEncryptionSession
248
+ * @param opts - options object
249
+ * @returns a promise which resolves once the keys have been imported
250
+ */
251
+ async importRoomKeysAsJson(keys) {
252
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
253
+ return await this.importRoomKeys(JSON.parse(keys));
254
+ }
255
+ }
256
+ //# sourceMappingURL=groupEncryptionCrypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"groupEncryptionCrypto.js","sourceRoot":"","sources":["../src/groupEncryptionCrypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { DecryptionAlgorithm, IDecryptionParams } from './base';
2
+ import { GroupEncryptionAlgorithmId, GroupEncryptionSession } from './olmLib';
3
+ import { EncryptedData } from '@towns-protocol/proto';
4
+ /**
5
+ * Group decryption implementation
6
+ *
7
+ * @param params - parameters, as per {@link DecryptionAlgorithm}
8
+ */
9
+ export declare class HybridGroupDecryption extends DecryptionAlgorithm {
10
+ readonly algorithm = GroupEncryptionAlgorithmId.HybridGroupEncryption;
11
+ private lruCache;
12
+ constructor(params: IDecryptionParams);
13
+ /**
14
+ * returns a promise which resolves to a
15
+ * {@link EventDecryptionResult} once we have finished
16
+ * decrypting, or rejects with an `algorithms.DecryptionError` if there is a
17
+ * problem decrypting the event.
18
+ */
19
+ decrypt(streamId: string, content: EncryptedData): Promise<Uint8Array | string>;
20
+ /**
21
+ * @param streamId - the stream id of the session
22
+ * @param session- the group session object
23
+ */
24
+ importStreamKey(streamId: string, session: GroupEncryptionSession): Promise<void>;
25
+ /** */
26
+ exportGroupSession(streamId: string, sessionId: string): Promise<GroupEncryptionSession | undefined>;
27
+ /** */
28
+ exportGroupSessions(): Promise<GroupEncryptionSession[]>;
29
+ /** */
30
+ exportGroupSessionIds(streamId: string): Promise<string[]>;
31
+ hasSessionKey(streamId: string, sessionId: string): Promise<boolean>;
32
+ }
33
+ //# sourceMappingURL=hybridGroupDecryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybridGroupDecryption.d.ts","sourceRoot":"","sources":["../src/hybridGroupDecryption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAmB,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAChF,OAAO,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAA;AAC7E,OAAO,EAAE,aAAa,EAA+C,MAAM,uBAAuB,CAAA;AAOlG;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,mBAAmB;IAC1D,SAAgB,SAAS,oDAAmD;IAC5E,OAAO,CAAC,QAAQ,CAAyC;gBACtC,MAAM,EAAE,iBAAiB;IAK5C;;;;;OAKG;IACU,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC;IA2C5F;;;OAGG;IACU,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9F,MAAM;IACO,kBAAkB,CAC3B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAI9C,MAAM;IACC,mBAAmB,IAAI,OAAO,CAAC,sBAAsB,EAAE,CAAC;IAI/D,MAAM;IACC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAIpD,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGpF"}
@@ -0,0 +1,84 @@
1
+ import { DecryptionAlgorithm, DecryptionError } from './base';
2
+ import { GroupEncryptionAlgorithmId } from './olmLib';
3
+ import { EncryptedDataVersion } from '@towns-protocol/proto';
4
+ import { bin_toHexString, dlogError } from '@towns-protocol/dlog';
5
+ import { decryptAesGcm, importAesGsmKeyBytes } from './cryptoAesGcm';
6
+ import { LRUCache } from 'lru-cache';
7
+ const logError = dlogError('csb:encryption:groupDecryption');
8
+ /**
9
+ * Group decryption implementation
10
+ *
11
+ * @param params - parameters, as per {@link DecryptionAlgorithm}
12
+ */
13
+ export class HybridGroupDecryption extends DecryptionAlgorithm {
14
+ algorithm = GroupEncryptionAlgorithmId.HybridGroupEncryption;
15
+ lruCache;
16
+ constructor(params) {
17
+ super(params);
18
+ this.lruCache = new LRUCache({ max: 1000 });
19
+ }
20
+ /**
21
+ * returns a promise which resolves to a
22
+ * {@link EventDecryptionResult} once we have finished
23
+ * decrypting, or rejects with an `algorithms.DecryptionError` if there is a
24
+ * problem decrypting the event.
25
+ */
26
+ async decrypt(streamId, content) {
27
+ if (!content.senderKey ||
28
+ !content.sessionIdBytes ||
29
+ !content.ciphertextBytes ||
30
+ !content.ivBytes) {
31
+ throw new DecryptionError('HYBRID_GROUP_DECRYPTION_MISSING_FIELDS', 'Missing fields in input');
32
+ }
33
+ const sessionId = bin_toHexString(content.sessionIdBytes);
34
+ // Check cache first
35
+ let session = this.lruCache.get(sessionId);
36
+ // If not in cache, fetch from device
37
+ if (!session) {
38
+ session = await this.device.getHybridGroupSessionKey(streamId, sessionId);
39
+ if (!session) {
40
+ throw new DecryptionError('HYBRID_GROUP_DECRYPTION_MISSING_SESSION', 'Missing session');
41
+ }
42
+ this.lruCache.set(sessionId, session);
43
+ }
44
+ const key = await importAesGsmKeyBytes(session.key);
45
+ const result = await decryptAesGcm(key, content.ciphertextBytes, content.ivBytes);
46
+ switch (content.version) {
47
+ case EncryptedDataVersion.ENCRYPTED_DATA_VERSION_0:
48
+ return new TextDecoder().decode(result);
49
+ case EncryptedDataVersion.ENCRYPTED_DATA_VERSION_1:
50
+ return result;
51
+ default:
52
+ throw new DecryptionError('GROUP_DECRYPTION_INVALID_VERSION', 'Unsupported version');
53
+ }
54
+ }
55
+ /**
56
+ * @param streamId - the stream id of the session
57
+ * @param session- the group session object
58
+ */
59
+ async importStreamKey(streamId, session) {
60
+ try {
61
+ await this.device.addHybridGroupSession(streamId, session.sessionId, session.sessionKey);
62
+ }
63
+ catch (e) {
64
+ logError(`Error handling room key import: ${e.message}`);
65
+ throw e;
66
+ }
67
+ }
68
+ /** */
69
+ async exportGroupSession(streamId, sessionId) {
70
+ return this.device.exportHybridGroupSession(streamId, sessionId);
71
+ }
72
+ /** */
73
+ exportGroupSessions() {
74
+ return this.device.exportHybridGroupSessions();
75
+ }
76
+ /** */
77
+ exportGroupSessionIds(streamId) {
78
+ return this.device.getHybridGroupSessionIds(streamId);
79
+ }
80
+ async hasSessionKey(streamId, sessionId) {
81
+ return this.device.hasHybridGroupSessionKey(streamId, sessionId);
82
+ }
83
+ }
84
+ //# sourceMappingURL=hybridGroupDecryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybridGroupDecryption.js","sourceRoot":"","sources":["../src/hybridGroupDecryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { EncryptedData, HybridGroupSessionKey } from '@towns-protocol/proto';
2
+ import { EncryptionAlgorithm, IEncryptionParams } from './base';
3
+ import { GroupEncryptionAlgorithmId } from './olmLib';
4
+ /**
5
+ * Hybrid Group encryption implementation
6
+ *
7
+ * @param params - parameters, as per {@link EncryptionAlgorithm}
8
+ */
9
+ export declare class HybridGroupEncryption extends EncryptionAlgorithm {
10
+ readonly algorithm = GroupEncryptionAlgorithmId.HybridGroupEncryption;
11
+ constructor(params: IEncryptionParams);
12
+ ensureOutboundSession(streamId: string, opts?: {
13
+ awaitInitialShareSession: boolean;
14
+ }): Promise<void>;
15
+ _ensureOutboundSession(streamId: string, opts?: {
16
+ awaitInitialShareSession: boolean;
17
+ }): Promise<HybridGroupSessionKey>;
18
+ private shareSession;
19
+ /**
20
+ * @deprecated
21
+ */
22
+ encrypt_deprecated_v0(streamId: string, payload: string): Promise<EncryptedData>;
23
+ /**
24
+ * @param content - plaintext event content
25
+ *
26
+ * @returns Promise which resolves to the new event body
27
+ */
28
+ encrypt(streamId: string, payload: Uint8Array): Promise<EncryptedData>;
29
+ }
30
+ //# sourceMappingURL=hybridGroupEncryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybridGroupEncryption.d.ts","sourceRoot":"","sources":["../src/hybridGroupEncryption.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,aAAa,EAGb,qBAAqB,EACxB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAA;AAOrD;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,mBAAmB;IAC1D,SAAgB,SAAS,oDAAmD;gBACzD,MAAM,EAAE,iBAAiB;IAI/B,qBAAqB,CAC9B,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,wBAAwB,EAAE,OAAO,CAAA;KAAE,GAC7C,OAAO,CAAC,IAAI,CAAC;IAIH,sBAAsB,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,wBAAwB,EAAE,OAAO,CAAA;KAAE,GAC7C,OAAO,CAAC,qBAAqB,CAAC;YAgCnB,YAAY;IAgB1B;;OAEG;IACU,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAe7F;;;;OAIG;IACU,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CActF"}
@@ -0,0 +1,92 @@
1
+ import { EncryptedDataSchema, EncryptedDataVersion, } from '@towns-protocol/proto';
2
+ import { EncryptionAlgorithm } from './base';
3
+ import { GroupEncryptionAlgorithmId } from './olmLib';
4
+ import { dlog } from '@towns-protocol/dlog';
5
+ import { encryptAesGcm, importAesGsmKeyBytes } from './cryptoAesGcm';
6
+ import { create } from '@bufbuild/protobuf';
7
+ const log = dlog('csb:encryption:groupEncryption');
8
+ /**
9
+ * Hybrid Group encryption implementation
10
+ *
11
+ * @param params - parameters, as per {@link EncryptionAlgorithm}
12
+ */
13
+ export class HybridGroupEncryption extends EncryptionAlgorithm {
14
+ algorithm = GroupEncryptionAlgorithmId.HybridGroupEncryption;
15
+ constructor(params) {
16
+ super(params);
17
+ }
18
+ async ensureOutboundSession(streamId, opts) {
19
+ await this._ensureOutboundSession(streamId, opts);
20
+ }
21
+ async _ensureOutboundSession(streamId, opts) {
22
+ try {
23
+ const sessionKey = await this.device.getHybridGroupSessionKeyForStream(streamId);
24
+ return sessionKey;
25
+ }
26
+ catch (error) {
27
+ const { miniblockNum, miniblockHash } = await this.client.getMiniblockInfo(streamId);
28
+ // if we don't have a cached session at this point, create a new one
29
+ const { sessionId, sessionKey } = await this.device.createHybridGroupSession(streamId, miniblockNum, miniblockHash);
30
+ log(`Started new hybrid group session ${sessionId}`);
31
+ // don't wait for the session to be shared
32
+ const promise = this.shareSession(streamId, sessionId);
33
+ if (opts?.awaitInitialShareSession === true) {
34
+ await promise;
35
+ }
36
+ else {
37
+ // await the promise but timeout after N seconds
38
+ const waitTimeBeforeMovingOn = 30000;
39
+ await Promise.race([
40
+ promise,
41
+ new Promise((resolve, _) => setTimeout(() => resolve(), waitTimeBeforeMovingOn)),
42
+ ]);
43
+ }
44
+ return sessionKey;
45
+ }
46
+ }
47
+ async shareSession(streamId, sessionId) {
48
+ const devicesInRoom = await this.client.getDevicesInStream(streamId);
49
+ const session = await this.device.exportHybridGroupSession(streamId, sessionId);
50
+ if (!session) {
51
+ throw new Error('Session key not found for session ' + sessionId);
52
+ }
53
+ await this.client.encryptAndShareGroupSessions(streamId, [session], devicesInRoom, this.algorithm);
54
+ }
55
+ /**
56
+ * @deprecated
57
+ */
58
+ async encrypt_deprecated_v0(streamId, payload) {
59
+ const sessionKey = await this._ensureOutboundSession(streamId);
60
+ const key = await importAesGsmKeyBytes(sessionKey.key);
61
+ const payloadBytes = new TextEncoder().encode(payload);
62
+ const { ciphertext, iv } = await encryptAesGcm(key, payloadBytes);
63
+ return create(EncryptedDataSchema, {
64
+ algorithm: this.algorithm,
65
+ senderKey: this.device.deviceCurve25519Key,
66
+ sessionIdBytes: sessionKey.sessionId,
67
+ ciphertextBytes: ciphertext,
68
+ ivBytes: iv,
69
+ version: EncryptedDataVersion.ENCRYPTED_DATA_VERSION_0,
70
+ });
71
+ }
72
+ /**
73
+ * @param content - plaintext event content
74
+ *
75
+ * @returns Promise which resolves to the new event body
76
+ */
77
+ async encrypt(streamId, payload) {
78
+ log('Starting to encrypt event');
79
+ const sessionKey = await this._ensureOutboundSession(streamId);
80
+ const key = await importAesGsmKeyBytes(sessionKey.key);
81
+ const { ciphertext, iv } = await encryptAesGcm(key, payload);
82
+ return create(EncryptedDataSchema, {
83
+ algorithm: this.algorithm,
84
+ senderKey: this.device.deviceCurve25519Key,
85
+ sessionIdBytes: sessionKey.sessionId,
86
+ ciphertextBytes: ciphertext,
87
+ ivBytes: iv,
88
+ version: EncryptedDataVersion.ENCRYPTED_DATA_VERSION_1,
89
+ });
90
+ }
91
+ }
92
+ //# sourceMappingURL=hybridGroupEncryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hybridGroupEncryption.js","sourceRoot":"","sources":["../src/hybridGroupEncryption.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**************************************************************************
2
+ * This file is generated by running 🏕️ scripts/generate_sdk_index.sh 🏕️ *
3
+ **************************************************************************/
4
+ export * from './base';
5
+ export * from './cryptoAesGcm';
6
+ export * from './cryptoStore';
7
+ export * from './decryptionExtensions';
8
+ export * from './derivedEncryption';
9
+ export * from './encryptionDelegate';
10
+ export * from './encryptionDevice';
11
+ export * from './encryptionTypes';
12
+ export * from './groupDecryption';
13
+ export * from './groupEncryption';
14
+ export * from './groupEncryptionCrypto';
15
+ export * from './hybridGroupDecryption';
16
+ export * from './hybridGroupEncryption';
17
+ export * from './olmLib';
18
+ export * from './storeTypes';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;4EAE4E;AAC5E,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ /**************************************************************************
2
+ * This file is generated by running 🏕️ scripts/generate_sdk_index.sh 🏕️ *
3
+ **************************************************************************/
4
+ export * from './base';
5
+ export * from './cryptoAesGcm';
6
+ export * from './cryptoStore';
7
+ export * from './decryptionExtensions';
8
+ export * from './derivedEncryption';
9
+ export * from './encryptionDelegate';
10
+ export * from './encryptionDevice';
11
+ export * from './encryptionTypes';
12
+ export * from './groupDecryption';
13
+ export * from './groupEncryption';
14
+ export * from './groupEncryptionCrypto';
15
+ export * from './hybridGroupDecryption';
16
+ export * from './hybridGroupEncryption';
17
+ export * from './olmLib';
18
+ export * from './storeTypes';
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;4EAE4E;AAC5E,cAAc,QAAQ,CAAA;AACtB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,wBAAwB,CAAA;AACtC,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,cAAc,CAAA"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Utilities common to Olm encryption
3
+ */
4
+ export declare enum EncryptionAlgorithmId {
5
+ Olm = "r.olm.v1.curve25519-aes-sha2"
6
+ }
7
+ export declare enum GroupEncryptionAlgorithmId {
8
+ GroupEncryption = "r.group-encryption.v1.aes-sha2",
9
+ HybridGroupEncryption = "grpaes"
10
+ }
11
+ export declare function isGroupEncryptionAlgorithmId(value: string): value is GroupEncryptionAlgorithmId;
12
+ type Matched = {
13
+ kind: 'matched';
14
+ value: GroupEncryptionAlgorithmId;
15
+ };
16
+ type Unrecognized = {
17
+ kind: 'unrecognized';
18
+ value: string;
19
+ };
20
+ export declare function parseGroupEncryptionAlgorithmId(value: string, defaultValue?: GroupEncryptionAlgorithmId): Matched | Unrecognized;
21
+ export interface UserDevice {
22
+ deviceKey: string;
23
+ fallbackKey: string;
24
+ }
25
+ export interface UserDeviceCollection {
26
+ [userId: string]: UserDevice[];
27
+ }
28
+ export interface GroupEncryptionSession {
29
+ streamId: string;
30
+ sessionId: string;
31
+ sessionKey: string;
32
+ algorithm: GroupEncryptionAlgorithmId;
33
+ }
34
+ export {};
35
+ //# sourceMappingURL=olmLib.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"olmLib.d.ts","sourceRoot":"","sources":["../src/olmLib.ts"],"names":[],"mappings":"AAOA;;GAEG;AAGH,oBAAY,qBAAqB;IAC7B,GAAG,iCAAiC;CACvC;AAED,oBAAY,0BAA0B;IAElC,eAAe,mCAAmC;IAElD,qBAAqB,WAAW;CACnC;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,0BAA0B,CAE/F;AAED,KAAK,OAAO,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,0BAA0B,CAAA;CAAE,CAAA;AACrE,KAAK,YAAY,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3D,wBAAgB,+BAA+B,CAC3C,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,0BAA0B,GAC1C,OAAO,GAAG,YAAY,CAYxB;AAED,MAAM,WAAW,UAAU;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,oBAAoB;IACjC,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,CAAA;CACjC;AAED,MAAM,WAAW,sBAAsB;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,0BAA0B,CAAA;CACxC"}