forkoff 1.0.8 → 1.0.9
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/E2EE-COMPLETE.md +290 -0
- package/dist/__tests__/crypto/e2e-integration.test.d.ts +17 -0
- package/dist/__tests__/crypto/e2e-integration.test.d.ts.map +1 -0
- package/dist/__tests__/crypto/e2e-integration.test.js +338 -0
- package/dist/__tests__/crypto/e2e-integration.test.js.map +1 -0
- package/dist/__tests__/crypto/e2eeManager.test.d.ts +2 -0
- package/dist/__tests__/crypto/e2eeManager.test.d.ts.map +1 -0
- package/dist/__tests__/crypto/e2eeManager.test.js +242 -0
- package/dist/__tests__/crypto/e2eeManager.test.js.map +1 -0
- package/dist/__tests__/crypto/encryption.test.d.ts +2 -0
- package/dist/__tests__/crypto/encryption.test.d.ts.map +1 -0
- package/dist/__tests__/crypto/encryption.test.js +116 -0
- package/dist/__tests__/crypto/encryption.test.js.map +1 -0
- package/dist/__tests__/crypto/keyExchange.test.d.ts +2 -0
- package/dist/__tests__/crypto/keyExchange.test.d.ts.map +1 -0
- package/dist/__tests__/crypto/keyExchange.test.js +84 -0
- package/dist/__tests__/crypto/keyExchange.test.js.map +1 -0
- package/dist/__tests__/crypto/keyGeneration.test.d.ts +2 -0
- package/dist/__tests__/crypto/keyGeneration.test.d.ts.map +1 -0
- package/dist/__tests__/crypto/keyGeneration.test.js +61 -0
- package/dist/__tests__/crypto/keyGeneration.test.js.map +1 -0
- package/dist/__tests__/crypto/keyStorage.test.d.ts +2 -0
- package/dist/__tests__/crypto/keyStorage.test.d.ts.map +1 -0
- package/dist/__tests__/crypto/keyStorage.test.js +133 -0
- package/dist/__tests__/crypto/keyStorage.test.js.map +1 -0
- package/dist/__tests__/crypto/websocketIntegration.test.d.ts +2 -0
- package/dist/__tests__/crypto/websocketIntegration.test.d.ts.map +1 -0
- package/dist/__tests__/crypto/websocketIntegration.test.js +259 -0
- package/dist/__tests__/crypto/websocketIntegration.test.js.map +1 -0
- package/dist/crypto/e2eeManager.d.ts +82 -0
- package/dist/crypto/e2eeManager.d.ts.map +1 -0
- package/dist/crypto/e2eeManager.js +270 -0
- package/dist/crypto/e2eeManager.js.map +1 -0
- package/dist/crypto/encryption.d.ts +19 -0
- package/dist/crypto/encryption.d.ts.map +1 -0
- package/dist/crypto/encryption.js +111 -0
- package/dist/crypto/encryption.js.map +1 -0
- package/dist/crypto/keyExchange.d.ts +24 -0
- package/dist/crypto/keyExchange.d.ts.map +1 -0
- package/dist/crypto/keyExchange.js +119 -0
- package/dist/crypto/keyExchange.js.map +1 -0
- package/dist/crypto/keyGeneration.d.ts +18 -0
- package/dist/crypto/keyGeneration.d.ts.map +1 -0
- package/dist/crypto/keyGeneration.js +99 -0
- package/dist/crypto/keyGeneration.js.map +1 -0
- package/dist/crypto/keyStorage.d.ts +39 -0
- package/dist/crypto/keyStorage.d.ts.map +1 -0
- package/dist/crypto/keyStorage.js +117 -0
- package/dist/crypto/keyStorage.js.map +1 -0
- package/dist/crypto/sessionPersistence.d.ts +33 -0
- package/dist/crypto/sessionPersistence.d.ts.map +1 -0
- package/dist/crypto/sessionPersistence.js +173 -0
- package/dist/crypto/sessionPersistence.js.map +1 -0
- package/dist/crypto/types.d.ts +35 -0
- package/dist/crypto/types.d.ts.map +1 -0
- package/dist/crypto/types.js +8 -0
- package/dist/crypto/types.js.map +1 -0
- package/dist/crypto/websocketE2EE.d.ts +47 -0
- package/dist/crypto/websocketE2EE.d.ts.map +1 -0
- package/dist/crypto/websocketE2EE.js +144 -0
- package/dist/crypto/websocketE2EE.js.map +1 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -1
- package/dist/websocket.d.ts +26 -1
- package/dist/websocket.d.ts.map +1 -1
- package/dist/websocket.js +25 -1
- package/dist/websocket.js.map +1 -1
- package/jest.config.js +15 -0
- package/package.json +9 -2
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateKeyPair = generateKeyPair;
|
|
37
|
+
exports.generateKeyPairFromSeed = generateKeyPairFromSeed;
|
|
38
|
+
const crypto = __importStar(require("crypto"));
|
|
39
|
+
/**
|
|
40
|
+
* Generates a random X25519 key pair for E2EE
|
|
41
|
+
* Uses Node.js crypto module
|
|
42
|
+
*
|
|
43
|
+
* @returns E2EEKeyPair with Base64-encoded public and private keys (32 bytes each)
|
|
44
|
+
*/
|
|
45
|
+
function generateKeyPair() {
|
|
46
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519', {
|
|
47
|
+
publicKeyEncoding: {
|
|
48
|
+
type: 'spki',
|
|
49
|
+
format: 'der',
|
|
50
|
+
},
|
|
51
|
+
privateKeyEncoding: {
|
|
52
|
+
type: 'pkcs8',
|
|
53
|
+
format: 'der',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
// Extract raw 32-byte keys from DER-encoded buffers
|
|
57
|
+
// X25519 public key: last 32 bytes of SPKI
|
|
58
|
+
// X25519 private key: last 32 bytes of PKCS8
|
|
59
|
+
const rawPublicKey = publicKey.slice(-32);
|
|
60
|
+
const rawPrivateKey = privateKey.slice(-32);
|
|
61
|
+
return {
|
|
62
|
+
publicKey: rawPublicKey.toString('base64'),
|
|
63
|
+
privateKey: rawPrivateKey.toString('base64'),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Generates a deterministic X25519 key pair from a seed
|
|
68
|
+
* Useful for testing and key derivation
|
|
69
|
+
*
|
|
70
|
+
* @param seed - 32-byte buffer to use as the private key seed
|
|
71
|
+
* @returns E2EEKeyPair with Base64-encoded public and private keys
|
|
72
|
+
* @throws Error if seed is not 32 bytes
|
|
73
|
+
*/
|
|
74
|
+
function generateKeyPairFromSeed(seed) {
|
|
75
|
+
if (seed.length !== 32) {
|
|
76
|
+
throw new Error('Seed must be exactly 32 bytes');
|
|
77
|
+
}
|
|
78
|
+
// In X25519, the private key IS the seed (32 random bytes)
|
|
79
|
+
// The public key is derived: publicKey = privateKey * basepoint
|
|
80
|
+
const privateKeyObject = crypto.createPrivateKey({
|
|
81
|
+
key: Buffer.concat([
|
|
82
|
+
Buffer.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20]),
|
|
83
|
+
seed,
|
|
84
|
+
]),
|
|
85
|
+
format: 'der',
|
|
86
|
+
type: 'pkcs8',
|
|
87
|
+
});
|
|
88
|
+
const publicKeyObject = crypto.createPublicKey(privateKeyObject);
|
|
89
|
+
// Export raw keys
|
|
90
|
+
const publicKeyDER = publicKeyObject.export({ type: 'spki', format: 'der' });
|
|
91
|
+
const privateKeyDER = privateKeyObject.export({ type: 'pkcs8', format: 'der' });
|
|
92
|
+
const rawPublicKey = publicKeyDER.slice(-32);
|
|
93
|
+
const rawPrivateKey = privateKeyDER.slice(-32);
|
|
94
|
+
return {
|
|
95
|
+
publicKey: rawPublicKey.toString('base64'),
|
|
96
|
+
privateKey: rawPrivateKey.toString('base64'),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=keyGeneration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyGeneration.js","sourceRoot":"","sources":["../../src/crypto/keyGeneration.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,0CAsBC;AAUD,0DA6BC;AAtED,+CAAiC;AAGjC;;;;;GAKG;AACH,SAAgB,eAAe;IAC7B,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE;QACrE,iBAAiB,EAAE;YACjB,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,KAAK;SACd;QACD,kBAAkB,EAAE;YAClB,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,KAAK;SACd;KACF,CAAC,CAAC;IAEH,oDAAoD;IACpD,2CAA2C;IAC3C,6CAA6C;IAC7C,MAAM,YAAY,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IAC1C,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5C,OAAO;QACL,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC1C,UAAU,EAAE,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,uBAAuB,CAAC,IAAY;IAClD,IAAI,IAAI,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,2DAA2D;IAC3D,gEAAgE;IAChE,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC;QAC/C,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;YAC7G,IAAI;SACL,CAAC;QACF,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,OAAO;KACd,CAAC,CAAC;IAEH,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC;IAEjE,kBAAkB;IAClB,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAW,CAAC;IACvF,MAAM,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAW,CAAC;IAE1F,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;IAE/C,OAAO;QACL,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC1C,UAAU,EAAE,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAC7C,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SessionKeys } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Stores private key in OS keychain
|
|
4
|
+
* @param deviceId - Device ID
|
|
5
|
+
* @param privateKey - Base64-encoded X25519 private key
|
|
6
|
+
*/
|
|
7
|
+
export declare function storePrivateKey(deviceId: string, privateKey: string): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Retrieves private key from OS keychain
|
|
10
|
+
* @param deviceId - Device ID
|
|
11
|
+
* @returns Base64-encoded private key or null if not found
|
|
12
|
+
*/
|
|
13
|
+
export declare function getPrivateKey(deviceId: string): Promise<string | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Deletes private key from OS keychain
|
|
16
|
+
* @param deviceId - Device ID
|
|
17
|
+
*/
|
|
18
|
+
export declare function deletePrivateKey(deviceId: string): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Stores session encryption key in memory
|
|
21
|
+
* Session keys are ephemeral and not persisted to disk
|
|
22
|
+
*
|
|
23
|
+
* @param deviceId - Target device ID
|
|
24
|
+
* @param encryptionKey - AES-256-GCM encryption key (32 bytes)
|
|
25
|
+
* @param sessionId - Unique session identifier
|
|
26
|
+
*/
|
|
27
|
+
export declare function storeSessionKey(deviceId: string, encryptionKey: Uint8Array, sessionId: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Retrieves session encryption key from memory
|
|
30
|
+
* @param deviceId - Target device ID
|
|
31
|
+
* @returns SessionKeys or null if not found
|
|
32
|
+
*/
|
|
33
|
+
export declare function getSessionKey(deviceId: string): SessionKeys | null;
|
|
34
|
+
/**
|
|
35
|
+
* Clears all session keys from memory
|
|
36
|
+
* Called on disconnect or logout
|
|
37
|
+
*/
|
|
38
|
+
export declare function clearSessionKeys(): void;
|
|
39
|
+
//# sourceMappingURL=keyStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyStorage.d.ts","sourceRoot":"","sources":["../../src/crypto/keyStorage.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAOtC;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAW5E;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAUtE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,UAAU,EACzB,SAAS,EAAE,MAAM,GAChB,IAAI,CAKN;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAElE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.storePrivateKey = storePrivateKey;
|
|
37
|
+
exports.getPrivateKey = getPrivateKey;
|
|
38
|
+
exports.deletePrivateKey = deletePrivateKey;
|
|
39
|
+
exports.storeSessionKey = storeSessionKey;
|
|
40
|
+
exports.getSessionKey = getSessionKey;
|
|
41
|
+
exports.clearSessionKeys = clearSessionKeys;
|
|
42
|
+
const keytar = __importStar(require("keytar"));
|
|
43
|
+
const SERVICE_NAME = 'forkoff-cli';
|
|
44
|
+
// In-memory storage for session keys (not persisted)
|
|
45
|
+
const sessionKeyStore = new Map();
|
|
46
|
+
/**
|
|
47
|
+
* Stores private key in OS keychain
|
|
48
|
+
* @param deviceId - Device ID
|
|
49
|
+
* @param privateKey - Base64-encoded X25519 private key
|
|
50
|
+
*/
|
|
51
|
+
async function storePrivateKey(deviceId, privateKey) {
|
|
52
|
+
try {
|
|
53
|
+
await keytar.setPassword(SERVICE_NAME, `e2ee-private-key-${deviceId}`, privateKey);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error('Failed to store private key in keychain:', error);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Retrieves private key from OS keychain
|
|
62
|
+
* @param deviceId - Device ID
|
|
63
|
+
* @returns Base64-encoded private key or null if not found
|
|
64
|
+
*/
|
|
65
|
+
async function getPrivateKey(deviceId) {
|
|
66
|
+
try {
|
|
67
|
+
const key = await keytar.getPassword(SERVICE_NAME, `e2ee-private-key-${deviceId}`);
|
|
68
|
+
return key;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error('Failed to retrieve private key from keychain:', error);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Deletes private key from OS keychain
|
|
77
|
+
* @param deviceId - Device ID
|
|
78
|
+
*/
|
|
79
|
+
async function deletePrivateKey(deviceId) {
|
|
80
|
+
try {
|
|
81
|
+
await keytar.deletePassword(SERVICE_NAME, `e2ee-private-key-${deviceId}`);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error('Failed to delete private key from keychain:', error);
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Stores session encryption key in memory
|
|
90
|
+
* Session keys are ephemeral and not persisted to disk
|
|
91
|
+
*
|
|
92
|
+
* @param deviceId - Target device ID
|
|
93
|
+
* @param encryptionKey - AES-256-GCM encryption key (32 bytes)
|
|
94
|
+
* @param sessionId - Unique session identifier
|
|
95
|
+
*/
|
|
96
|
+
function storeSessionKey(deviceId, encryptionKey, sessionId) {
|
|
97
|
+
sessionKeyStore.set(deviceId, {
|
|
98
|
+
encryptionKey,
|
|
99
|
+
sessionId,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Retrieves session encryption key from memory
|
|
104
|
+
* @param deviceId - Target device ID
|
|
105
|
+
* @returns SessionKeys or null if not found
|
|
106
|
+
*/
|
|
107
|
+
function getSessionKey(deviceId) {
|
|
108
|
+
return sessionKeyStore.get(deviceId) ?? null;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Clears all session keys from memory
|
|
112
|
+
* Called on disconnect or logout
|
|
113
|
+
*/
|
|
114
|
+
function clearSessionKeys() {
|
|
115
|
+
sessionKeyStore.clear();
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=keyStorage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyStorage.js","sourceRoot":"","sources":["../../src/crypto/keyStorage.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,0CAcC;AAOD,sCAWC;AAMD,4CAUC;AAUD,0CASC;AAOD,sCAEC;AAMD,4CAEC;AAjGD,+CAAiC;AAGjC,MAAM,YAAY,GAAG,aAAa,CAAC;AAEnC,qDAAqD;AACrD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAuB,CAAC;AAEvD;;;;GAIG;AACI,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,UAAkB;IAElB,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,WAAW,CACtB,YAAY,EACZ,oBAAoB,QAAQ,EAAE,EAC9B,UAAU,CACX,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QACjE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACI,KAAK,UAAU,aAAa,CAAC,QAAgB;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,WAAW,CAClC,YAAY,EACZ,oBAAoB,QAAQ,EAAE,CAC/B,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,KAAK,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,cAAc,CACzB,YAAY,EACZ,oBAAoB,QAAQ,EAAE,CAC/B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;QACpE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,eAAe,CAC7B,QAAgB,EAChB,aAAyB,EACzB,SAAiB;IAEjB,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE;QAC5B,aAAa;QACb,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAgB,aAAa,CAAC,QAAgB;IAC5C,OAAO,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB;IAC9B,eAAe,CAAC,KAAK,EAAE,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SessionKeys } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Persists a session key to disk
|
|
4
|
+
* @param deviceId - Current device ID
|
|
5
|
+
* @param targetDeviceId - Target device ID
|
|
6
|
+
* @param sessionKeys - Session encryption keys
|
|
7
|
+
*/
|
|
8
|
+
export declare function persistSessionKey(deviceId: string, targetDeviceId: string, sessionKeys: SessionKeys): void;
|
|
9
|
+
/**
|
|
10
|
+
* Loads a persisted session key from disk
|
|
11
|
+
* @param deviceId - Current device ID
|
|
12
|
+
* @param targetDeviceId - Target device ID
|
|
13
|
+
* @returns SessionKeys or null if not found
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadPersistedSessionKey(deviceId: string, targetDeviceId: string): SessionKeys | null;
|
|
16
|
+
/**
|
|
17
|
+
* Deletes a persisted session
|
|
18
|
+
* @param deviceId - Current device ID
|
|
19
|
+
* @param targetDeviceId - Target device ID
|
|
20
|
+
*/
|
|
21
|
+
export declare function deletePersistedSession(deviceId: string, targetDeviceId: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Deletes all persisted sessions for a device
|
|
24
|
+
* @param deviceId - Current device ID
|
|
25
|
+
*/
|
|
26
|
+
export declare function deleteAllPersistedSessions(deviceId: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Lists all persisted sessions for a device
|
|
29
|
+
* @param deviceId - Current device ID
|
|
30
|
+
* @returns Array of target device IDs with active sessions
|
|
31
|
+
*/
|
|
32
|
+
export declare function listPersistedSessions(deviceId: string): string[];
|
|
33
|
+
//# sourceMappingURL=sessionPersistence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionPersistence.d.ts","sourceRoot":"","sources":["../../src/crypto/sessionPersistence.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAyBtC;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,WAAW,EAAE,WAAW,GACvB,IAAI,CAeN;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GACrB,WAAW,GAAG,IAAI,CA6BpB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GACrB,IAAI,CAUN;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAgBjE;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBhE"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.persistSessionKey = persistSessionKey;
|
|
37
|
+
exports.loadPersistedSessionKey = loadPersistedSessionKey;
|
|
38
|
+
exports.deletePersistedSession = deletePersistedSession;
|
|
39
|
+
exports.deleteAllPersistedSessions = deleteAllPersistedSessions;
|
|
40
|
+
exports.listPersistedSessions = listPersistedSessions;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
/**
|
|
45
|
+
* Session Persistence
|
|
46
|
+
* Stores session keys to disk so they survive reconnections after IP changes
|
|
47
|
+
*/
|
|
48
|
+
const SESSION_STORE_DIR = path.join(os.homedir(), '.forkoff-cli', 'sessions');
|
|
49
|
+
/**
|
|
50
|
+
* Ensures the session store directory exists
|
|
51
|
+
*/
|
|
52
|
+
function ensureSessionStoreExists() {
|
|
53
|
+
if (!fs.existsSync(SESSION_STORE_DIR)) {
|
|
54
|
+
fs.mkdirSync(SESSION_STORE_DIR, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Gets the file path for a device's session
|
|
59
|
+
*/
|
|
60
|
+
function getSessionFilePath(deviceId, targetDeviceId) {
|
|
61
|
+
return path.join(SESSION_STORE_DIR, `${deviceId}-${targetDeviceId}.json`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Persists a session key to disk
|
|
65
|
+
* @param deviceId - Current device ID
|
|
66
|
+
* @param targetDeviceId - Target device ID
|
|
67
|
+
* @param sessionKeys - Session encryption keys
|
|
68
|
+
*/
|
|
69
|
+
function persistSessionKey(deviceId, targetDeviceId, sessionKeys) {
|
|
70
|
+
try {
|
|
71
|
+
ensureSessionStoreExists();
|
|
72
|
+
const data = {
|
|
73
|
+
encryptionKey: Array.from(sessionKeys.encryptionKey), // Convert Uint8Array to Array for JSON
|
|
74
|
+
sessionId: sessionKeys.sessionId,
|
|
75
|
+
timestamp: new Date().toISOString(),
|
|
76
|
+
};
|
|
77
|
+
const filePath = getSessionFilePath(deviceId, targetDeviceId);
|
|
78
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
console.error('Failed to persist session key:', error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Loads a persisted session key from disk
|
|
86
|
+
* @param deviceId - Current device ID
|
|
87
|
+
* @param targetDeviceId - Target device ID
|
|
88
|
+
* @returns SessionKeys or null if not found
|
|
89
|
+
*/
|
|
90
|
+
function loadPersistedSessionKey(deviceId, targetDeviceId) {
|
|
91
|
+
try {
|
|
92
|
+
const filePath = getSessionFilePath(deviceId, targetDeviceId);
|
|
93
|
+
if (!fs.existsSync(filePath)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
97
|
+
// Check if session is expired (older than 24 hours)
|
|
98
|
+
const timestamp = new Date(data.timestamp);
|
|
99
|
+
const now = new Date();
|
|
100
|
+
const hoursSinceCreation = (now.getTime() - timestamp.getTime()) / (1000 * 60 * 60);
|
|
101
|
+
if (hoursSinceCreation > 24) {
|
|
102
|
+
// Session expired, delete it
|
|
103
|
+
fs.unlinkSync(filePath);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
encryptionKey: new Uint8Array(data.encryptionKey),
|
|
108
|
+
sessionId: data.sessionId,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
console.error('Failed to load persisted session key:', error);
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Deletes a persisted session
|
|
118
|
+
* @param deviceId - Current device ID
|
|
119
|
+
* @param targetDeviceId - Target device ID
|
|
120
|
+
*/
|
|
121
|
+
function deletePersistedSession(deviceId, targetDeviceId) {
|
|
122
|
+
try {
|
|
123
|
+
const filePath = getSessionFilePath(deviceId, targetDeviceId);
|
|
124
|
+
if (fs.existsSync(filePath)) {
|
|
125
|
+
fs.unlinkSync(filePath);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
console.error('Failed to delete persisted session:', error);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Deletes all persisted sessions for a device
|
|
134
|
+
* @param deviceId - Current device ID
|
|
135
|
+
*/
|
|
136
|
+
function deleteAllPersistedSessions(deviceId) {
|
|
137
|
+
try {
|
|
138
|
+
if (!fs.existsSync(SESSION_STORE_DIR)) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const files = fs.readdirSync(SESSION_STORE_DIR);
|
|
142
|
+
for (const file of files) {
|
|
143
|
+
if (file.startsWith(`${deviceId}-`)) {
|
|
144
|
+
fs.unlinkSync(path.join(SESSION_STORE_DIR, file));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error('Failed to delete all persisted sessions:', error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Lists all persisted sessions for a device
|
|
154
|
+
* @param deviceId - Current device ID
|
|
155
|
+
* @returns Array of target device IDs with active sessions
|
|
156
|
+
*/
|
|
157
|
+
function listPersistedSessions(deviceId) {
|
|
158
|
+
try {
|
|
159
|
+
if (!fs.existsSync(SESSION_STORE_DIR)) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
const files = fs.readdirSync(SESSION_STORE_DIR);
|
|
163
|
+
const prefix = `${deviceId}-`;
|
|
164
|
+
return files
|
|
165
|
+
.filter((file) => file.startsWith(prefix) && file.endsWith('.json'))
|
|
166
|
+
.map((file) => file.substring(prefix.length, file.length - 5)); // Remove prefix and .json
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
console.error('Failed to list persisted sessions:', error);
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=sessionPersistence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionPersistence.js","sourceRoot":"","sources":["../../src/crypto/sessionPersistence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2EE Type Definitions for ForkOff CLI
|
|
3
|
+
*
|
|
4
|
+
* X25519 key exchange + AES-256-GCM encryption
|
|
5
|
+
*/
|
|
6
|
+
export interface E2EEKeyPair {
|
|
7
|
+
publicKey: string;
|
|
8
|
+
privateKey: string;
|
|
9
|
+
}
|
|
10
|
+
export interface EncryptedPayload {
|
|
11
|
+
ciphertext: string;
|
|
12
|
+
nonce: string;
|
|
13
|
+
authTag: string;
|
|
14
|
+
}
|
|
15
|
+
export interface EncryptedMessage {
|
|
16
|
+
senderDeviceId: string;
|
|
17
|
+
recipientDeviceId: string;
|
|
18
|
+
sessionId: string;
|
|
19
|
+
payload: EncryptedPayload;
|
|
20
|
+
messageCounter: number;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
}
|
|
23
|
+
export interface SessionKeys {
|
|
24
|
+
encryptionKey: Uint8Array;
|
|
25
|
+
sessionId: string;
|
|
26
|
+
}
|
|
27
|
+
export interface KeyExchangeInit {
|
|
28
|
+
senderDeviceId: string;
|
|
29
|
+
ephemeralPublicKey: string;
|
|
30
|
+
}
|
|
31
|
+
export interface KeyExchangeAck {
|
|
32
|
+
recipientDeviceId: string;
|
|
33
|
+
ephemeralPublicKey: string;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/crypto/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,UAAU,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/crypto/types.ts"],"names":[],"mappings":";AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { WebSocketClient } from '../websocket';
|
|
2
|
+
/**
|
|
3
|
+
* WebSocket E2EE Integration
|
|
4
|
+
* Adds end-to-end encryption capabilities to WebSocket client
|
|
5
|
+
*/
|
|
6
|
+
export declare class WebSocketE2EEIntegration {
|
|
7
|
+
private wsClient;
|
|
8
|
+
private e2eeManager;
|
|
9
|
+
private enabled;
|
|
10
|
+
constructor(wsClient: WebSocketClient);
|
|
11
|
+
/**
|
|
12
|
+
* Initializes E2EE and sets up event handlers
|
|
13
|
+
*/
|
|
14
|
+
initialize(deviceId: string, apiUrl: string, authToken: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Sets up WebSocket event handlers for E2EE
|
|
17
|
+
*/
|
|
18
|
+
private setupEventHandlers;
|
|
19
|
+
/**
|
|
20
|
+
* Initiates key exchange with a target device
|
|
21
|
+
*/
|
|
22
|
+
initiateKeyExchange(targetDeviceId: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Encrypts and sends a message to a target device
|
|
25
|
+
*/
|
|
26
|
+
sendEncryptedMessage(plaintext: string, targetDeviceId: string, sessionId: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Checks if E2EE session exists for a device
|
|
29
|
+
*/
|
|
30
|
+
hasSession(deviceId: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Checks if E2EE is enabled
|
|
33
|
+
*/
|
|
34
|
+
isEnabled(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Cleans up E2EE sessions
|
|
37
|
+
*/
|
|
38
|
+
cleanup(): void;
|
|
39
|
+
private emitKeyExchangeInit;
|
|
40
|
+
private emitKeyExchangeAck;
|
|
41
|
+
private emitEncryptedMessage;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Factory function to create E2EE-enabled WebSocket client
|
|
45
|
+
*/
|
|
46
|
+
export declare function createE2EEWebSocketClient(wsClient: WebSocketClient, deviceId: string, apiUrl: string, authToken: string): Promise<WebSocketE2EEIntegration>;
|
|
47
|
+
//# sourceMappingURL=websocketE2EE.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websocketE2EE.d.ts","sourceRoot":"","sources":["../../src/crypto/websocketE2EE.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAI/C;;;GAGG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,OAAO,CAAS;gBAEZ,QAAQ,EAAE,eAAe;IAIrC;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpF;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA6D1B;;OAEG;IACG,mBAAmB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWhE;;OAEG;IACH,oBAAoB,CAClB,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,GAChB,IAAI;IAqBP;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIrC;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,oBAAoB;CAG7B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,wBAAwB,CAAC,CAGnC"}
|