@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
package/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 River Association
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Group Encryption protocol
2
+
3
+ Documentation here: <https://docs.towns.com/build/towns-encryption>
package/dist/base.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ import { GroupEncryptionAlgorithmId, GroupEncryptionSession, UserDeviceCollection } from './olmLib';
2
+ import { EncryptionDevice } from './encryptionDevice';
3
+ import { EncryptedData } from '@towns-protocol/proto';
4
+ export interface IGroupEncryptionClient {
5
+ downloadUserDeviceInfo(userIds: string[], forceDownload: boolean): Promise<UserDeviceCollection>;
6
+ encryptAndShareGroupSessions(streamId: string, sessions: GroupEncryptionSession[], devicesInRoom: UserDeviceCollection, algorithm: GroupEncryptionAlgorithmId): Promise<void>;
7
+ getDevicesInStream(streamId: string): Promise<UserDeviceCollection>;
8
+ getMiniblockInfo(streamId: string): Promise<{
9
+ miniblockNum: bigint;
10
+ miniblockHash: Uint8Array;
11
+ }>;
12
+ }
13
+ export interface IDecryptionParams {
14
+ /** olm.js wrapper */
15
+ device: EncryptionDevice;
16
+ }
17
+ export interface IEncryptionParams {
18
+ client: IGroupEncryptionClient;
19
+ /** olm.js wrapper */
20
+ device: EncryptionDevice;
21
+ }
22
+ /**
23
+ * base type for encryption implementations
24
+ */
25
+ export declare abstract class EncryptionAlgorithm implements IEncryptionParams {
26
+ readonly device: EncryptionDevice;
27
+ readonly client: IGroupEncryptionClient;
28
+ /**
29
+ * @param params - parameters
30
+ */
31
+ constructor(params: IEncryptionParams);
32
+ abstract ensureOutboundSession(streamId: string, opts?: {
33
+ awaitInitialShareSession: boolean;
34
+ }): Promise<void>;
35
+ abstract encrypt_deprecated_v0(streamId: string, payload: string): Promise<EncryptedData>;
36
+ abstract encrypt(streamId: string, payload: Uint8Array): Promise<EncryptedData>;
37
+ }
38
+ /**
39
+ * base type for decryption implementations
40
+ */
41
+ export declare abstract class DecryptionAlgorithm implements IDecryptionParams {
42
+ readonly device: EncryptionDevice;
43
+ constructor(params: IDecryptionParams);
44
+ abstract decrypt(streamId: string, content: EncryptedData): Promise<Uint8Array | string>;
45
+ abstract importStreamKey(streamId: string, session: GroupEncryptionSession): Promise<void>;
46
+ abstract exportGroupSession(streamId: string, sessionId: string): Promise<GroupEncryptionSession | undefined>;
47
+ abstract exportGroupSessions(): Promise<GroupEncryptionSession[]>;
48
+ abstract exportGroupSessionIds(streamId: string): Promise<string[]>;
49
+ abstract hasSessionKey(streamId: string, sessionId: string): Promise<boolean>;
50
+ }
51
+ /**
52
+ * Exception thrown when decryption fails
53
+ *
54
+ * @param msg - user-visible message describing the problem
55
+ *
56
+ * @param details - key/value pairs reported in the logs but not shown
57
+ * to the user.
58
+ */
59
+ export declare class DecryptionError extends Error {
60
+ readonly code: string;
61
+ constructor(code: string, msg: string);
62
+ }
63
+ export declare function isDecryptionError(e: Error): e is DecryptionError;
64
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAEnG,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAErD,MAAM,WAAW,sBAAsB;IACnC,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAChG,4BAA4B,CACxB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,sBAAsB,EAAE,EAClC,aAAa,EAAE,oBAAoB,EACnC,SAAS,EAAE,0BAA0B,GACtC,OAAO,CAAC,IAAI,CAAC,CAAA;IAChB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IACnE,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,UAAU,CAAA;KAAE,CAAC,CAAA;CACnG;AAED,MAAM,WAAW,iBAAiB;IAC9B,qBAAqB;IACrB,MAAM,EAAE,gBAAgB,CAAA;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,sBAAsB,CAAA;IAC9B,qBAAqB;IACrB,MAAM,EAAE,gBAAgB,CAAA;CAC3B;AAED;;GAEG;AACH,8BAAsB,mBAAoB,YAAW,iBAAiB;IAClE,SAAgB,MAAM,EAAE,gBAAgB,CAAA;IACxC,SAAgB,MAAM,EAAE,sBAAsB,CAAA;IAE9C;;OAEG;gBACgB,MAAM,EAAE,iBAAiB;IAK5C,QAAQ,CAAC,qBAAqB,CAC1B,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,wBAAwB,EAAE,OAAO,CAAA;KAAE,GAC7C,OAAO,CAAC,IAAI,CAAC;IAEhB,QAAQ,CAAC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IACzF,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CAClF;AAED;;GAEG;AACH,8BAAsB,mBAAoB,YAAW,iBAAiB;IAClE,SAAgB,MAAM,EAAE,gBAAgB,CAAA;gBAErB,MAAM,EAAE,iBAAiB;IAI5C,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC;IAExF,QAAQ,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1F,QAAQ,CAAC,kBAAkB,CACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAE9C,QAAQ,CAAC,mBAAmB,IAAI,OAAO,CAAC,sBAAsB,EAAE,CAAC;IACjE,QAAQ,CAAC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IACnE,QAAQ,CAAC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAChF;AAED;;;;;;;GAOG;AACH,qBAAa,eAAgB,SAAQ,KAAK;aACH,IAAI,EAAE,MAAM;gBAAZ,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAK/D;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,IAAI,eAAe,CAEhE"}
package/dist/base.js ADDED
@@ -0,0 +1,44 @@
1
+ /**
2
+ * base type for encryption implementations
3
+ */
4
+ export class EncryptionAlgorithm {
5
+ device;
6
+ client;
7
+ /**
8
+ * @param params - parameters
9
+ */
10
+ constructor(params) {
11
+ this.device = params.device;
12
+ this.client = params.client;
13
+ }
14
+ }
15
+ /**
16
+ * base type for decryption implementations
17
+ */
18
+ export class DecryptionAlgorithm {
19
+ device;
20
+ constructor(params) {
21
+ this.device = params.device;
22
+ }
23
+ }
24
+ /**
25
+ * Exception thrown when decryption fails
26
+ *
27
+ * @param msg - user-visible message describing the problem
28
+ *
29
+ * @param details - key/value pairs reported in the logs but not shown
30
+ * to the user.
31
+ */
32
+ export class DecryptionError extends Error {
33
+ code;
34
+ constructor(code, msg) {
35
+ super(msg);
36
+ this.code = code;
37
+ this.code = code;
38
+ this.name = 'DecryptionError';
39
+ }
40
+ }
41
+ export function isDecryptionError(e) {
42
+ return e.name === 'DecryptionError';
43
+ }
44
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../src/base.ts"],"names":[],"mappings":"AA4BA;;GAEG;AACH,MAAM,OAAgB,mBAAmB;IACrB,MAAM,CAAkB;IACxB,MAAM,CAAwB;IAE9C;;OAEG;IACH,YAAmB,MAAyB;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;IAC/B,CAAC;CASJ;AAED;;GAEG;AACH,MAAM,OAAgB,mBAAmB;IACrB,MAAM,CAAkB;IAExC,YAAmB,MAAyB;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;IAC/B,CAAC;CAcJ;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACH;IAAnC,YAAmC,IAAY,EAAE,GAAW;QACxD,KAAK,CAAC,GAAG,CAAC,CAAA;QADqB,SAAI,GAAJ,IAAI,CAAQ;QAE3C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;IACjC,CAAC;CACJ;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAQ;IACtC,OAAO,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAA;AACvC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare function generateNewAesGcmKey(): Promise<CryptoKey>;
2
+ export declare function exportAesGsmKeyBytes(key: CryptoKey): Promise<Uint8Array>;
3
+ export declare function importAesGsmKeyBytes(key: Uint8Array): Promise<CryptoKey>;
4
+ export declare function encryptAesGcm(key: CryptoKey, data: Uint8Array): Promise<{
5
+ ciphertext: Uint8Array;
6
+ iv: Uint8Array;
7
+ }>;
8
+ export declare function decryptAesGcm(key: CryptoKey, ciphertext: Uint8Array, iv: Uint8Array): Promise<Uint8Array>;
9
+ //# sourceMappingURL=cryptoAesGcm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cryptoAesGcm.d.ts","sourceRoot":"","sources":["../src/cryptoAesGcm.ts"],"names":[],"mappings":"AAAA,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,SAAS,CAAC,CAE/D;AAED,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAG9E;AAED,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CAE9E;AAED,wBAAsB,aAAa,CAC/B,GAAG,EAAE,SAAS,EACd,IAAI,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,UAAU,EAAE,UAAU,CAAC;IAAC,EAAE,EAAE,UAAU,CAAA;CAAE,CAAC,CAYrD;AAED,wBAAsB,aAAa,CAC/B,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CAarB"}
@@ -0,0 +1,30 @@
1
+ export async function generateNewAesGcmKey() {
2
+ return crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, true, ['encrypt', 'decrypt']);
3
+ }
4
+ export async function exportAesGsmKeyBytes(key) {
5
+ const exportedKey = await crypto.subtle.exportKey('raw', key);
6
+ return new Uint8Array(exportedKey);
7
+ }
8
+ export async function importAesGsmKeyBytes(key) {
9
+ return crypto.subtle.importKey('raw', key, 'AES-GCM', true, ['encrypt', 'decrypt']);
10
+ }
11
+ export async function encryptAesGcm(key, data) {
12
+ // If data is empty, it's obvious what the message is from the result length.
13
+ if (data.length === 0) {
14
+ throw new Error('Data to encrypt cannot be empty');
15
+ }
16
+ const iv = crypto.getRandomValues(new Uint8Array(12));
17
+ const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv, tagLength: 128 }, key, data);
18
+ return { ciphertext: new Uint8Array(encrypted), iv };
19
+ }
20
+ export async function decryptAesGcm(key, ciphertext, iv) {
21
+ if (iv.length !== 12) {
22
+ throw new Error('IV must be 12 bytes');
23
+ }
24
+ if (ciphertext.length < 17) {
25
+ throw new Error('Ciphertext can not be this short');
26
+ }
27
+ const decrypted = await crypto.subtle.decrypt({ name: 'AES-GCM', iv, tagLength: 128 }, key, ciphertext);
28
+ return new Uint8Array(decrypted);
29
+ }
30
+ //# sourceMappingURL=cryptoAesGcm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cryptoAesGcm.js","sourceRoot":"","sources":["../src/cryptoAesGcm.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACtC,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAA;AACpG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,GAAc;IACrD,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IAC7D,OAAO,IAAI,UAAU,CAAC,WAAW,CAAC,CAAA;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,GAAe;IACtD,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAA;AACvF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,GAAc,EACd,IAAgB;IAEhB,6EAA6E;IAC7E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAA;IACrD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACzC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EACvC,GAAG,EACH,IAAI,CACP,CAAA;IACD,OAAO,EAAE,UAAU,EAAE,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAA;AACxD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,GAAc,EACd,UAAsB,EACtB,EAAc;IAEd,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAA;IAC1C,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACvD,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CACzC,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,EACvC,GAAG,EACH,UAAU,CACb,CAAA;IACD,OAAO,IAAI,UAAU,CAAC,SAAS,CAAC,CAAA;AACpC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { AccountRecord, ExtendedInboundGroupSessionData, GroupSessionRecord, HybridGroupSessionRecord, UserDeviceRecord } from './storeTypes';
2
+ import Dexie, { Table } from 'dexie';
3
+ import { InboundGroupSessionData } from './encryptionDevice';
4
+ import { UserDevice } from './olmLib';
5
+ export declare class CryptoStore extends Dexie {
6
+ account: Table<AccountRecord>;
7
+ outboundGroupSessions: Table<GroupSessionRecord>;
8
+ inboundGroupSessions: Table<ExtendedInboundGroupSessionData>;
9
+ hybridGroupSessions: Table<HybridGroupSessionRecord>;
10
+ devices: Table<UserDeviceRecord>;
11
+ userId: string;
12
+ constructor(databaseName: string, userId: string);
13
+ initialize(): Promise<void>;
14
+ deleteAllData(): void;
15
+ deleteInboundGroupSessions(streamId: string, sessionId: string): Promise<void>;
16
+ deleteAccount(userId: string): Promise<void>;
17
+ getAccount(): Promise<string>;
18
+ storeAccount(accountPickle: string): Promise<void>;
19
+ storeEndToEndOutboundGroupSession(sessionId: string, sessionData: string, streamId: string): Promise<void>;
20
+ getEndToEndOutboundGroupSession(streamId: string): Promise<string>;
21
+ getAllEndToEndOutboundGroupSessions(): Promise<GroupSessionRecord[]>;
22
+ getEndToEndInboundGroupSession(streamId: string, sessionId: string): Promise<InboundGroupSessionData | undefined>;
23
+ getHybridGroupSession(streamId: string, sessionId: string): Promise<HybridGroupSessionRecord | undefined>;
24
+ getHybridGroupSessionsForStream(streamId: string): Promise<HybridGroupSessionRecord[]>;
25
+ getAllEndToEndInboundGroupSessions(): Promise<ExtendedInboundGroupSessionData[]>;
26
+ getAllHybridGroupSessions(): Promise<HybridGroupSessionRecord[]>;
27
+ storeEndToEndInboundGroupSession(streamId: string, sessionId: string, sessionData: InboundGroupSessionData): Promise<void>;
28
+ storeHybridGroupSession(sessionData: HybridGroupSessionRecord): Promise<void>;
29
+ getInboundGroupSessionIds(streamId: string): Promise<string[]>;
30
+ getHybridGroupSessionIds(streamId: string): Promise<string[]>;
31
+ withAccountTx<T>(fn: () => Promise<T>): Promise<T>;
32
+ withGroupSessions<T>(fn: () => Promise<T>): Promise<T>;
33
+ /**
34
+ * Only used for testing
35
+ * @returns total number of devices in the store
36
+ */
37
+ deviceRecordCount(): Promise<number>;
38
+ /**
39
+ * Store a list of devices for a given userId
40
+ * @param userId string
41
+ * @param devices UserDeviceInfo[]
42
+ * @param expirationMs Expiration time in milliseconds
43
+ */
44
+ saveUserDevices(userId: string, devices: UserDevice[], expirationMs?: number): Promise<void>;
45
+ /**
46
+ * Get all stored devices for a given userId
47
+ * @param userId string
48
+ * @returns UserDevice[], a list of devices
49
+ */
50
+ getUserDevices(userId: string): Promise<UserDevice[]>;
51
+ }
52
+ //# sourceMappingURL=cryptoStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cryptoStore.d.ts","sourceRoot":"","sources":["../src/cryptoStore.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,aAAa,EACb,+BAA+B,EAC/B,kBAAkB,EAClB,wBAAwB,EACxB,gBAAgB,EACnB,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAEpC,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAMrC,qBAAa,WAAY,SAAQ,KAAK;IAClC,OAAO,EAAG,KAAK,CAAC,aAAa,CAAC,CAAA;IAC9B,qBAAqB,EAAG,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACjD,oBAAoB,EAAG,KAAK,CAAC,+BAA+B,CAAC,CAAA;IAC7D,mBAAmB,EAAG,KAAK,CAAC,wBAAwB,CAAC,CAAA;IACrD,OAAO,EAAG,KAAK,CAAC,gBAAgB,CAAC,CAAA;IACjC,MAAM,EAAE,MAAM,CAAA;gBAEF,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAY1C,UAAU;IAIhB,aAAa;IAIP,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9E,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ7B,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,iCAAiC,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAIV,+BAA+B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQlE,mCAAmC,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAIpE,8BAA8B,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC;IAIzC,qBAAqB,CACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC;IAI1C,+BAA+B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAKtF,kCAAkC,IAAI,OAAO,CAAC,+BAA+B,EAAE,CAAC;IAIhF,yBAAyB,IAAI,OAAO,CAAC,wBAAwB,EAAE,CAAC;IAIhE,gCAAgC,CAClC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,uBAAuB,GACrC,OAAO,CAAC,IAAI,CAAC;IAIV,uBAAuB,CAAC,WAAW,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7E,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAK9D,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAK7D,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,iBAAiB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAU5D;;;OAGG;IACG,iBAAiB;IAIvB;;;;;OAKG;IACG,eAAe,CACjB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,UAAU,EAAE,EACrB,YAAY,GAAE,MAA+C;IAQjE;;;;OAIG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAa9D"}
@@ -0,0 +1,131 @@
1
+ import Dexie from 'dexie';
2
+ // TODO: Increase this time to 10 days or something.
3
+ // Its 15 min right now so we can catch any issues with the expiration time.
4
+ const DEFAULT_USER_DEVICE_EXPIRATION_TIME_MS = 15 * 60 * 1000;
5
+ export class CryptoStore extends Dexie {
6
+ account;
7
+ outboundGroupSessions;
8
+ inboundGroupSessions;
9
+ hybridGroupSessions;
10
+ devices;
11
+ userId;
12
+ constructor(databaseName, userId) {
13
+ super(databaseName);
14
+ this.userId = userId;
15
+ this.version(6).stores({
16
+ account: 'id',
17
+ inboundGroupSessions: '[streamId+sessionId]',
18
+ outboundGroupSessions: 'streamId',
19
+ hybridGroupSessions: '[streamId+sessionId],streamId',
20
+ devices: '[userId+deviceKey],expirationTimestamp',
21
+ });
22
+ }
23
+ async initialize() {
24
+ await this.devices.where('expirationTimestamp').below(Date.now()).delete();
25
+ }
26
+ deleteAllData() {
27
+ throw new Error('Method not implemented.');
28
+ }
29
+ async deleteInboundGroupSessions(streamId, sessionId) {
30
+ await this.inboundGroupSessions.where({ streamId, sessionId }).delete();
31
+ }
32
+ async deleteAccount(userId) {
33
+ await this.account.where({ id: userId }).delete();
34
+ }
35
+ async getAccount() {
36
+ const account = await this.account.get({ id: this.userId });
37
+ if (!account) {
38
+ throw new Error('account not found');
39
+ }
40
+ return account.accountPickle;
41
+ }
42
+ async storeAccount(accountPickle) {
43
+ await this.account.put({ id: this.userId, accountPickle });
44
+ }
45
+ async storeEndToEndOutboundGroupSession(sessionId, sessionData, streamId) {
46
+ await this.outboundGroupSessions.put({ sessionId, session: sessionData, streamId });
47
+ }
48
+ async getEndToEndOutboundGroupSession(streamId) {
49
+ const session = await this.outboundGroupSessions.get({ streamId });
50
+ if (!session) {
51
+ throw new Error('session not found');
52
+ }
53
+ return session.session;
54
+ }
55
+ async getAllEndToEndOutboundGroupSessions() {
56
+ return await this.outboundGroupSessions.toArray();
57
+ }
58
+ async getEndToEndInboundGroupSession(streamId, sessionId) {
59
+ return await this.inboundGroupSessions.get({ sessionId, streamId });
60
+ }
61
+ async getHybridGroupSession(streamId, sessionId) {
62
+ return await this.hybridGroupSessions.get({ streamId, sessionId });
63
+ }
64
+ async getHybridGroupSessionsForStream(streamId) {
65
+ const sessions = await this.hybridGroupSessions.where({ streamId }).toArray();
66
+ return sessions;
67
+ }
68
+ async getAllEndToEndInboundGroupSessions() {
69
+ return await this.inboundGroupSessions.toArray();
70
+ }
71
+ async getAllHybridGroupSessions() {
72
+ return await this.hybridGroupSessions.toArray();
73
+ }
74
+ async storeEndToEndInboundGroupSession(streamId, sessionId, sessionData) {
75
+ await this.inboundGroupSessions.put({ streamId, sessionId, ...sessionData });
76
+ }
77
+ async storeHybridGroupSession(sessionData) {
78
+ await this.hybridGroupSessions.put({ ...sessionData });
79
+ }
80
+ async getInboundGroupSessionIds(streamId) {
81
+ const sessions = await this.inboundGroupSessions.where({ streamId }).toArray();
82
+ return sessions.map((s) => s.sessionId);
83
+ }
84
+ async getHybridGroupSessionIds(streamId) {
85
+ const sessions = await this.hybridGroupSessions.where({ streamId }).toArray();
86
+ return sessions.map((s) => s.sessionId);
87
+ }
88
+ async withAccountTx(fn) {
89
+ return await this.transaction('rw', this.account, fn);
90
+ }
91
+ async withGroupSessions(fn) {
92
+ return await this.transaction('rw', this.outboundGroupSessions, this.inboundGroupSessions, this.hybridGroupSessions, // aellis this should be in its own transaction but tests were failing otherwise
93
+ fn);
94
+ }
95
+ /**
96
+ * Only used for testing
97
+ * @returns total number of devices in the store
98
+ */
99
+ async deviceRecordCount() {
100
+ return await this.devices.count();
101
+ }
102
+ /**
103
+ * Store a list of devices for a given userId
104
+ * @param userId string
105
+ * @param devices UserDeviceInfo[]
106
+ * @param expirationMs Expiration time in milliseconds
107
+ */
108
+ async saveUserDevices(userId, devices, expirationMs = DEFAULT_USER_DEVICE_EXPIRATION_TIME_MS) {
109
+ const expirationTimestamp = Date.now() + expirationMs;
110
+ for (const device of devices) {
111
+ await this.devices.put({ userId, expirationTimestamp, ...device });
112
+ }
113
+ }
114
+ /**
115
+ * Get all stored devices for a given userId
116
+ * @param userId string
117
+ * @returns UserDevice[], a list of devices
118
+ */
119
+ async getUserDevices(userId) {
120
+ const expirationTimestamp = Date.now();
121
+ return (await this.devices
122
+ .where('userId')
123
+ .equals(userId)
124
+ .and((record) => record.expirationTimestamp > expirationTimestamp)
125
+ .toArray()).map((record) => ({
126
+ deviceKey: record.deviceKey,
127
+ fallbackKey: record.fallbackKey,
128
+ }));
129
+ }
130
+ }
131
+ //# sourceMappingURL=cryptoStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cryptoStore.js","sourceRoot":"","sources":["../src/cryptoStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,200 @@
1
+ import TypedEmitter from 'typed-emitter';
2
+ import { Permission } from '@towns-protocol/web3';
3
+ import { AddEventResponse_Error, EncryptedData, SessionKeys, UserInboxPayload_GroupEncryptionSessions } from '@towns-protocol/proto';
4
+ import { DLogger } from '@towns-protocol/dlog';
5
+ import { GroupEncryptionAlgorithmId, GroupEncryptionSession, UserDevice } from './olmLib';
6
+ import { GroupEncryptionCrypto } from './groupEncryptionCrypto';
7
+ export interface EntitlementsDelegate {
8
+ isEntitled(spaceId: string | undefined, channelId: string | undefined, user: string, permission: Permission): Promise<boolean>;
9
+ }
10
+ export declare enum DecryptionStatus {
11
+ initializing = "initializing",
12
+ updating = "updating",
13
+ working = "working",
14
+ idle = "idle",
15
+ done = "done"
16
+ }
17
+ export type DecryptionEvents = {
18
+ decryptionExtStatusChanged: (status: DecryptionStatus) => void;
19
+ };
20
+ export interface NewGroupSessionItem {
21
+ streamId: string;
22
+ sessions: UserInboxPayload_GroupEncryptionSessions;
23
+ }
24
+ export interface EncryptedContentItem {
25
+ streamId: string;
26
+ eventId: string;
27
+ kind: string;
28
+ encryptedData: EncryptedData;
29
+ }
30
+ export interface KeySolicitationContent {
31
+ deviceKey: string;
32
+ fallbackKey: string;
33
+ isNewDevice: boolean;
34
+ sessionIds: string[];
35
+ }
36
+ export interface EventSignatureBundle {
37
+ hash: Uint8Array;
38
+ signature: Uint8Array | undefined;
39
+ event: {
40
+ creatorAddress: Uint8Array;
41
+ delegateSig: Uint8Array;
42
+ delegateExpiryEpochMs: bigint;
43
+ };
44
+ }
45
+ export interface KeySolicitationItem {
46
+ streamId: string;
47
+ fromUserId: string;
48
+ fromUserAddress: Uint8Array;
49
+ solicitation: KeySolicitationContent;
50
+ respondAfter: number;
51
+ sigBundle: EventSignatureBundle;
52
+ hashStr: string;
53
+ }
54
+ export interface KeySolicitationData {
55
+ streamId: string;
56
+ isNewDevice: boolean;
57
+ missingSessionIds: string[];
58
+ }
59
+ export interface KeyFulfilmentData {
60
+ streamId: string;
61
+ userAddress: Uint8Array;
62
+ deviceKey: string;
63
+ sessionIds: string[];
64
+ }
65
+ export interface GroupSessionsData {
66
+ streamId: string;
67
+ item: KeySolicitationItem;
68
+ sessions: GroupEncryptionSession[];
69
+ algorithm: GroupEncryptionAlgorithmId;
70
+ }
71
+ export interface DecryptionSessionError {
72
+ missingSession: boolean;
73
+ kind: string;
74
+ encryptedData: EncryptedData;
75
+ error?: unknown;
76
+ }
77
+ /**
78
+ *
79
+ * Responsibilities:
80
+ * 1. Download new to-device messages that happened while we were offline
81
+ * 2. Decrypt new to-device messages
82
+ * 3. Decrypt encrypted content
83
+ * 4. Retry decryption failures, request keys for failed decryption
84
+ * 5. Respond to key solicitations
85
+ *
86
+ *
87
+ * Notes:
88
+ * If in the future we started snapshotting the eventNum of the last message sent by every user,
89
+ * we could use that to determine the order we send out keys, and the order that we reply to key solicitations.
90
+ *
91
+ * It should be easy to introduce a priority stream, where we decrypt messages from that stream first, before
92
+ * anything else, so the messages show up quicky in the ui that the user is looking at.
93
+ *
94
+ * We need code to purge bad sessions (if someones sends us the wrong key, or a key that doesn't decrypt the message)
95
+ */
96
+ export declare abstract class BaseDecryptionExtensions {
97
+ private _status;
98
+ private mainQueues;
99
+ private streamQueues;
100
+ private upToDateStreams;
101
+ private highPriorityIds;
102
+ private recentStreamIds;
103
+ private decryptionFailures;
104
+ private inProgressTick?;
105
+ private timeoutId?;
106
+ private delayMs;
107
+ private started;
108
+ private numRecentStreamIds;
109
+ private emitter;
110
+ protected _onStopFn?: () => void;
111
+ protected log: {
112
+ debug: DLogger;
113
+ info: DLogger;
114
+ error: DLogger;
115
+ };
116
+ readonly crypto: GroupEncryptionCrypto;
117
+ readonly entitlementDelegate: EntitlementsDelegate;
118
+ readonly userDevice: UserDevice;
119
+ readonly userId: string;
120
+ constructor(emitter: TypedEmitter<DecryptionEvents>, crypto: GroupEncryptionCrypto, entitlementDelegate: EntitlementsDelegate, userDevice: UserDevice, userId: string, upToDateStreams: Set<string>, inLogId: string);
121
+ abstract ackNewGroupSession(session: UserInboxPayload_GroupEncryptionSessions): Promise<void>;
122
+ abstract decryptGroupEvent(streamId: string, eventId: string, kind: string, encryptedData: EncryptedData): Promise<void>;
123
+ abstract downloadNewMessages(): Promise<void>;
124
+ abstract getKeySolicitations(streamId: string): KeySolicitationContent[];
125
+ abstract hasStream(streamId: string): boolean;
126
+ abstract isUserEntitledToKeyExchange(streamId: string, userId: string, opts?: {
127
+ skipOnChainValidation: boolean;
128
+ }): Promise<boolean>;
129
+ abstract isValidEvent(item: KeySolicitationItem): {
130
+ isValid: boolean;
131
+ reason?: string;
132
+ };
133
+ abstract isUserInboxStreamUpToDate(upToDateStreams: Set<string>): boolean;
134
+ abstract onDecryptionError(item: EncryptedContentItem, err: DecryptionSessionError): void;
135
+ abstract sendKeySolicitation(args: KeySolicitationData): Promise<void>;
136
+ abstract sendKeyFulfillment(args: KeyFulfilmentData): Promise<{
137
+ error?: AddEventResponse_Error;
138
+ }>;
139
+ abstract encryptAndShareGroupSessions(args: GroupSessionsData): Promise<void>;
140
+ abstract shouldPauseTicking(): boolean;
141
+ /**
142
+ * uploadDeviceKeys
143
+ * upload device keys to the server
144
+ */
145
+ abstract uploadDeviceKeys(): Promise<void>;
146
+ abstract getPriorityForStream(streamId: string, highPriorityIds: Set<string>, recentStreamIds: Set<string>): number;
147
+ enqueueNewGroupSessions(sessions: UserInboxPayload_GroupEncryptionSessions, _senderId: string): void;
148
+ enqueueNewEncryptedContent(streamId: string, eventId: string, kind: string, // kind of encrypted data
149
+ encryptedData: EncryptedData): void;
150
+ enqueueInitKeySolicitations(streamId: string, eventHashStr: string, members: {
151
+ userId: string;
152
+ userAddress: Uint8Array;
153
+ solicitations: KeySolicitationContent[];
154
+ }[], sigBundle: EventSignatureBundle): void;
155
+ enqueueKeySolicitation(streamId: string, eventHashStr: string, fromUserId: string, fromUserAddress: Uint8Array, keySolicitation: KeySolicitationContent, sigBundle: EventSignatureBundle): void;
156
+ setStreamUpToDate(streamId: string): void;
157
+ resetUpToDateStreams(): void;
158
+ retryDecryptionFailures(streamId: string): void;
159
+ start(): void;
160
+ enqueueNewMessageDownload(): void;
161
+ onStart(): void;
162
+ stop(): Promise<void>;
163
+ onStop(): Promise<void>;
164
+ get status(): DecryptionStatus;
165
+ private setStatus;
166
+ private compareStreamIds;
167
+ private lastPrintedAt;
168
+ protected checkStartTicking(): void;
169
+ private stopTicking;
170
+ private getDelayMs;
171
+ private tick;
172
+ /**
173
+ * processNewGroupSession
174
+ * process new group sessions that were sent to our to device stream inbox
175
+ * re-enqueue any decryption failures with matching session id
176
+ */
177
+ private processNewGroupSession;
178
+ /**
179
+ * processEncryptedContentItem
180
+ * try to decrypt encrytped content
181
+ */
182
+ private processEncryptedContentItem;
183
+ /**
184
+ * processMissingKeys
185
+ * process missing keys and send key solicitations to streams
186
+ */
187
+ private processMissingKeys;
188
+ /**
189
+ * processKeySolicitation
190
+ * process incoming key solicitations and send keys and key fulfillments
191
+ */
192
+ private processKeySolicitation;
193
+ /**
194
+ * can be overridden to add a delay to the key solicitation response
195
+ */
196
+ getRespondDelayMSForKeySolicitation(_streamId: string, _userId: string): number;
197
+ setHighPriorityStreams(streamIds: string[]): void;
198
+ }
199
+ export declare function makeSessionKeys(sessions: GroupEncryptionSession[]): SessionKeys;
200
+ //# sourceMappingURL=decryptionExtensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decryptionExtensions.d.ts","sourceRoot":"","sources":["../src/decryptionExtensions.ts"],"names":[],"mappings":"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"}