@kojinx/collab-crypto 0.0.2
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/esm2022/kojinx-collab-crypto.mjs +5 -0
- package/esm2022/lib/models/crypto.models.mjs +2 -0
- package/esm2022/lib/services/e2e-chat-crypto.service.mjs +148 -0
- package/esm2022/lib/services/session-key-manager.service.mjs +267 -0
- package/esm2022/lib/tokens.mjs +36 -0
- package/esm2022/lib/utils/safety-number.utils.mjs +72 -0
- package/esm2022/public-api.mjs +9 -0
- package/fesm2022/kojinx-collab-crypto.mjs +528 -0
- package/fesm2022/kojinx-collab-crypto.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/models/crypto.models.d.ts +99 -0
- package/lib/services/e2e-chat-crypto.service.d.ts +58 -0
- package/lib/services/session-key-manager.service.d.ts +71 -0
- package/lib/tokens.d.ts +24 -0
- package/lib/utils/safety-number.utils.d.ts +30 -0
- package/package.json +26 -0
- package/public-api.d.ts +5 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public-api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia29qaW54LWNvbGxhYi1jcnlwdG8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9rb2ppbngvY29sbGFiLWNyeXB0by9zcmMva29qaW54LWNvbGxhYi1jcnlwdG8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3J5cHRvLm1vZGVscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2tvamlueC9jb2xsYWItY3J5cHRvL3NyYy9saWIvbW9kZWxzL2NyeXB0by5tb2RlbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRW5jcnlwdGVkIG1lc3NhZ2UgcGF5bG9hZCBmb3JtYXQgdHJhbnNtaXR0ZWQgb3ZlciBIVFRQL1NTRSBhbmQgc3RvcmVkIGluIGRhdGFiYXNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVuY3J5cHRlZE1lc3NhZ2VQYXlsb2FkIHtcbiAgLyoqIEJhc2U2NC1lbmNvZGVkIEFFUy0yNTYtR0NNIGNpcGhlcnRleHQgKi9cbiAgY2lwaGVydGV4dDogc3RyaW5nO1xuICAvKiogQmFzZTY0LWVuY29kZWQgMTItYnl0ZSAoOTYtYml0KSBJbml0aWFsaXphdGlvbiBWZWN0b3IgKE5vbmNlKSAqL1xuICBub25jZTogc3RyaW5nO1xuICAvKiogVVVJRCBvZiB0aGUgU2Vzc2lvbiBLZXkgdXNlZCB0byBlbmNyeXB0IHRoaXMgbWVzc2FnZSAqL1xuICBzZXNzaW9uS2V5SWQ6IHN0cmluZztcbiAgLyoqIEdlbmVyYXRpb24gbnVtYmVyIG9mIHRoZSBTZXNzaW9uIEtleSAoaW5jcmVtZW50ZWQgZHVyaW5nIGtleSByb3RhdGlvbikgKi9cbiAgZ2VuZXJhdGlvbjogbnVtYmVyO1xufVxuXG4vKipcbiAqIEluLW1lbW9yeSBhY3RpdmUgU2Vzc2lvbiBLZXkgaG9sZGluZyBzdGFuZGFyZCBXM0MgQ3J5cHRvS2V5LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbnZlcnNhdGlvblNlc3Npb25LZXkge1xuICAvKiogVW5pcXVlIFVVSUQgaWRlbnRpZmllciBmb3IgdGhpcyBzZXNzaW9uIGtleSAqL1xuICBpZDogc3RyaW5nO1xuICAvKiogQ29udmVyc2F0aW9uIHNjb3BlICovXG4gIHR5cGU6ICdkbScgfCAnY2hhbm5lbCcgfCAnZ3JvdXAnO1xuICAvKiogVGFyZ2V0IGNvbnZlcnNhdGlvbiBJRCAocmVjaXBpZW50SWQgZm9yIDE6MSBETSwgY2hhbm5lbElkIGZvciBjaGFubmVscywgZ3JvdXBJZCBmb3IgZ3JvdXBzKSAqL1xuICBjb252ZXJzYXRpb25JZDogc3RyaW5nO1xuICAvKiogVzNDIFN1YnRsZUNyeXB0byBBRVMtR0NNIDI1Ni1iaXQgS2V5ICovXG4gIHJhd0tleTogQ3J5cHRvS2V5O1xuICAvKiogR2VuZXJhdGlvbiBpbmRleCAoc3RhcnRzIGF0IDEsIGluY3JlbWVudGVkIHVwb24gcm90YXRpb24pICovXG4gIGdlbmVyYXRpb246IG51bWJlcjtcbiAgLyoqIENyZWF0aW9uIGVwb2NoIHRpbWVzdGFtcCBpbiBtaWxsaXNlY29uZHMgKi9cbiAgY3JlYXRlZEF0OiBudW1iZXI7XG59XG5cbi8qKlxuICogV2lyZS1mb3JtYXQgZm9yIHN0b3JpbmcgYW5kIHN5bmNocm9uaXppbmcgZW5jcnlwdGVkIHNlc3Npb24ga2V5cyBhY3Jvc3MgbWVtYmVycy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZXNzaW9uS2V5RXhjaGFuZ2VQYXlsb2FkIHtcbiAgc2Vzc2lvbktleUlkOiBzdHJpbmc7XG4gIGNvbnZlcnNhdGlvblR5cGU6ICdkbScgfCAnY2hhbm5lbCcgfCAnZ3JvdXAnO1xuICBjb252ZXJzYXRpb25JZDogc3RyaW5nO1xuICBnZW5lcmF0aW9uOiBudW1iZXI7XG4gIC8qKiBNYXAgb2YgVXNlcklkIC0+IFJTQS1PQUVQIEJhc2U2NCBFbmNyeXB0ZWQgQUVTIFJhdyBLZXkgKi9cbiAgbWVtYmVyUGF5bG9hZHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGNyZWF0ZWRBdD86IHN0cmluZztcbiAgY3JlYXRlZEJ5Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE1lbWJlciBwdWJsaWMga2V5IGVudHJ5IHJldHVybmVkIGJ5IHB1YmxpYyBrZXkgZGlyZWN0b3J5LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1lbWJlclB1YmxpY0tleSB7XG4gIHVzZXJJZDogc3RyaW5nO1xuICBwdWJsaWNLZXk6IHN0cmluZztcbn1cblxuLyoqXG4gKiBTYWZldHkgTnVtYmVyIHZlcmlmaWNhdGlvbiBtb2RlbCAoU2lnbmFsLXN0eWxlKS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTYWZldHlOdW1iZXIge1xuICAvKiogUmF3IDYwLWNoYXJhY3RlciBoZXhhZGVjaW1hbCBkaWdlc3QgKi9cbiAgcmF3OiBzdHJpbmc7XG4gIC8qKiBTdGFuZGFyZGl6ZWQgZm9ybWF0dGVkIGRpc3BsYXkgaW4gNiBibG9ja3Mgb2YgNSBkZWNpbWFsIGRpZ2l0cyAqL1xuICBmb3JtYXR0ZWQ6IHN0cmluZztcbiAgLyoqIEZpbmdlcnByaW50IGNvbXBvbmVudCBmb3IgdGhlIGxvY2FsIHVzZXIgKi9cbiAgbG9jYWxGaW5nZXJwcmludDogc3RyaW5nO1xuICAvKiogRmluZ2VycHJpbnQgY29tcG9uZW50IGZvciB0aGUgcmVtb3RlIHVzZXIgKi9cbiAgcmVtb3RlRmluZ2VycHJpbnQ6IHN0cmluZztcbn1cblxuLyoqXG4gKiBDcnlwdG9ncmFwaHkgcHJvdmlkZXIgYWJzdHJhY3Rpb24gaW50ZXJmYWNlIChSU0EtMjA0OCBPQUVQKS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBLb2ppbnhDcnlwdG9Qcm92aWRlciB7XG4gIC8qKiBSZXR1cm5zIHRoZSBiYXNlNjQtZW5jb2RlZCBSU0EgcHVibGljIGtleSAqL1xuICBnZXRQdWJsaWNLZXkoKTogUHJvbWlzZTxzdHJpbmc+O1xuICAvKiogQXN5bW1ldHJpY2FsbHkgZW5jcnlwdHMgcGxhaW50ZXh0IHVzaW5nIHRhcmdldCBiYXNlNjQgUlNBIHB1YmxpYyBrZXkgKi9cbiAgZW5jcnlwdChwdWJsaWNLZXlCYXNlNjQ6IHN0cmluZywgcGxhaW50ZXh0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz47XG4gIC8qKiBBc3ltbWV0cmljYWxseSBkZWNyeXB0cyBjaXBoZXJ0ZXh0IHVzaW5nIGxvY2FsIHByaXZhdGUga2V5ICovXG4gIGRlY3J5cHQoY2lwaGVydGV4dEJhc2U2NDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+O1xufVxuXG4vKipcbiAqIENsaWVudC1hZ25vc3RpYyBmZXRjaCBvcHRpb25zLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEtvamlueEZldGNoT3B0aW9ucyB7XG4gIG1ldGhvZD86IHN0cmluZztcbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG4gIGJvZHk/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQ2xpZW50LWFnbm9zdGljIGZldGNoIHJlc3BvbnNlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEtvamlueEZldGNoUmVzcG9uc2U8VCA9IGFueT4ge1xuICBzdGF0dXM6IG51bWJlcjtcbiAgZGF0YTogVDtcbiAgaGVhZGVycz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG59XG5cbmV4cG9ydCB0eXBlIEtvamlueEZldGNoRnVuY3Rpb24gPSA8VCA9IGFueT4oXG4gIHVybDogc3RyaW5nLFxuICBvcHRpb25zPzogS29qaW54RmV0Y2hPcHRpb25zXG4pID0+IFByb21pc2U8S29qaW54RmV0Y2hSZXNwb25zZTxUPj47XG5cbi8qKlxuICogTG9jYWwgc3RvcmFnZSBpbnRlcmZhY2UgZm9yIHNlc3Npb24ga2V5IGNhY2hpbmcuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgS29qaW54U3RvcmFnZVByb3ZpZGVyIHtcbiAgZ2V0SXRlbShrZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD47XG4gIHNldEl0ZW0oa2V5OiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+O1xuICByZW1vdmVJdGVtKGtleTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPjtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Injectable, inject } from '@angular/core';
|
|
2
|
+
import { KOJINX_CRYPTO_PROVIDER } from '../tokens';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/**
|
|
5
|
+
* Pure End-to-End Encryption cryptographic service.
|
|
6
|
+
* Handles AES-256-GCM message encryption/decryption and RSA key wrapping/unwrapping.
|
|
7
|
+
*/
|
|
8
|
+
export class E2EChatCryptoService {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.cryptoProvider = inject(KOJINX_CRYPTO_PROVIDER, {
|
|
11
|
+
optional: true
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Generates a new cryptographically secure 256-bit AES-GCM session key.
|
|
16
|
+
*/
|
|
17
|
+
async generateAesKey() {
|
|
18
|
+
return crypto.subtle.generateKey({
|
|
19
|
+
name: 'AES-GCM',
|
|
20
|
+
length: 256
|
|
21
|
+
}, true, // extractable for RSA wrapping & secure export
|
|
22
|
+
['encrypt', 'decrypt']);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Encrypts plaintext string using AES-256-GCM with a fresh 12-byte (96-bit) nonce.
|
|
26
|
+
*
|
|
27
|
+
* @param sessionKey In-memory active session key
|
|
28
|
+
* @param plaintext Plaintext message content
|
|
29
|
+
*/
|
|
30
|
+
async encryptMessage(sessionKey, plaintext) {
|
|
31
|
+
if (!sessionKey || !sessionKey.rawKey) {
|
|
32
|
+
throw new Error('Invalid session key provided for encryption.');
|
|
33
|
+
}
|
|
34
|
+
// Standard 12-byte initialization vector for AES-GCM
|
|
35
|
+
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
36
|
+
const encoder = new TextEncoder();
|
|
37
|
+
const encodedPlaintext = encoder.encode(plaintext);
|
|
38
|
+
const ciphertextBuffer = await crypto.subtle.encrypt({
|
|
39
|
+
name: 'AES-GCM',
|
|
40
|
+
iv: nonce
|
|
41
|
+
}, sessionKey.rawKey, encodedPlaintext);
|
|
42
|
+
return {
|
|
43
|
+
ciphertext: this.arrayBufferToBase64(ciphertextBuffer),
|
|
44
|
+
nonce: this.arrayBufferToBase64(nonce.buffer),
|
|
45
|
+
sessionKeyId: sessionKey.id,
|
|
46
|
+
generation: sessionKey.generation
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Decrypts an EncryptedMessagePayload using AES-256-GCM.
|
|
51
|
+
*
|
|
52
|
+
* @param sessionKey In-memory session key corresponding to payload.sessionKeyId
|
|
53
|
+
* @param payload Encrypted payload containing ciphertext and nonce
|
|
54
|
+
*/
|
|
55
|
+
async decryptMessage(sessionKey, payload) {
|
|
56
|
+
if (!sessionKey || !sessionKey.rawKey) {
|
|
57
|
+
throw new Error('Invalid session key provided for decryption.');
|
|
58
|
+
}
|
|
59
|
+
const ciphertext = this.base64ToArrayBuffer(payload.ciphertext);
|
|
60
|
+
const nonce = this.base64ToArrayBuffer(payload.nonce);
|
|
61
|
+
const decryptedBuffer = await crypto.subtle.decrypt({
|
|
62
|
+
name: 'AES-GCM',
|
|
63
|
+
iv: new Uint8Array(nonce)
|
|
64
|
+
}, sessionKey.rawKey, ciphertext);
|
|
65
|
+
const decoder = new TextDecoder();
|
|
66
|
+
return decoder.decode(decryptedBuffer);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Exports an AES-GCM key and wraps (encrypts) it with a recipient's RSA public key.
|
|
70
|
+
*
|
|
71
|
+
* @param aesKey AES CryptoKey to wrap
|
|
72
|
+
* @param recipientPublicKey Base64-encoded recipient RSA public key
|
|
73
|
+
*/
|
|
74
|
+
async wrapSessionKey(aesKey, recipientPublicKey) {
|
|
75
|
+
if (!this.cryptoProvider) {
|
|
76
|
+
throw new Error('KOJINX_CRYPTO_PROVIDER is not provided. Cannot wrap session keys.');
|
|
77
|
+
}
|
|
78
|
+
const rawKeyBytes = await crypto.subtle.exportKey('raw', aesKey);
|
|
79
|
+
const rawKeyBase64 = this.arrayBufferToBase64(rawKeyBytes);
|
|
80
|
+
// Asymmetrically encrypt using host RSA provider
|
|
81
|
+
return this.cryptoProvider.encrypt(recipientPublicKey, rawKeyBase64);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Unwraps (decrypts) an RSA-encrypted AES raw key and imports it back into a W3C CryptoKey.
|
|
85
|
+
*
|
|
86
|
+
* @param encryptedAesKeyBase64 RSA-encrypted AES raw key in base64 format
|
|
87
|
+
*/
|
|
88
|
+
async unwrapSessionKey(encryptedAesKeyBase64) {
|
|
89
|
+
if (!this.cryptoProvider) {
|
|
90
|
+
throw new Error('KOJINX_CRYPTO_PROVIDER is not provided. Cannot unwrap session keys.');
|
|
91
|
+
}
|
|
92
|
+
// Asymmetrically decrypt using local private key
|
|
93
|
+
const rawKeyBase64 = await this.cryptoProvider.decrypt(encryptedAesKeyBase64);
|
|
94
|
+
const rawKeyBuffer = this.base64ToArrayBuffer(rawKeyBase64);
|
|
95
|
+
return crypto.subtle.importKey('raw', rawKeyBuffer, {
|
|
96
|
+
name: 'AES-GCM',
|
|
97
|
+
length: 256
|
|
98
|
+
}, true, ['encrypt', 'decrypt']);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Exports a CryptoKey to base64 raw bytes.
|
|
102
|
+
*/
|
|
103
|
+
async exportRawKeyBase64(key) {
|
|
104
|
+
const raw = await crypto.subtle.exportKey('raw', key);
|
|
105
|
+
return this.arrayBufferToBase64(raw);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Imports a base64 raw key string into a CryptoKey.
|
|
109
|
+
*/
|
|
110
|
+
async importRawKeyBase64(base64) {
|
|
111
|
+
const buffer = this.base64ToArrayBuffer(base64);
|
|
112
|
+
return crypto.subtle.importKey('raw', buffer, {
|
|
113
|
+
name: 'AES-GCM',
|
|
114
|
+
length: 256
|
|
115
|
+
}, true, ['encrypt', 'decrypt']);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Encodes ArrayBuffer to Base64 string.
|
|
119
|
+
*/
|
|
120
|
+
arrayBufferToBase64(buffer) {
|
|
121
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
122
|
+
let binary = '';
|
|
123
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
124
|
+
binary += String.fromCharCode(bytes[i]);
|
|
125
|
+
}
|
|
126
|
+
return btoa(binary);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Decodes Base64 string to ArrayBuffer.
|
|
130
|
+
*/
|
|
131
|
+
base64ToArrayBuffer(base64) {
|
|
132
|
+
const binary = atob(base64.trim());
|
|
133
|
+
const bytes = new Uint8Array(binary.length);
|
|
134
|
+
for (let i = 0; i < binary.length; i++) {
|
|
135
|
+
bytes[i] = binary.charCodeAt(i);
|
|
136
|
+
}
|
|
137
|
+
return bytes.buffer;
|
|
138
|
+
}
|
|
139
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: E2EChatCryptoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
140
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: E2EChatCryptoService, providedIn: 'root' }); }
|
|
141
|
+
}
|
|
142
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: E2EChatCryptoService, decorators: [{
|
|
143
|
+
type: Injectable,
|
|
144
|
+
args: [{
|
|
145
|
+
providedIn: 'root'
|
|
146
|
+
}]
|
|
147
|
+
}] });
|
|
148
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZTJlLWNoYXQtY3J5cHRvLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9rb2ppbngvY29sbGFiLWNyeXB0by9zcmMvbGliL3NlcnZpY2VzL2UyZS1jaGF0LWNyeXB0by5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBTW5ELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLFdBQVcsQ0FBQzs7QUFFbkQ7OztHQUdHO0FBSUgsTUFBTSxPQUFPLG9CQUFvQjtJQUhqQztRQUlVLG1CQUFjLEdBQUcsTUFBTSxDQUF1QixzQkFBc0IsRUFBRTtZQUM1RSxRQUFRLEVBQUUsSUFBSTtTQUNmLENBQUMsQ0FBQztLQXVMSjtJQXJMQzs7T0FFRztJQUNILEtBQUssQ0FBQyxjQUFjO1FBQ2xCLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQzlCO1lBQ0UsSUFBSSxFQUFFLFNBQVM7WUFDZixNQUFNLEVBQUUsR0FBRztTQUNaLEVBQ0QsSUFBSSxFQUFFLCtDQUErQztRQUNyRCxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FDdkIsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxjQUFjLENBQ2xCLFVBQWtDLEVBQ2xDLFNBQWlCO1FBRWpCLElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDdEMsTUFBTSxJQUFJLEtBQUssQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ2xFLENBQUM7UUFFRCxxREFBcUQ7UUFDckQsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLGVBQWUsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3pELE1BQU0sT0FBTyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7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QUFNLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUNuQyxNQUFNLEtBQUssR0FBRyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDNUMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUN2QyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsQyxDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQ3RCLENBQUM7K0dBekxVLG9CQUFvQjttSEFBcEIsb0JBQW9CLGNBRm5CLE1BQU07OzRGQUVQLG9CQUFvQjtrQkFIaEMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIENvbnZlcnNhdGlvblNlc3Npb25LZXksXG4gIEVuY3J5cHRlZE1lc3NhZ2VQYXlsb2FkLFxuICBLb2ppbnhDcnlwdG9Qcm92aWRlclxufSBmcm9tICcuLi9tb2RlbHMvY3J5cHRvLm1vZGVscyc7XG5pbXBvcnQgeyBLT0pJTlhfQ1JZUFRPX1BST1ZJREVSIH0gZnJvbSAnLi4vdG9rZW5zJztcblxuLyoqXG4gKiBQdXJlIEVuZC10by1FbmQgRW5jcnlwdGlvbiBjcnlwdG9ncmFwaGljIHNlcnZpY2UuXG4gKiBIYW5kbGVzIEFFUy0yNTYtR0NNIG1lc3NhZ2UgZW5jcnlwdGlvbi9kZWNyeXB0aW9uIGFuZCBSU0Ega2V5IHdyYXBwaW5nL3Vud3JhcHBpbmcuXG4gKi9cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIEUyRUNoYXRDcnlwdG9TZXJ2aWNlIHtcbiAgcHJpdmF0ZSBjcnlwdG9Qcm92aWRlciA9IGluamVjdDxLb2ppbnhDcnlwdG9Qcm92aWRlcj4oS09KSU5YX0NSWVBUT19QUk9WSURFUiwge1xuICAgIG9wdGlvbmFsOiB0cnVlXG4gIH0pO1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYSBuZXcgY3J5cHRvZ3JhcGhpY2FsbHkgc2VjdXJlIDI1Ni1iaXQgQUVTLUdDTSBzZXNzaW9uIGtleS5cbiAgICovXG4gIGFzeW5jIGdlbmVyYXRlQWVzS2V5KCk6IFByb21pc2U8Q3J5cHRvS2V5PiB7XG4gICAgcmV0dXJuIGNyeXB0by5zdWJ0bGUuZ2VuZXJhdGVLZXkoXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdBRVMtR0NNJyxcbiAgICAgICAgbGVuZ3RoOiAyNTZcbiAgICAgIH0sXG4gICAgICB0cnVlLCAvLyBleHRyYWN0YWJsZSBmb3IgUlNBIHdyYXBwaW5nICYgc2VjdXJlIGV4cG9ydFxuICAgICAgWydlbmNyeXB0JywgJ2RlY3J5cHQnXVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogRW5jcnlwdHMgcGxhaW50ZXh0IHN0cmluZyB1c2luZyBBRVMtMjU2LUdDTSB3aXRoIGEgZnJlc2ggMTItYnl0ZSAoOTYtYml0KSBub25jZS5cbiAgICpcbiAgICogQHBhcmFtIHNlc3Npb25LZXkgSW4tbWVtb3J5IGFjdGl2ZSBzZXNzaW9uIGtleVxuICAgKiBAcGFyYW0gcGxhaW50ZXh0IFBsYWludGV4dCBtZXNzYWdlIGNvbnRlbnRcbiAgICovXG4gIGFzeW5jIGVuY3J5cHRNZXNzYWdlKFxuICAgIHNlc3Npb25LZXk6IENvbnZlcnNhdGlvblNlc3Npb25LZXksXG4gICAgcGxhaW50ZXh0OiBzdHJpbmdcbiAgKTogUHJvbWlzZTxFbmNyeXB0ZWRNZXNzYWdlUGF5bG9hZD4ge1xuICAgIGlmICghc2Vzc2lvbktleSB8fCAhc2Vzc2lvbktleS5yYXdLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzZXNzaW9uIGtleSBwcm92aWRlZCBmb3IgZW5jcnlwdGlvbi4nKTtcbiAgICB9XG5cbiAgICAvLyBTdGFuZGFyZCAxMi1ieXRlIGluaXRpYWxpemF0aW9uIHZlY3RvciBmb3IgQUVTLUdDTVxuICAgIGNvbnN0IG5vbmNlID0gY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhuZXcgVWludDhBcnJheSgxMikpO1xuICAgIGNvbnN0IGVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgICBjb25zdCBlbmNvZGVkUGxhaW50ZXh0ID0gZW5jb2Rlci5lbmNvZGUocGxhaW50ZXh0KTtcblxuICAgIGNvbnN0IGNpcGhlcnRleHRCdWZmZXIgPSBhd2FpdCBjcnlwdG8uc3VidGxlLmVuY3J5cHQoXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdBRVMtR0NNJyxcbiAgICAgICAgaXY6IG5vbmNlXG4gICAgICB9LFxuICAgICAgc2Vzc2lvbktleS5yYXdLZXksXG4gICAgICBlbmNvZGVkUGxhaW50ZXh0XG4gICAgKTtcblxuICAgIHJldHVybiB7XG4gICAgICBjaXBoZXJ0ZXh0OiB0aGlzLmFycmF5QnVmZmVyVG9CYXNlNjQoY2lwaGVydGV4dEJ1ZmZlciksXG4gICAgICBub25jZTogdGhpcy5hcnJheUJ1ZmZlclRvQmFzZTY0KG5vbmNlLmJ1ZmZlciksXG4gICAgICBzZXNzaW9uS2V5SWQ6IHNlc3Npb25LZXkuaWQsXG4gICAgICBnZW5lcmF0aW9uOiBzZXNzaW9uS2V5LmdlbmVyYXRpb25cbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIERlY3J5cHRzIGFuIEVuY3J5cHRlZE1lc3NhZ2VQYXlsb2FkIHVzaW5nIEFFUy0yNTYtR0NNLlxuICAgKlxuICAgKiBAcGFyYW0gc2Vzc2lvbktleSBJbi1tZW1vcnkgc2Vzc2lvbiBrZXkgY29ycmVzcG9uZGluZyB0byBwYXlsb2FkLnNlc3Npb25LZXlJZFxuICAgKiBAcGFyYW0gcGF5bG9hZCBFbmNyeXB0ZWQgcGF5bG9hZCBjb250YWluaW5nIGNpcGhlcnRleHQgYW5kIG5vbmNlXG4gICAqL1xuICBhc3luYyBkZWNyeXB0TWVzc2FnZShcbiAgICBzZXNzaW9uS2V5OiBDb252ZXJzYXRpb25TZXNzaW9uS2V5LFxuICAgIHBheWxvYWQ6IEVuY3J5cHRlZE1lc3NhZ2VQYXlsb2FkXG4gICk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKCFzZXNzaW9uS2V5IHx8ICFzZXNzaW9uS2V5LnJhd0tleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNlc3Npb24ga2V5IHByb3ZpZGVkIGZvciBkZWNyeXB0aW9uLicpO1xuICAgIH1cblxuICAgIGNvbnN0IGNpcGhlcnRleHQgPSB0aGlzLmJhc2U2NFRvQXJyYXlCdWZmZXIocGF5bG9hZC5jaXBoZXJ0ZXh0KTtcbiAgICBjb25zdCBub25jZSA9IHRoaXMuYmFzZTY0VG9BcnJheUJ1ZmZlcihwYXlsb2FkLm5vbmNlKTtcblxuICAgIGNvbnN0IGRlY3J5cHRlZEJ1ZmZlciA9IGF3YWl0IGNyeXB0by5zdWJ0bGUuZGVjcnlwdChcbiAgICAgIHtcbiAgICAgICAgbmFtZTogJ0FFUy1HQ00nLFxuICAgICAgICBpdjogbmV3IFVpbnQ4QXJyYXkobm9uY2UpXG4gICAgICB9LFxuICAgICAgc2Vzc2lvbktleS5yYXdLZXksXG4gICAgICBjaXBoZXJ0ZXh0XG4gICAgKTtcblxuICAgIGNvbnN0IGRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoKTtcbiAgICByZXR1cm4gZGVjb2Rlci5kZWNvZGUoZGVjcnlwdGVkQnVmZmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBvcnRzIGFuIEFFUy1HQ00ga2V5IGFuZCB3cmFwcyAoZW5jcnlwdHMpIGl0IHdpdGggYSByZWNpcGllbnQncyBSU0EgcHVibGljIGtleS5cbiAgICpcbiAgICogQHBhcmFtIGFlc0tleSBBRVMgQ3J5cHRvS2V5IHRvIHdyYXBcbiAgICogQHBhcmFtIHJlY2lwaWVudFB1YmxpY0tleSBCYXNlNjQtZW5jb2RlZCByZWNpcGllbnQgUlNBIHB1YmxpYyBrZXlcbiAgICovXG4gIGFzeW5jIHdyYXBTZXNzaW9uS2V5KFxuICAgIGFlc0tleTogQ3J5cHRvS2V5LFxuICAgIHJlY2lwaWVudFB1YmxpY0tleTogc3RyaW5nXG4gICk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgaWYgKCF0aGlzLmNyeXB0b1Byb3ZpZGVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdLT0pJTlhfQ1JZUFRPX1BST1ZJREVSIGlzIG5vdCBwcm92aWRlZC4gQ2Fubm90IHdyYXAgc2Vzc2lvbiBrZXlzLidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgY29uc3QgcmF3S2V5Qnl0ZXMgPSBhd2FpdCBjcnlwdG8uc3VidGxlLmV4cG9ydEtleSgncmF3JywgYWVzS2V5KTtcbiAgICBjb25zdCByYXdLZXlCYXNlNjQgPSB0aGlzLmFycmF5QnVmZmVyVG9CYXNlNjQocmF3S2V5Qnl0ZXMpO1xuXG4gICAgLy8gQXN5bW1ldHJpY2FsbHkgZW5jcnlwdCB1c2luZyBob3N0IFJTQSBwcm92aWRlclxuICAgIHJldHVybiB0aGlzLmNyeXB0b1Byb3ZpZGVyLmVuY3J5cHQocmVjaXBpZW50UHVibGljS2V5LCByYXdLZXlCYXNlNjQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVud3JhcHMgKGRlY3J5cHRzKSBhbiBSU0EtZW5jcnlwdGVkIEFFUyByYXcga2V5IGFuZCBpbXBvcnRzIGl0IGJhY2sgaW50byBhIFczQyBDcnlwdG9LZXkuXG4gICAqXG4gICAqIEBwYXJhbSBlbmNyeXB0ZWRBZXNLZXlCYXNlNjQgUlNBLWVuY3J5cHRlZCBBRVMgcmF3IGtleSBpbiBiYXNlNjQgZm9ybWF0XG4gICAqL1xuICBhc3luYyB1bndyYXBTZXNzaW9uS2V5KGVuY3J5cHRlZEFlc0tleUJhc2U2NDogc3RyaW5nKTogUHJvbWlzZTxDcnlwdG9LZXk+IHtcbiAgICBpZiAoIXRoaXMuY3J5cHRvUHJvdmlkZXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ0tPSklOWF9DUllQVE9fUFJPVklERVIgaXMgbm90IHByb3ZpZGVkLiBDYW5ub3QgdW53cmFwIHNlc3Npb24ga2V5cy4nXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEFzeW1tZXRyaWNhbGx5IGRlY3J5cHQgdXNpbmcgbG9jYWwgcHJpdmF0ZSBrZXlcbiAgICBjb25zdCByYXdLZXlCYXNlNjQgPSBhd2FpdCB0aGlzLmNyeXB0b1Byb3ZpZGVyLmRlY3J5cHQoXG4gICAgICBlbmNyeXB0ZWRBZXNLZXlCYXNlNjRcbiAgICApO1xuICAgIGNvbnN0IHJhd0tleUJ1ZmZlciA9IHRoaXMuYmFzZTY0VG9BcnJheUJ1ZmZlcihyYXdLZXlCYXNlNjQpO1xuXG4gICAgcmV0dXJuIGNyeXB0by5zdWJ0bGUuaW1wb3J0S2V5KFxuICAgICAgJ3JhdycsXG4gICAgICByYXdLZXlCdWZmZXIsXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdBRVMtR0NNJyxcbiAgICAgICAgbGVuZ3RoOiAyNTZcbiAgICAgIH0sXG4gICAgICB0cnVlLFxuICAgICAgWydlbmNyeXB0JywgJ2RlY3J5cHQnXVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogRXhwb3J0cyBhIENyeXB0b0tleSB0byBiYXNlNjQgcmF3IGJ5dGVzLlxuICAgKi9cbiAgYXN5bmMgZXhwb3J0UmF3S2V5QmFzZTY0KGtleTogQ3J5cHRvS2V5KTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCByYXcgPSBhd2FpdCBjcnlwdG8uc3VidGxlLmV4cG9ydEtleSgncmF3Jywga2V5KTtcbiAgICByZXR1cm4gdGhpcy5hcnJheUJ1ZmZlclRvQmFzZTY0KHJhdyk7XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0cyBhIGJhc2U2NCByYXcga2V5IHN0cmluZyBpbnRvIGEgQ3J5cHRvS2V5LlxuICAgKi9cbiAgYXN5bmMgaW1wb3J0UmF3S2V5QmFzZTY0KGJhc2U2NDogc3RyaW5nKTogUHJvbWlzZTxDcnlwdG9LZXk+IHtcbiAgICBjb25zdCBidWZmZXIgPSB0aGlzLmJhc2U2NFRvQXJyYXlCdWZmZXIoYmFzZTY0KTtcbiAgICByZXR1cm4gY3J5cHRvLnN1YnRsZS5pbXBvcnRLZXkoXG4gICAgICAncmF3JyxcbiAgICAgIGJ1ZmZlcixcbiAgICAgIHtcbiAgICAgICAgbmFtZTogJ0FFUy1HQ00nLFxuICAgICAgICBsZW5ndGg6IDI1NlxuICAgICAgfSxcbiAgICAgIHRydWUsXG4gICAgICBbJ2VuY3J5cHQnLCAnZGVjcnlwdCddXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmNvZGVzIEFycmF5QnVmZmVyIHRvIEJhc2U2NCBzdHJpbmcuXG4gICAqL1xuICBhcnJheUJ1ZmZlclRvQmFzZTY0KGJ1ZmZlcjogQXJyYXlCdWZmZXIgfCBVaW50OEFycmF5KTogc3RyaW5nIHtcbiAgICBjb25zdCBieXRlcyA9IGJ1ZmZlciBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgPyBidWZmZXIgOiBuZXcgVWludDhBcnJheShidWZmZXIpO1xuICAgIGxldCBiaW5hcnkgPSAnJztcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGJ5dGVzLmJ5dGVMZW5ndGg7IGkrKykge1xuICAgICAgYmluYXJ5ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZXNbaV0pO1xuICAgIH1cbiAgICByZXR1cm4gYnRvYShiaW5hcnkpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY29kZXMgQmFzZTY0IHN0cmluZyB0byBBcnJheUJ1ZmZlci5cbiAgICovXG4gIGJhc2U2NFRvQXJyYXlCdWZmZXIoYmFzZTY0OiBzdHJpbmcpOiBBcnJheUJ1ZmZlciB7XG4gICAgY29uc3QgYmluYXJ5ID0gYXRvYihiYXNlNjQudHJpbSgpKTtcbiAgICBjb25zdCBieXRlcyA9IG5ldyBVaW50OEFycmF5KGJpbmFyeS5sZW5ndGgpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgYmluYXJ5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBieXRlc1tpXSA9IGJpbmFyeS5jaGFyQ29kZUF0KGkpO1xuICAgIH1cbiAgICByZXR1cm4gYnl0ZXMuYnVmZmVyO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { Injectable, inject } from '@angular/core';
|
|
2
|
+
import { KOJINX_API_BASE_URL, KOJINX_AUTH_TOKEN, KOJINX_CRYPTO_STORAGE, KOJINX_HTTP_FETCH } from '../tokens';
|
|
3
|
+
import { E2EChatCryptoService } from './e2e-chat-crypto.service';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/** 30 days in milliseconds for maximum session key lifetime */
|
|
6
|
+
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
|
|
7
|
+
/**
|
|
8
|
+
* Manages the lifecycle, caching, negotiation, and rotation of conversation session keys.
|
|
9
|
+
*/
|
|
10
|
+
export class SessionKeyManagerService {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.cryptoService = inject(E2EChatCryptoService);
|
|
13
|
+
this.httpFetch = inject(KOJINX_HTTP_FETCH, {
|
|
14
|
+
optional: true
|
|
15
|
+
});
|
|
16
|
+
this.getApiUrl = inject(KOJINX_API_BASE_URL, {
|
|
17
|
+
optional: true
|
|
18
|
+
});
|
|
19
|
+
this.getAuthToken = inject(KOJINX_AUTH_TOKEN, { optional: true });
|
|
20
|
+
this.storage = inject(KOJINX_CRYPTO_STORAGE, {
|
|
21
|
+
optional: true
|
|
22
|
+
});
|
|
23
|
+
/** Fast in-memory cache mapped by conversationId */
|
|
24
|
+
this.activeKeysByConversation = new Map();
|
|
25
|
+
/** Fast in-memory cache mapped by sessionKeyId (for historic messages) */
|
|
26
|
+
this.keysById = new Map();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Retrieves or creates an active session key for a 1:1 Direct Message conversation.
|
|
30
|
+
*
|
|
31
|
+
* @param localUserId Current user's ID
|
|
32
|
+
* @param remoteUserId Remote contact's ID
|
|
33
|
+
* @param remotePublicKey Base64 RSA public key of remote contact
|
|
34
|
+
* @param localPublicKey Base64 RSA public key of local user
|
|
35
|
+
*/
|
|
36
|
+
async getOrCreateDmSessionKey(localUserId, remoteUserId, remotePublicKey, localPublicKey) {
|
|
37
|
+
const conversationId = this.buildDmConversationId(localUserId, remoteUserId);
|
|
38
|
+
// 1. Check in-memory cache
|
|
39
|
+
const cached = this.activeKeysByConversation.get(conversationId);
|
|
40
|
+
if (cached && !this.isKeyExpired(cached)) {
|
|
41
|
+
return cached;
|
|
42
|
+
}
|
|
43
|
+
// 2. Attempt fetching from server if HTTP fetch is provided
|
|
44
|
+
if (this.httpFetch && this.getApiUrl && this.getAuthToken) {
|
|
45
|
+
const serverKey = await this.fetchSessionKeyFromServer(conversationId, 'dm');
|
|
46
|
+
if (serverKey) {
|
|
47
|
+
this.cacheKey(serverKey);
|
|
48
|
+
return serverKey;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 3. Create fresh session key and distribute
|
|
52
|
+
return this.createAndDistributeSessionKey({
|
|
53
|
+
type: 'dm',
|
|
54
|
+
conversationId,
|
|
55
|
+
generation: cached ? cached.generation + 1 : 1,
|
|
56
|
+
members: [
|
|
57
|
+
{ userId: localUserId, publicKey: localPublicKey },
|
|
58
|
+
{ userId: remoteUserId, publicKey: remotePublicKey }
|
|
59
|
+
]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Retrieves or creates an active session key for a Native Channel or Group.
|
|
64
|
+
*
|
|
65
|
+
* @param channelId Unique channel ID
|
|
66
|
+
* @param members List of all workspace/channel members with their public keys
|
|
67
|
+
*/
|
|
68
|
+
async getOrCreateChannelSessionKey(channelId, members) {
|
|
69
|
+
const cached = this.activeKeysByConversation.get(channelId);
|
|
70
|
+
if (cached && !this.isKeyExpired(cached)) {
|
|
71
|
+
return cached;
|
|
72
|
+
}
|
|
73
|
+
if (this.httpFetch && this.getApiUrl && this.getAuthToken) {
|
|
74
|
+
const serverKey = await this.fetchSessionKeyFromServer(channelId, 'channel');
|
|
75
|
+
if (serverKey) {
|
|
76
|
+
this.cacheKey(serverKey);
|
|
77
|
+
return serverKey;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return this.createAndDistributeSessionKey({
|
|
81
|
+
type: 'channel',
|
|
82
|
+
conversationId: channelId,
|
|
83
|
+
generation: cached ? cached.generation + 1 : 1,
|
|
84
|
+
members
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Retrieves a session key by its specific sessionKeyId (used for decrypting historic messages).
|
|
89
|
+
*/
|
|
90
|
+
async getSessionKeyById(sessionKeyId) {
|
|
91
|
+
const cached = this.keysById.get(sessionKeyId);
|
|
92
|
+
if (cached)
|
|
93
|
+
return cached;
|
|
94
|
+
// Check local storage
|
|
95
|
+
if (this.storage) {
|
|
96
|
+
const stored = await this.storage.getItem(`kojinx_sk_${sessionKeyId}`);
|
|
97
|
+
if (stored) {
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse(stored);
|
|
100
|
+
const rawKey = await this.cryptoService.importRawKeyBase64(parsed.rawKeyBase64);
|
|
101
|
+
const key = {
|
|
102
|
+
id: parsed.id,
|
|
103
|
+
type: parsed.type,
|
|
104
|
+
conversationId: parsed.conversationId,
|
|
105
|
+
rawKey,
|
|
106
|
+
generation: parsed.generation,
|
|
107
|
+
createdAt: parsed.createdAt
|
|
108
|
+
};
|
|
109
|
+
this.cacheKey(key);
|
|
110
|
+
return key;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// ignore corrupted local key
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Generates a new AES session key, wraps it for all members, and uploads to the server.
|
|
121
|
+
*/
|
|
122
|
+
async createAndDistributeSessionKey(params) {
|
|
123
|
+
const rawAesKey = await this.cryptoService.generateAesKey();
|
|
124
|
+
const sessionKeyId = this.generateUuid();
|
|
125
|
+
const memberPayloads = {};
|
|
126
|
+
for (const member of params.members) {
|
|
127
|
+
if (member.publicKey) {
|
|
128
|
+
memberPayloads[member.userId] =
|
|
129
|
+
await this.cryptoService.wrapSessionKey(rawAesKey, member.publicKey);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const sessionKey = {
|
|
133
|
+
id: sessionKeyId,
|
|
134
|
+
type: params.type,
|
|
135
|
+
conversationId: params.conversationId,
|
|
136
|
+
rawKey: rawAesKey,
|
|
137
|
+
generation: params.generation,
|
|
138
|
+
createdAt: Date.now()
|
|
139
|
+
};
|
|
140
|
+
// Store in memory
|
|
141
|
+
this.cacheKey(sessionKey);
|
|
142
|
+
await this.persistKeyLocally(sessionKey);
|
|
143
|
+
// Upload to server if online
|
|
144
|
+
if (this.httpFetch && this.getApiUrl && this.getAuthToken) {
|
|
145
|
+
const token = await this.getAuthToken();
|
|
146
|
+
const apiUrl = this.getApiUrl();
|
|
147
|
+
const payload = {
|
|
148
|
+
sessionKeyId,
|
|
149
|
+
conversationType: params.type,
|
|
150
|
+
conversationId: params.conversationId,
|
|
151
|
+
generation: params.generation,
|
|
152
|
+
memberPayloads
|
|
153
|
+
};
|
|
154
|
+
try {
|
|
155
|
+
await this.httpFetch(`${apiUrl}/api/e2e/session-keys`, {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
headers: {
|
|
158
|
+
Authorization: `Bearer ${token}`,
|
|
159
|
+
'Content-Type': 'application/json'
|
|
160
|
+
},
|
|
161
|
+
body: JSON.stringify(payload)
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
console.warn('[SessionKeyManager] Failed to sync session key to server:', err);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return sessionKey;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Helper to check if a key has exceeded the 30-day rotation threshold.
|
|
172
|
+
*/
|
|
173
|
+
isKeyExpired(key) {
|
|
174
|
+
return Date.now() - key.createdAt > THIRTY_DAYS_MS;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Builds a deterministic conversation identifier for 1:1 DMs (lexicographical sort).
|
|
178
|
+
*/
|
|
179
|
+
buildDmConversationId(userIdA, userIdB) {
|
|
180
|
+
return [userIdA, userIdB].sort().join('_');
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Caches a session key in memory.
|
|
184
|
+
*/
|
|
185
|
+
cacheKey(key) {
|
|
186
|
+
this.activeKeysByConversation.set(key.conversationId, key);
|
|
187
|
+
this.keysById.set(key.id, key);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Persists an unwrapped session key to local storage for fast startup.
|
|
191
|
+
*/
|
|
192
|
+
async persistKeyLocally(key) {
|
|
193
|
+
if (!this.storage)
|
|
194
|
+
return;
|
|
195
|
+
try {
|
|
196
|
+
const rawKeyBase64 = await this.cryptoService.exportRawKeyBase64(key.rawKey);
|
|
197
|
+
const data = JSON.stringify({
|
|
198
|
+
id: key.id,
|
|
199
|
+
type: key.type,
|
|
200
|
+
conversationId: key.conversationId,
|
|
201
|
+
rawKeyBase64,
|
|
202
|
+
generation: key.generation,
|
|
203
|
+
createdAt: key.createdAt
|
|
204
|
+
});
|
|
205
|
+
await this.storage.setItem(`kojinx_sk_${key.id}`, data);
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// ignore persistence error
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Fetches latest session key from server and unwraps it locally.
|
|
213
|
+
*/
|
|
214
|
+
async fetchSessionKeyFromServer(conversationId, type) {
|
|
215
|
+
if (!this.httpFetch || !this.getApiUrl || !this.getAuthToken)
|
|
216
|
+
return null;
|
|
217
|
+
try {
|
|
218
|
+
const token = await this.getAuthToken();
|
|
219
|
+
const apiUrl = this.getApiUrl();
|
|
220
|
+
const res = await this.httpFetch(`${apiUrl}/api/e2e/session-keys/${conversationId}`, {
|
|
221
|
+
method: 'GET',
|
|
222
|
+
headers: {
|
|
223
|
+
Authorization: `Bearer ${token}`
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
if (res.status === 200 && res.data?.encryptedKey) {
|
|
227
|
+
const rawKey = await this.cryptoService.unwrapSessionKey(res.data.encryptedKey);
|
|
228
|
+
return {
|
|
229
|
+
id: res.data.sessionKeyId,
|
|
230
|
+
type,
|
|
231
|
+
conversationId,
|
|
232
|
+
rawKey,
|
|
233
|
+
generation: res.data.generation || 1,
|
|
234
|
+
createdAt: res.data.createdAt
|
|
235
|
+
? new Date(res.data.createdAt).getTime()
|
|
236
|
+
: Date.now()
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
// Not found or network error
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Generates a random UUID (W3C standard or fallback).
|
|
247
|
+
*/
|
|
248
|
+
generateUuid() {
|
|
249
|
+
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
250
|
+
return crypto.randomUUID();
|
|
251
|
+
}
|
|
252
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
|
253
|
+
const r = (Math.random() * 16) | 0;
|
|
254
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
255
|
+
return v.toString(16);
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SessionKeyManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
259
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SessionKeyManagerService, providedIn: 'root' }); }
|
|
260
|
+
}
|
|
261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SessionKeyManagerService, decorators: [{
|
|
262
|
+
type: Injectable,
|
|
263
|
+
args: [{
|
|
264
|
+
providedIn: 'root'
|
|
265
|
+
}]
|
|
266
|
+
}] });
|
|
267
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbi1rZXktbWFuYWdlci5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva29qaW54L2NvbGxhYi1jcnlwdG8vc3JjL2xpYi9zZXJ2aWNlcy9zZXNzaW9uLWtleS1tYW5hZ2VyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFRbkQsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixpQkFBaUIsRUFDakIscUJBQXFCLEVBQ3JCLGlCQUFpQixFQUNsQixNQUFNLFdBQVcsQ0FBQztBQUNuQixPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQzs7QUFFakUsK0RBQStEO0FBQy9ELE1BQU0sY0FBYyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFFaEQ7O0dBRUc7QUFJSCxNQUFNLE9BQU8sd0JBQXdCO0lBSHJDO1FBSVUsa0JBQWEsR0FBRyxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUM3QyxjQUFTLEdBQUcsTUFBTSxDQUFzQixpQkFBaUIsRUFBRTtZQUNqRSxRQUFRLEVBQUUsSUFBSTtTQUNmLENBQUMsQ0FBQztRQUNLLGNBQVMsR0FBRyxNQUFNLENBQWUsbUJBQW1CLEVBQUU7WUFDNUQsUUFBUSxFQUFFLElBQUk7U0FDZixDQUFDLENBQUM7UUFDSyxpQkFBWSxHQUFHLE1BQU0sQ0FDM0IsaUJBQWlCLEVBQ2pCLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUNuQixDQUFDO1FBQ00sWUFBTyxHQUFHLE1BQU0sQ0FBd0IscUJBQXFCLEVBQUU7WUFDckUsUUFBUSxFQUFFLElBQUk7U0FDZixDQUFDLENBQUM7UUFFSCxvREFBb0Q7UUFDNUMsNkJBQXdCLEdBQUcsSUFBSSxHQUFHLEVBQWtDLENBQUM7UUFD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QixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7K0dBNVRVLHdCQUF3QjttSEFBeEIsd0JBQXdCLGNBRnZCLE1BQU07OzRGQUVQLHdCQUF3QjtrQkFIcEMsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIENvbnZlcnNhdGlvblNlc3Npb25LZXksXG4gIEtvamlueEZldGNoRnVuY3Rpb24sXG4gIEtvamlueFN0b3JhZ2VQcm92aWRlcixcbiAgTWVtYmVyUHVibGljS2V5LFxuICBTZXNzaW9uS2V5RXhjaGFuZ2VQYXlsb2FkXG59IGZyb20gJy4uL21vZGVscy9jcnlwdG8ubW9kZWxzJztcbmltcG9ydCB7XG4gIEtPSklOWF9BUElfQkFTRV9VUkwsXG4gIEtPSklOWF9BVVRIX1RPS0VOLFxuICBLT0pJTlhfQ1JZUFRPX1NUT1JBR0UsXG4gIEtPSklOWF9IVFRQX0ZFVENIXG59IGZyb20gJy4uL3Rva2Vucyc7XG5pbXBvcnQgeyBFMkVDaGF0Q3J5cHRvU2VydmljZSB9IGZyb20gJy4vZTJlLWNoYXQtY3J5cHRvLnNlcnZpY2UnO1xuXG4vKiogMzAgZGF5cyBpbiBtaWxsaXNlY29uZHMgZm9yIG1heGltdW0gc2Vzc2lvbiBrZXkgbGlmZXRpbWUgKi9cbmNvbnN0IFRISVJUWV9EQVlTX01TID0gMzAgKiAyNCAqIDYwICogNjAgKiAxMDAwO1xuXG4vKipcbiAqIE1hbmFnZXMgdGhlIGxpZmVjeWNsZSwgY2FjaGluZywgbmVnb3RpYXRpb24sIGFuZCByb3RhdGlvbiBvZiBjb252ZXJzYXRpb24gc2Vzc2lvbiBrZXlzLlxuICovXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBTZXNzaW9uS2V5TWFuYWdlclNlcnZpY2Uge1xuICBwcml2YXRlIGNyeXB0b1NlcnZpY2UgPSBpbmplY3QoRTJFQ2hhdENyeXB0b1NlcnZpY2UpO1xuICBwcml2YXRlIGh0dHBGZXRjaCA9IGluamVjdDxLb2ppbnhGZXRjaEZ1bmN0aW9uPihLT0pJTlhfSFRUUF9GRVRDSCwge1xuICAgIG9wdGlvbmFsOiB0cnVlXG4gIH0pO1xuICBwcml2YXRlIGdldEFwaVVybCA9IGluamVjdDwoKSA9PiBzdHJpbmc+KEtPSklOWF9BUElfQkFTRV9VUkwsIHtcbiAgICBvcHRpb25hbDogdHJ1ZVxuICB9KTtcbiAgcHJpdmF0ZSBnZXRBdXRoVG9rZW4gPSBpbmplY3Q8KCkgPT4gUHJvbWlzZTxzdHJpbmcgfCBudWxsPj4oXG4gICAgS09KSU5YX0FVVEhfVE9LRU4sXG4gICAgeyBvcHRpb25hbDogdHJ1ZSB9XG4gICk7XG4gIHByaXZhdGUgc3RvcmFnZSA9IGluamVjdDxLb2ppbnhTdG9yYWdlUHJvdmlkZXI+KEtPSklOWF9DUllQVE9fU1RPUkFHRSwge1xuICAgIG9wdGlvbmFsOiB0cnVlXG4gIH0pO1xuXG4gIC8qKiBGYXN0IGluLW1lbW9yeSBjYWNoZSBtYXBwZWQgYnkgY29udmVyc2F0aW9uSWQgKi9cbiAgcHJpdmF0ZSBhY3RpdmVLZXlzQnlDb252ZXJzYXRpb24gPSBuZXcgTWFwPHN0cmluZywgQ29udmVyc2F0aW9uU2Vzc2lvbktleT4oKTtcbiAgLyoqIEZhc3QgaW4tbWVtb3J5IGNhY2hlIG1hcHBlZCBieSBzZXNzaW9uS2V5SWQgKGZvciBoaXN0b3JpYyBtZXNzYWdlcykgKi9cbiAgcHJpdmF0ZSBrZXlzQnlJZCA9IG5ldyBNYXA8c3RyaW5nLCBDb252ZXJzYXRpb25TZXNzaW9uS2V5PigpO1xuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgb3IgY3JlYXRlcyBhbiBhY3RpdmUgc2Vzc2lvbiBrZXkgZm9yIGEgMToxIERpcmVjdCBNZXNzYWdlIGNvbnZlcnNhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIGxvY2FsVXNlcklkIEN1cnJlbnQgdXNlcidzIElEXG4gICAqIEBwYXJhbSByZW1vdGVVc2VySWQgUmVtb3RlIGNvbnRhY3QncyBJRFxuICAgKiBAcGFyYW0gcmVtb3RlUHVibGljS2V5IEJhc2U2NCBSU0EgcHVibGljIGtleSBvZiByZW1vdGUgY29udGFjdFxuICAgKiBAcGFyYW0gbG9jYWxQdWJsaWNLZXkgQmFzZTY0IFJTQSBwdWJsaWMga2V5IG9mIGxvY2FsIHVzZXJcbiAgICovXG4gIGFzeW5jIGdldE9yQ3JlYXRlRG1TZXNzaW9uS2V5KFxuICAgIGxvY2FsVXNlcklkOiBzdHJpbmcsXG4gICAgcmVtb3RlVXNlcklkOiBzdHJpbmcsXG4gICAgcmVtb3RlUHVibGljS2V5OiBzdHJpbmcsXG4gICAgbG9jYWxQdWJsaWNLZXk6IHN0cmluZ1xuICApOiBQcm9taXNlPENvbnZlcnNhdGlvblNlc3Npb25LZXk+IHtcbiAgICBjb25zdCBjb252ZXJzYXRpb25JZCA9IHRoaXMuYnVpbGREbUNvbnZlcnNhdGlvbklkKFxuICAgICAgbG9jYWxVc2VySWQsXG4gICAgICByZW1vdGVVc2VySWRcbiAgICApO1xuXG4gICAgLy8gMS4gQ2hlY2sgaW4tbWVtb3J5IGNhY2hlXG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5hY3RpdmVLZXlzQnlDb252ZXJzYXRpb24uZ2V0KGNvbnZlcnNhdGlvbklkKTtcbiAgICBpZiAoY2FjaGVkICYmICF0aGlzLmlzS2V5RXhwaXJlZChjYWNoZWQpKSB7XG4gICAgICByZXR1cm4gY2FjaGVkO1xuICAgIH1cblxuICAgIC8vIDIuIEF0dGVtcHQgZmV0Y2hpbmcgZnJvbSBzZXJ2ZXIgaWYgSFRUUCBmZXRjaCBpcyBwcm92aWRlZFxuICAgIGlmICh0aGlzLmh0dHBGZXRjaCAmJiB0aGlzLmdldEFwaVVybCAmJiB0aGlzLmdldEF1dGhUb2tlbikge1xuICAgICAgY29uc3Qgc2VydmVyS2V5ID0gYXdhaXQgdGhpcy5mZXRjaFNlc3Npb25LZXlGcm9tU2VydmVyKFxuICAgICAgICBjb252ZXJzYXRpb25JZCxcbiAgICAgICAgJ2RtJ1xuICAgICAgKTtcbiAgICAgIGlmIChzZXJ2ZXJLZXkpIHtcbiAgICAgICAgdGhpcy5jYWNoZUtleShzZXJ2ZXJLZXkpO1xuICAgICAgICByZXR1cm4gc2VydmVyS2V5O1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIDMuIENyZWF0ZSBmcmVzaCBzZXNzaW9uIGtleSBhbmQgZGlzdHJpYnV0ZVxuICAgIHJldHVybiB0aGlzLmNyZWF0ZUFuZERpc3RyaWJ1dGVTZXNzaW9uS2V5KHtcbiAgICAgIHR5cGU6ICdkbScsXG4gICAgICBjb252ZXJzYXRpb25JZCxcbiAgICAgIGdlbmVyYXRpb246IGNhY2hlZCA/IGNhY2hlZC5nZW5lcmF0aW9uICsgMSA6IDEsXG4gICAgICBtZW1iZXJzOiBbXG4gICAgICAgIHsgdXNlcklkOiBsb2NhbFVzZXJJZCwgcHVibGljS2V5OiBsb2NhbFB1YmxpY0tleSB9LFxuICAgICAgICB7IHVzZXJJZDogcmVtb3RlVXNlcklkLCBwdWJsaWNLZXk6IHJlbW90ZVB1YmxpY0tleSB9XG4gICAgICBdXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIG9yIGNyZWF0ZXMgYW4gYWN0aXZlIHNlc3Npb24ga2V5IGZvciBhIE5hdGl2ZSBDaGFubmVsIG9yIEdyb3VwLlxuICAgKlxuICAgKiBAcGFyYW0gY2hhbm5lbElkIFVuaXF1ZSBjaGFubmVsIElEXG4gICAqIEBwYXJhbSBtZW1iZXJzIExpc3Qgb2YgYWxsIHdvcmtzcGFjZS9jaGFubmVsIG1lbWJlcnMgd2l0aCB0aGVpciBwdWJsaWMga2V5c1xuICAgKi9cbiAgYXN5bmMgZ2V0T3JDcmVhdGVDaGFubmVsU2Vzc2lvbktleShcbiAgICBjaGFubmVsSWQ6IHN0cmluZyxcbiAgICBtZW1iZXJzOiBNZW1iZXJQdWJsaWNLZXlbXVxuICApOiBQcm9taXNlPENvbnZlcnNhdGlvblNlc3Npb25LZXk+IHtcbiAgICBjb25zdCBjYWNoZWQgPSB0aGlzLmFjdGl2ZUtleXNCeUNvbnZlcnNhdGlvbi5nZXQoY2hhbm5lbElkKTtcbiAgICBpZiAoY2FjaGVkICYmICF0aGlzLmlzS2V5RXhwaXJlZChjYWNoZWQpKSB7XG4gICAgICByZXR1cm4gY2FjaGVkO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmh0dHBGZXRjaCAmJiB0aGlzLmdldEFwaVVybCAmJiB0aGlzLmdldEF1dGhUb2tlbikge1xuICAgICAgY29uc3Qgc2VydmVyS2V5ID0gYXdhaXQgdGhpcy5mZXRjaFNlc3Npb25LZXlGcm9tU2VydmVyKFxuICAgICAgICBjaGFubmVsSWQsXG4gICAgICAgICdjaGFubmVsJ1xuICAgICAgKTtcbiAgICAgIGlmIChzZXJ2ZXJLZXkpIHtcbiAgICAgICAgdGhpcy5jYWNoZUtleShzZXJ2ZXJLZXkpO1xuICAgICAgICByZXR1cm4gc2VydmVyS2V5O1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmNyZWF0ZUFuZERpc3RyaWJ1dGVTZXNzaW9uS2V5KHtcbiAgICAgIHR5cGU6ICdjaGFubmVsJyxcbiAgICAgIGNvbnZlcnNhdGlvbklkOiBjaGFubmVsSWQsXG4gICAgICBnZW5lcmF0aW9uOiBjYWNoZWQgPyBjYWNoZWQuZ2VuZXJhdGlvbiArIDEgOiAxLFxuICAgICAgbWVtYmVyc1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBhIHNlc3Npb24ga2V5IGJ5IGl0cyBzcGVjaWZpYyBzZXNzaW9uS2V5SWQgKHVzZWQgZm9yIGRlY3J5cHRpbmcgaGlzdG9yaWMgbWVzc2FnZXMpLlxuICAgKi9cbiAgYXN5bmMgZ2V0U2Vzc2lvbktleUJ5SWQoXG4gICAgc2Vzc2lvbktleUlkOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxDb252ZXJzYXRpb25TZXNzaW9uS2V5IHwgbnVsbD4ge1xuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMua2V5c0J5SWQuZ2V0KHNlc3Npb25LZXlJZCk7XG4gICAgaWYgKGNhY2hlZCkgcmV0dXJuIGNhY2hlZDtcblxuICAgIC8vIENoZWNrIGxvY2FsIHN0b3JhZ2VcbiAgICBpZiAodGhpcy5zdG9yYWdlKSB7XG4gICAgICBjb25zdCBzdG9yZWQgPSBhd2FpdCB0aGlzLnN0b3JhZ2UuZ2V0SXRlbShcbiAgICAgICAgYGtvamlueF9za18ke3Nlc3Npb25LZXlJZH1gXG4gICAgICApO1xuICAgICAgaWYgKHN0b3JlZCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2Uoc3RvcmVkKTtcbiAgICAgICAgICBjb25zdCByYXdLZXkgPSBhd2FpdCB0aGlzLmNyeXB0b1NlcnZpY2UuaW1wb3J0UmF3S2V5QmFzZTY0KFxuICAgICAgICAgICAgcGFyc2VkLnJhd0tleUJhc2U2NFxuICAgICAgICAgICk7XG4gICAgICAgICAgY29uc3Qga2V5OiBDb252ZXJzYXRpb25TZXNzaW9uS2V5ID0ge1xuICAgICAgICAgICAgaWQ6IHBhcnNlZC5pZCxcbiAgICAgICAgICAgIHR5cGU6IHBhcnNlZC50eXBlLFxuICAgICAgICAgICAgY29udmVyc2F0aW9uSWQ6IHBhcnNlZC5jb252ZXJzYXRpb25JZCxcbiAgICAgICAgICAgIHJhd0tleSxcbiAgICAgICAgICAgIGdlbmVyYXRpb246IHBhcnNlZC5nZW5lcmF0aW9uLFxuICAgICAgICAgICAgY3JlYXRlZEF0OiBwYXJzZWQuY3JlYXRlZEF0XG4gICAgICAgICAgfTtcbiAgICAgICAgICB0aGlzLmNhY2hlS2V5KGtleSk7XG4gICAgICAgICAgcmV0dXJuIGtleTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgLy8gaWdub3JlIGNvcnJ1cHRlZCBsb2NhbCBrZXlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyBhIG5ldyBBRVMgc2Vzc2lvbiBrZXksIHdyYXBzIGl0IGZvciBhbGwgbWVtYmVycywgYW5kIHVwbG9hZHMgdG8gdGhlIHNlcnZlci5cbiAgICovXG4gIGFzeW5jIGNyZWF0ZUFuZERpc3RyaWJ1dGVTZXNzaW9uS2V5KHBhcmFtczoge1xuICAgIHR5cGU6ICdkbScgfCAnY2hhbm5lbCcgfCAnZ3JvdXAnO1xuICAgIGNvbnZlcnNhdGlvbklkOiBzdHJpbmc7XG4gICAgZ2VuZXJhdGlvbjogbnVtYmVyO1xuICAgIG1lbWJlcnM6IE1lbWJlclB1YmxpY0tleVtdO1xuICB9KTogUHJvbWlzZTxDb252ZXJzYXRpb25TZXNzaW9uS2V5PiB7XG4gICAgY29uc3QgcmF3QWVzS2V5ID0gYXdhaXQgdGhpcy5jcnlwdG9TZXJ2aWNlLmdlbmVyYXRlQWVzS2V5KCk7XG4gICAgY29uc3Qgc2Vzc2lvbktleUlkID0gdGhpcy5nZW5lcmF0ZVV1aWQoKTtcblxuICAgIGNvbnN0IG1lbWJlclBheWxvYWRzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gICAgZm9yIChjb25zdCBtZW1iZXIgb2YgcGFyYW1zLm1lbWJlcnMpIHtcbiAgICAgIGlmIChtZW1iZXIucHVibGljS2V5KSB7XG4gICAgICAgIG1lbWJlclBheWxvYWRzW21lbWJlci51c2VySWRdID1cbiAgICAgICAgICBhd2FpdCB0aGlzLmNyeXB0b1NlcnZpY2Uud3JhcFNlc3Npb25LZXkoXG4gICAgICAgICAgICByYXdBZXNLZXksXG4gICAgICAgICAgICBtZW1iZXIucHVibGljS2V5XG4gICAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBzZXNzaW9uS2V5OiBDb252ZXJzYXRpb25TZXNzaW9uS2V5ID0ge1xuICAgICAgaWQ6IHNlc3Npb25LZXlJZCxcbiAgICAgIHR5cGU6IHBhcmFtcy50eXBlLFxuICAgICAgY29udmVyc2F0aW9uSWQ6IHBhcmFtcy5jb252ZXJzYXRpb25JZCxcbiAgICAgIHJhd0tleTogcmF3QWVzS2V5LFxuICAgICAgZ2VuZXJhdGlvbjogcGFyYW1zLmdlbmVyYXRpb24sXG4gICAgICBjcmVhdGVkQXQ6IERhdGUubm93KClcbiAgICB9O1xuXG4gICAgLy8gU3RvcmUgaW4gbWVtb3J5XG4gICAgdGhpcy5jYWNoZUtleShzZXNzaW9uS2V5KTtcbiAgICBhd2FpdCB0aGlzLnBlcnNpc3RLZXlMb2NhbGx5KHNlc3Npb25LZXkpO1xuXG4gICAgLy8gVXBsb2FkIHRvIHNlcnZlciBpZiBvbmxpbmVcbiAgICBpZiAodGhpcy5odHRwRmV0Y2ggJiYgdGhpcy5nZXRBcGlVcmwgJiYgdGhpcy5nZXRBdXRoVG9rZW4pIHtcbiAgICAgIGNvbnN0IHRva2VuID0gYXdhaXQgdGhpcy5nZXRBdXRoVG9rZW4oKTtcbiAgICAgIGNvbnN0IGFwaVVybCA9IHRoaXMuZ2V0QXBpVXJsKCk7XG4gICAgICBjb25zdCBwYXlsb2FkOiBTZXNzaW9uS2V5RXhjaGFuZ2VQYXlsb2FkID0ge1xuICAgICAgICBzZXNzaW9uS2V5SWQsXG4gICAgICAgIGNvbnZlcnNhdGlvblR5cGU6IHBhcmFtcy50eXBlLFxuICAgICAgICBjb252ZXJzYXRpb25JZDogcGFyYW1zLmNvbnZlcnNhdGlvbklkLFxuICAgICAgICBnZW5lcmF0aW9uOiBwYXJhbXMuZ2VuZXJhdGlvbixcbiAgICAgICAgbWVtYmVyUGF5bG9hZHNcbiAgICAgIH07XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuaHR0cEZldGNoKGAke2FwaVVybH0vYXBpL2UyZS9zZXNzaW9uLWtleXNgLCB7XG4gICAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke3Rva2VufWAsXG4gICAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nXG4gICAgICAgICAgfSxcbiAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeShwYXlsb2FkKVxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgJ1tTZXNzaW9uS2V5TWFuYWdlcl0gRmFpbGVkIHRvIHN5bmMgc2Vzc2lvbiBrZXkgdG8gc2VydmVyOicsXG4gICAgICAgICAgZXJyXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlc3Npb25LZXk7XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIHRvIGNoZWNrIGlmIGEga2V5IGhhcyBleGNlZWRlZCB0aGUgMzAtZGF5IHJvdGF0aW9uIHRocmVzaG9sZC5cbiAgICovXG4gIGlzS2V5RXhwaXJlZChrZXk6IENvbnZlcnNhdGlvblNlc3Npb25LZXkpOiBib29sZWFuIHtcbiAgICByZXR1cm4gRGF0ZS5ub3coKSAtIGtleS5jcmVhdGVkQXQgPiBUSElSVFlfREFZU19NUztcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgYSBkZXRlcm1pbmlzdGljIGNvbnZlcnNhdGlvbiBpZGVudGlmaWVyIGZvciAxOjEgRE1zIChsZXhpY29ncmFwaGljYWwgc29ydCkuXG4gICAqL1xuICBidWlsZERtQ29udmVyc2F0aW9uSWQodXNlcklkQTogc3RyaW5nLCB1c2VySWRCOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBbdXNlcklkQSwgdXNlcklkQl0uc29ydCgpLmpvaW4oJ18nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWNoZXMgYSBzZXNzaW9uIGtleSBpbiBtZW1vcnkuXG4gICAqL1xuICBwcml2YXRlIGNhY2hlS2V5KGtleTogQ29udmVyc2F0aW9uU2Vzc2lvbktleSk6IHZvaWQge1xuICAgIHRoaXMuYWN0aXZlS2V5c0J5Q29udmVyc2F0aW9uLnNldChrZXkuY29udmVyc2F0aW9uSWQsIGtleSk7XG4gICAgdGhpcy5rZXlzQnlJZC5zZXQoa2V5LmlkLCBrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcnNpc3RzIGFuIHVud3JhcHBlZCBzZXNzaW9uIGtleSB0byBsb2NhbCBzdG9yYWdlIGZvciBmYXN0IHN0YXJ0dXAuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHBlcnNpc3RLZXlMb2NhbGx5KFxuICAgIGtleTogQ29udmVyc2F0aW9uU2Vzc2lvbktleVxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIXRoaXMuc3RvcmFnZSkgcmV0dXJuO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByYXdLZXlCYXNlNjQgPSBhd2FpdCB0aGlzLmNyeXB0b1NlcnZpY2UuZXhwb3J0UmF3S2V5QmFzZTY0KFxuICAgICAgICBrZXkucmF3S2V5XG4gICAgICApO1xuICAgICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgaWQ6IGtleS5pZCxcbiAgICAgICAgdHlwZToga2V5LnR5cGUsXG4gICAgICAgIGNvbnZlcnNhdGlvbklkOiBrZXkuY29udmVyc2F0aW9uSWQsXG4gICAgICAgIHJhd0tleUJhc2U2NCxcbiAgICAgICAgZ2VuZXJhdGlvbjoga2V5LmdlbmVyYXRpb24sXG4gICAgICAgIGNyZWF0ZWRBdDoga2V5LmNyZWF0ZWRBdFxuICAgICAgfSk7XG4gICAgICBhd2FpdCB0aGlzLnN0b3JhZ2Uuc2V0SXRlbShga29qaW54X3NrXyR7a2V5LmlkfWAsIGRhdGEpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gaWdub3JlIHBlcnNpc3RlbmNlIGVycm9yXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZldGNoZXMgbGF0ZXN0IHNlc3Npb24ga2V5IGZyb20gc2VydmVyIGFuZCB1bndyYXBzIGl0IGxvY2FsbHkuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGZldGNoU2Vzc2lvbktleUZyb21TZXJ2ZXIoXG4gICAgY29udmVyc2F0aW9uSWQ6IHN0cmluZyxcbiAgICB0eXBlOiAnZG0nIHwgJ2NoYW5uZWwnIHwgJ2dyb3VwJ1xuICApOiBQcm9taXNlPENvbnZlcnNhdGlvblNlc3Npb25LZXkgfCBudWxsPiB7XG4gICAgaWYgKCF0aGlzLmh0dHBGZXRjaCB8fCAhdGhpcy5nZXRBcGlVcmwgfHwgIXRoaXMuZ2V0QXV0aFRva2VuKSByZXR1cm4gbnVsbDtcblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB0b2tlbiA9IGF3YWl0IHRoaXMuZ2V0QXV0aFRva2VuKCk7XG4gICAgICBjb25zdCBhcGlVcmwgPSB0aGlzLmdldEFwaVVybCgpO1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5odHRwRmV0Y2g8e1xuICAgICAgICBzZXNzaW9uS2V5SWQ6IHN0cmluZztcbiAgICAgICAgZ2VuZXJhdGlvbjogbnVtYmVyO1xuICAgICAgICBlbmNyeXB0ZWRLZXk6IHN0cmluZztcbiAgICAgICAgY3JlYXRlZEF0Pzogc3RyaW5nO1xuICAgICAgfT4oYCR7YXBpVXJsfS9hcGkvZTJlL3Nlc3Npb24ta2V5cy8ke2NvbnZlcnNhdGlvbklkfWAsIHtcbiAgICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHt0b2tlbn1gXG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpZiAocmVzLnN0YXR1cyA9PT0gMjAwICYmIHJlcy5kYXRhPy5lbmNyeXB0ZWRLZXkpIHtcbiAgICAgICAgY29uc3QgcmF3S2V5ID0gYXdhaXQgdGhpcy5jcnlwdG9TZXJ2aWNlLnVud3JhcFNlc3Npb25LZXkoXG4gICAgICAgICAgcmVzLmRhdGEuZW5jcnlwdGVkS2V5XG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgaWQ6IHJlcy5kYXRhLnNlc3Npb25LZXlJZCxcbiAgICAgICAgICB0eXBlLFxuICAgICAgICAgIGNvbnZlcnNhdGlvbklkLFxuICAgICAgICAgIHJhd0tleSxcbiAgICAgICAgICBnZW5lcmF0aW9uOiByZXMuZGF0YS5nZW5lcmF0aW9uIHx8IDEsXG4gICAgICAgICAgY3JlYXRlZEF0OiByZXMuZGF0YS5jcmVhdGVkQXRcbiAgICAgICAgICAgID8gbmV3IERhdGUocmVzLmRhdGEuY3JlYXRlZEF0KS5nZXRUaW1lKClcbiAgICAgICAgICAgIDogRGF0ZS5ub3coKVxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTm90IGZvdW5kIG9yIG5ldHdvcmsgZXJyb3JcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYSByYW5kb20gVVVJRCAoVzNDIHN0YW5kYXJkIG9yIGZhbGxiYWNrKS5cbiAgICovXG4gIHByaXZhdGUgZ2VuZXJhdGVVdWlkKCk6IHN0cmluZyB7XG4gICAgaWYgKHR5cGVvZiBjcnlwdG8gIT09ICd1bmRlZmluZWQnICYmIGNyeXB0by5yYW5kb21VVUlEKSB7XG4gICAgICByZXR1cm4gY3J5cHRvLnJhbmRvbVVVSUQoKTtcbiAgICB9XG4gICAgcmV0dXJuICd4eHh4eHh4eC14eHh4LTR4eHgteXh4eC14eHh4eHh4eHh4eHgnLnJlcGxhY2UoL1t4eV0vZywgYyA9PiB7XG4gICAgICBjb25zdCByID0gKE1hdGgucmFuZG9tKCkgKiAxNikgfCAwO1xuICAgICAgY29uc3QgdiA9IGMgPT09ICd4JyA/IHIgOiAociAmIDB4MykgfCAweDg7XG4gICAgICByZXR1cm4gdi50b1N0cmluZygxNik7XG4gICAgfSk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { InjectionToken } from '@angular/core';
|
|
2
|
+
/**
|
|
3
|
+
* Injected Asymmetric Cryptography Provider (RSA-2048 OAEP).
|
|
4
|
+
* On desktop: Implemented via Tauri Rust Keyring IPC.
|
|
5
|
+
* On mobile: Implemented via SubtleCrypto + Capacitor SecureStorage.
|
|
6
|
+
*/
|
|
7
|
+
export const KOJINX_CRYPTO_PROVIDER = new InjectionToken('KOJINX_CRYPTO_PROVIDER');
|
|
8
|
+
/**
|
|
9
|
+
* Injected Client-Agnostic HTTP Fetcher (bypass CORS on native).
|
|
10
|
+
*/
|
|
11
|
+
export const KOJINX_HTTP_FETCH = new InjectionToken('KOJINX_HTTP_FETCH');
|
|
12
|
+
/**
|
|
13
|
+
* Injected Storage Provider for local session key caching.
|
|
14
|
+
*/
|
|
15
|
+
export const KOJINX_CRYPTO_STORAGE = new InjectionToken('KOJINX_CRYPTO_STORAGE', {
|
|
16
|
+
factory: () => ({
|
|
17
|
+
getItem: (key) => Promise.resolve(localStorage.getItem(key)),
|
|
18
|
+
setItem: (key, value) => {
|
|
19
|
+
localStorage.setItem(key, value);
|
|
20
|
+
return Promise.resolve();
|
|
21
|
+
},
|
|
22
|
+
removeItem: (key) => {
|
|
23
|
+
localStorage.removeItem(key);
|
|
24
|
+
return Promise.resolve();
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Injected API Base URL accessor function.
|
|
30
|
+
*/
|
|
31
|
+
export const KOJINX_API_BASE_URL = new InjectionToken('KOJINX_API_BASE_URL');
|
|
32
|
+
/**
|
|
33
|
+
* Injected Auth Bearer Token accessor function.
|
|
34
|
+
*/
|
|
35
|
+
export const KOJINX_AUTH_TOKEN = new InjectionToken('KOJINX_AUTH_TOKEN');
|
|
36
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva29qaW54L2NvbGxhYi1jcnlwdG8vc3JjL2xpYi90b2tlbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQU8vQzs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxjQUFjLENBQ3RELHdCQUF3QixDQUN6QixDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLGNBQWMsQ0FDakQsbUJBQW1CLENBQ3BCLENBQUM7QUFFRjs7R0FFRztBQUNILE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLElBQUksY0FBYyxDQUNyRCx1QkFBdUIsRUFDdkI7SUFDRSxPQUFPLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUNkLE9BQU8sRUFBRSxDQUFDLEdBQVcsRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BFLE9BQU8sRUFBRSxDQUFDLEdBQVcsRUFBRSxLQUFhLEVBQUUsRUFBRTtZQUN0QyxZQUFZLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNqQyxPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMzQixDQUFDO1FBQ0QsVUFBVSxFQUFFLENBQUMsR0FBVyxFQUFFLEVBQUU7WUFDMUIsWUFBWSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUM3QixPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMzQixDQUFDO0tBQ0YsQ0FBQztDQUNILENBQ0YsQ0FBQztBQUVGOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxjQUFjLENBQ25ELHFCQUFxQixDQUN0QixDQUFDO0FBRUY7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLGNBQWMsQ0FDakQsbUJBQW1CLENBQ3BCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3Rpb25Ub2tlbiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgS29qaW54Q3J5cHRvUHJvdmlkZXIsXG4gIEtvamlueEZldGNoRnVuY3Rpb24sXG4gIEtvamlueFN0b3JhZ2VQcm92aWRlclxufSBmcm9tICcuL21vZGVscy9jcnlwdG8ubW9kZWxzJztcblxuLyoqXG4gKiBJbmplY3RlZCBBc3ltbWV0cmljIENyeXB0b2dyYXBoeSBQcm92aWRlciAoUlNBLTIwNDggT0FFUCkuXG4gKiBPbiBkZXNrdG9wOiBJbXBsZW1lbnRlZCB2aWEgVGF1cmkgUnVzdCBLZXlyaW5nIElQQy5cbiAqIE9uIG1vYmlsZTogSW1wbGVtZW50ZWQgdmlhIFN1YnRsZUNyeXB0byArIENhcGFjaXRvciBTZWN1cmVTdG9yYWdlLlxuICovXG5leHBvcnQgY29uc3QgS09KSU5YX0NSWVBUT19QUk9WSURFUiA9IG5ldyBJbmplY3Rpb25Ub2tlbjxLb2ppbnhDcnlwdG9Qcm92aWRlcj4oXG4gICdLT0pJTlhfQ1JZUFRPX1BST1ZJREVSJ1xuKTtcblxuLyoqXG4gKiBJbmplY3RlZCBDbGllbnQtQWdub3N0aWMgSFRUUCBGZXRjaGVyIChieXBhc3MgQ09SUyBvbiBuYXRpdmUpLlxuICovXG5leHBvcnQgY29uc3QgS09KSU5YX0hUVFBfRkVUQ0ggPSBuZXcgSW5qZWN0aW9uVG9rZW48S29qaW54RmV0Y2hGdW5jdGlvbj4oXG4gICdLT0pJTlhfSFRUUF9GRVRDSCdcbik7XG5cbi8qKlxuICogSW5qZWN0ZWQgU3RvcmFnZSBQcm92aWRlciBmb3IgbG9jYWwgc2Vzc2lvbiBrZXkgY2FjaGluZy5cbiAqL1xuZXhwb3J0IGNvbnN0IEtPSklOWF9DUllQVE9fU1RPUkFHRSA9IG5ldyBJbmplY3Rpb25Ub2tlbjxLb2ppbnhTdG9yYWdlUHJvdmlkZXI+KFxuICAnS09KSU5YX0NSWVBUT19TVE9SQUdFJyxcbiAge1xuICAgIGZhY3Rvcnk6ICgpID0+ICh7XG4gICAgICBnZXRJdGVtOiAoa2V5OiBzdHJpbmcpID0+IFByb21pc2UucmVzb2x2ZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbShrZXkpKSxcbiAgICAgIHNldEl0ZW06IChrZXk6IHN0cmluZywgdmFsdWU6IHN0cmluZykgPT4ge1xuICAgICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbShrZXksIHZhbHVlKTtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgfSxcbiAgICAgIHJlbW92ZUl0ZW06IChrZXk6IHN0cmluZykgPT4ge1xuICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbShrZXkpO1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgICB9XG4gICAgfSlcbiAgfVxuKTtcblxuLyoqXG4gKiBJbmplY3RlZCBBUEkgQmFzZSBVUkwgYWNjZXNzb3IgZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBLT0pJTlhfQVBJX0JBU0VfVVJMID0gbmV3IEluamVjdGlvblRva2VuPCgpID0+IHN0cmluZz4oXG4gICdLT0pJTlhfQVBJX0JBU0VfVVJMJ1xuKTtcblxuLyoqXG4gKiBJbmplY3RlZCBBdXRoIEJlYXJlciBUb2tlbiBhY2Nlc3NvciBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IEtPSklOWF9BVVRIX1RPS0VOID0gbmV3IEluamVjdGlvblRva2VuPCgpID0+IFByb21pc2U8c3RyaW5nIHwgbnVsbD4+KFxuICAnS09KSU5YX0FVVEhfVE9LRU4nXG4pO1xuIl19
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes deterministic SHA-256 safety verification numbers (Signal-style).
|
|
3
|
+
* Users can compare these 30-digit numbers out-of-band to verify end-to-end identity.
|
|
4
|
+
*/
|
|
5
|
+
export class SafetyNumberUtils {
|
|
6
|
+
/**
|
|
7
|
+
* Generates a Safety Number between two identity public keys.
|
|
8
|
+
*
|
|
9
|
+
* @param localPublicKey Base64-encoded local RSA public key
|
|
10
|
+
* @param remotePublicKey Base64-encoded remote RSA public key
|
|
11
|
+
*/
|
|
12
|
+
static async generate(localPublicKey, remotePublicKey) {
|
|
13
|
+
if (!localPublicKey || !remotePublicKey) {
|
|
14
|
+
throw new Error('Both public keys are required to generate safety numbers.');
|
|
15
|
+
}
|
|
16
|
+
const localFingerprint = await this.hashPublicKey(localPublicKey);
|
|
17
|
+
const remoteFingerprint = await this.hashPublicKey(remotePublicKey);
|
|
18
|
+
// Sort lexicographically to ensure order-independent verification
|
|
19
|
+
const sorted = [localFingerprint, remoteFingerprint].sort();
|
|
20
|
+
const combinedDigest = await this.sha256(sorted.join(''));
|
|
21
|
+
// Convert hex digest to a 30-digit decimal representation
|
|
22
|
+
const digits = this.hexTo30Digits(combinedDigest);
|
|
23
|
+
const formatted = this.formatBlocks(digits);
|
|
24
|
+
return {
|
|
25
|
+
raw: combinedDigest,
|
|
26
|
+
formatted,
|
|
27
|
+
localFingerprint: localFingerprint.substring(0, 16),
|
|
28
|
+
remoteFingerprint: remoteFingerprint.substring(0, 16)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Hashes a single public key using SHA-256.
|
|
33
|
+
*/
|
|
34
|
+
static async hashPublicKey(publicKeyBase64) {
|
|
35
|
+
const cleanKey = publicKeyBase64.replace(/\s+/g, '');
|
|
36
|
+
return this.sha256(cleanKey);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Computes SHA-256 hex string using W3C Web Crypto API.
|
|
40
|
+
*/
|
|
41
|
+
static async sha256(input) {
|
|
42
|
+
const encoder = new TextEncoder();
|
|
43
|
+
const data = encoder.encode(input);
|
|
44
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
45
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
46
|
+
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Converts a hexadecimal string into a deterministic 30-digit decimal string.
|
|
50
|
+
*/
|
|
51
|
+
static hexTo30Digits(hex) {
|
|
52
|
+
let result = '';
|
|
53
|
+
// Take chunks of 8 hex characters (32-bit integers) to produce 5-digit decimal blocks
|
|
54
|
+
for (let i = 0; i < 6; i++) {
|
|
55
|
+
const chunk = hex.substring(i * 8, (i + 1) * 8);
|
|
56
|
+
const num = parseInt(chunk, 16) % 100000;
|
|
57
|
+
result += num.toString().padStart(5, '0');
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Formats a 30-digit string into 6 blocks of 5 digits separated by spaces.
|
|
63
|
+
*/
|
|
64
|
+
static formatBlocks(digits) {
|
|
65
|
+
const blocks = [];
|
|
66
|
+
for (let i = 0; i < digits.length; i += 5) {
|
|
67
|
+
blocks.push(digits.substring(i, i + 5));
|
|
68
|
+
}
|
|
69
|
+
return blocks.join(' ');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FmZXR5LW51bWJlci51dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2tvamlueC9jb2xsYWItY3J5cHRvL3NyYy9saWIvdXRpbHMvc2FmZXR5LW51bWJlci51dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQTs7O0dBR0c7QUFDSCxNQUFNLE9BQU8saUJBQWlCO0lBQzVCOzs7OztPQUtHO0lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQ25CLGNBQXNCLEVBQ3RCLGVBQXVCO1FBRXZCLElBQUksQ0FBQyxjQUFjLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztZQUN4QyxNQUFNLElBQUksS0FBSyxDQUFDLDJEQUEyRCxDQUFDLENBQUM7UUFDL0UsQ0FBQztRQUVELE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ2xFLE1BQU0saUJBQWlCLEdBQUcsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBRXBFLGtFQUFrRTtRQUNsRSxNQUFNLE1BQU0sR0FBRyxDQUFDLGdCQUFnQixFQUFFLGlCQUFpQixDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDNUQsTUFBTSxjQUFjLEdBQUcsTUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUUxRCwwREFBMEQ7UUFDMUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUNsRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTVDLE9BQU87WUFDTCxHQUFHLEVBQUUsY0FBYztZQUNuQixTQUFTO1lBQ1QsZ0JBQWdCLEVBQUUsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDbkQsaUJBQWlCLEVBQUUsaUJBQWlCLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7U0FDdEQsQ0FBQztJQUNKLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLGVBQXVCO1FBQ2hELE1BQU0sUUFBUSxHQUFHLGVBQWUsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3JELE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUMvQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFhO1FBQ3ZDLE1BQU0sT0FBTyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7UUFDbEMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNuQyxNQUFNLFVBQVUsR0FBRyxNQUFNLE1BQU0sQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUMvRCxNQUFNLFNBQVMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7UUFDekQsT0FBTyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFFRDs7T0FFRztJQUNLLE1BQU0sQ0FBQyxhQUFhLENBQUMsR0FBVztRQUN0QyxJQUFJLE1BQU0sR0FBRyxFQUFFLENBQUM7UUFDaEIsc0ZBQXNGO1FBQ3RGLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUMzQixNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7WUFDaEQsTUFBTSxHQUFHLEdBQUcsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUM7WUFDekMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzVDLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQ7O09BRUc7SUFDSyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQWM7UUFDeEMsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO1FBQzVCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUMxQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzFDLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDMUIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgU2FmZXR5TnVtYmVyIH0gZnJvbSAnLi4vbW9kZWxzL2NyeXB0by5tb2RlbHMnO1xuXG4vKipcbiAqIENvbXB1dGVzIGRldGVybWluaXN0aWMgU0hBLTI1NiBzYWZldHkgdmVyaWZpY2F0aW9uIG51bWJlcnMgKFNpZ25hbC1zdHlsZSkuXG4gKiBVc2VycyBjYW4gY29tcGFyZSB0aGVzZSAzMC1kaWdpdCBudW1iZXJzIG91dC1vZi1iYW5kIHRvIHZlcmlmeSBlbmQtdG8tZW5kIGlkZW50aXR5LlxuICovXG5leHBvcnQgY2xhc3MgU2FmZXR5TnVtYmVyVXRpbHMge1xuICAvKipcbiAgICogR2VuZXJhdGVzIGEgU2FmZXR5IE51bWJlciBiZXR3ZWVuIHR3byBpZGVudGl0eSBwdWJsaWMga2V5cy5cbiAgICpcbiAgICogQHBhcmFtIGxvY2FsUHVibGljS2V5IEJhc2U2NC1lbmNvZGVkIGxvY2FsIFJTQSBwdWJsaWMga2V5XG4gICAqIEBwYXJhbSByZW1vdGVQdWJsaWNLZXkgQmFzZTY0LWVuY29kZWQgcmVtb3RlIFJTQSBwdWJsaWMga2V5XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZ2VuZXJhdGUoXG4gICAgbG9jYWxQdWJsaWNLZXk6IHN0cmluZyxcbiAgICByZW1vdGVQdWJsaWNLZXk6IHN0cmluZ1xuICApOiBQcm9taXNlPFNhZmV0eU51bWJlcj4ge1xuICAgIGlmICghbG9jYWxQdWJsaWNLZXkgfHwgIXJlbW90ZVB1YmxpY0tleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdCb3RoIHB1YmxpYyBrZXlzIGFyZSByZXF1aXJlZCB0byBnZW5lcmF0ZSBzYWZldHkgbnVtYmVycy4nKTtcbiAgICB9XG5cbiAgICBjb25zdCBsb2NhbEZpbmdlcnByaW50ID0gYXdhaXQgdGhpcy5oYXNoUHVibGljS2V5KGxvY2FsUHVibGljS2V5KTtcbiAgICBjb25zdCByZW1vdGVGaW5nZXJwcmludCA9IGF3YWl0IHRoaXMuaGFzaFB1YmxpY0tleShyZW1vdGVQdWJsaWNLZXkpO1xuXG4gICAgLy8gU29ydCBsZXhpY29ncmFwaGljYWxseSB0byBlbnN1cmUgb3JkZXItaW5kZXBlbmRlbnQgdmVyaWZpY2F0aW9uXG4gICAgY29uc3Qgc29ydGVkID0gW2xvY2FsRmluZ2VycHJpbnQsIHJlbW90ZUZpbmdlcnByaW50XS5zb3J0KCk7XG4gICAgY29uc3QgY29tYmluZWREaWdlc3QgPSBhd2FpdCB0aGlzLnNoYTI1Nihzb3J0ZWQuam9pbignJykpO1xuXG4gICAgLy8gQ29udmVydCBoZXggZGlnZXN0IHRvIGEgMzAtZGlnaXQgZGVjaW1hbCByZXByZXNlbnRhdGlvblxuICAgIGNvbnN0IGRpZ2l0cyA9IHRoaXMuaGV4VG8zMERpZ2l0cyhjb21iaW5lZERpZ2VzdCk7XG4gICAgY29uc3QgZm9ybWF0dGVkID0gdGhpcy5mb3JtYXRCbG9ja3MoZGlnaXRzKTtcblxuICAgIHJldHVybiB7XG4gICAgICByYXc6IGNvbWJpbmVkRGlnZXN0LFxuICAgICAgZm9ybWF0dGVkLFxuICAgICAgbG9jYWxGaW5nZXJwcmludDogbG9jYWxGaW5nZXJwcmludC5zdWJzdHJpbmcoMCwgMTYpLFxuICAgICAgcmVtb3RlRmluZ2VycHJpbnQ6IHJlbW90ZUZpbmdlcnByaW50LnN1YnN0cmluZygwLCAxNilcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEhhc2hlcyBhIHNpbmdsZSBwdWJsaWMga2V5IHVzaW5nIFNIQS0yNTYuXG4gICAqL1xuICBzdGF0aWMgYXN5bmMgaGFzaFB1YmxpY0tleShwdWJsaWNLZXlCYXNlNjQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgY2xlYW5LZXkgPSBwdWJsaWNLZXlCYXNlNjQucmVwbGFjZSgvXFxzKy9nLCAnJyk7XG4gICAgcmV0dXJuIHRoaXMuc2hhMjU2KGNsZWFuS2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wdXRlcyBTSEEtMjU2IGhleCBzdHJpbmcgdXNpbmcgVzNDIFdlYiBDcnlwdG8gQVBJLlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgc2hhMjU2KGlucHV0OiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGVuY29kZXIgPSBuZXcgVGV4dEVuY29kZXIoKTtcbiAgICBjb25zdCBkYXRhID0gZW5jb2Rlci5lbmNvZGUoaW5wdXQpO1xuICAgIGNvbnN0IGhhc2hCdWZmZXIgPSBhd2FpdCBjcnlwdG8uc3VidGxlLmRpZ2VzdCgnU0hBLTI1NicsIGRhdGEpO1xuICAgIGNvbnN0IGhhc2hBcnJheSA9IEFycmF5LmZyb20obmV3IFVpbnQ4QXJyYXkoaGFzaEJ1ZmZlcikpO1xuICAgIHJldHVybiBoYXNoQXJyYXkubWFwKGIgPT4gYi50b1N0cmluZygxNikucGFkU3RhcnQoMiwgJzAnKSkuam9pbignJyk7XG4gIH1cblxuICAvKipcbiAgICogQ29udmVydHMgYSBoZXhhZGVjaW1hbCBzdHJpbmcgaW50byBhIGRldGVybWluaXN0aWMgMzAtZGlnaXQgZGVjaW1hbCBzdHJpbmcuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBoZXhUbzMwRGlnaXRzKGhleDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBsZXQgcmVzdWx0ID0gJyc7XG4gICAgLy8gVGFrZSBjaHVua3Mgb2YgOCBoZXggY2hhcmFjdGVycyAoMzItYml0IGludGVnZXJzKSB0byBwcm9kdWNlIDUtZGlnaXQgZGVjaW1hbCBibG9ja3NcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IDY7IGkrKykge1xuICAgICAgY29uc3QgY2h1bmsgPSBoZXguc3Vic3RyaW5nKGkgKiA4LCAoaSArIDEpICogOCk7XG4gICAgICBjb25zdCBudW0gPSBwYXJzZUludChjaHVuaywgMTYpICUgMTAwMDAwO1xuICAgICAgcmVzdWx0ICs9IG51bS50b1N0cmluZygpLnBhZFN0YXJ0KDUsICcwJyk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogRm9ybWF0cyBhIDMwLWRpZ2l0IHN0cmluZyBpbnRvIDYgYmxvY2tzIG9mIDUgZGlnaXRzIHNlcGFyYXRlZCBieSBzcGFjZXMuXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBmb3JtYXRCbG9ja3MoZGlnaXRzOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IGJsb2Nrczogc3RyaW5nW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGRpZ2l0cy5sZW5ndGg7IGkgKz0gNSkge1xuICAgICAgYmxvY2tzLnB1c2goZGlnaXRzLnN1YnN0cmluZyhpLCBpICsgNSkpO1xuICAgIH1cbiAgICByZXR1cm4gYmxvY2tzLmpvaW4oJyAnKTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public API Surface of @kojinx/collab-crypto
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/tokens';
|
|
5
|
+
export * from './lib/models/crypto.models';
|
|
6
|
+
export * from './lib/utils/safety-number.utils';
|
|
7
|
+
export * from './lib/services/e2e-chat-crypto.service';
|
|
8
|
+
export * from './lib/services/session-key-manager.service';
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL2tvamlueC9jb2xsYWItY3J5cHRvL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLGlDQUFpQyxDQUFDO0FBQ2hELGNBQWMsd0NBQXdDLENBQUM7QUFDdkQsY0FBYyw0Q0FBNEMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBQdWJsaWMgQVBJIFN1cmZhY2Ugb2YgQGtvamlueC9jb2xsYWItY3J5cHRvXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9saWIvdG9rZW5zJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL21vZGVscy9jcnlwdG8ubW9kZWxzJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3V0aWxzL3NhZmV0eS1udW1iZXIudXRpbHMnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc2VydmljZXMvZTJlLWNoYXQtY3J5cHRvLnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc2VydmljZXMvc2Vzc2lvbi1rZXktbWFuYWdlci5zZXJ2aWNlJztcbiJdfQ==
|