@massalabs/gossip-sdk 0.0.2-dev.20260128094509 → 0.0.2-dev.20260128111120
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/dist/api/messageProtocol/index.d.ts +19 -0
- package/dist/api/messageProtocol/index.js +26 -0
- package/dist/api/messageProtocol/mock.d.ts +12 -0
- package/{src/api/messageProtocol/mock.ts → dist/api/messageProtocol/mock.js} +2 -3
- package/dist/api/messageProtocol/rest.d.ts +22 -0
- package/dist/api/messageProtocol/rest.js +161 -0
- package/dist/api/messageProtocol/types.d.ts +61 -0
- package/dist/api/messageProtocol/types.js +6 -0
- package/dist/assets/generated/wasm/README.md +281 -0
- package/dist/assets/generated/wasm/gossip_wasm.d.ts +498 -0
- package/dist/assets/generated/wasm/gossip_wasm.js +1399 -0
- package/dist/assets/generated/wasm/gossip_wasm_bg.wasm +0 -0
- package/dist/assets/generated/wasm/gossip_wasm_bg.wasm.d.ts +68 -0
- package/dist/assets/generated/wasm/package.json +15 -0
- package/dist/config/protocol.d.ts +36 -0
- package/dist/config/protocol.js +77 -0
- package/dist/config/sdk.d.ts +82 -0
- package/dist/config/sdk.js +55 -0
- package/{src/contacts.ts → dist/contacts.d.ts} +10 -94
- package/dist/contacts.js +166 -0
- package/dist/core/SdkEventEmitter.d.ts +36 -0
- package/dist/core/SdkEventEmitter.js +59 -0
- package/dist/core/SdkPolling.d.ts +35 -0
- package/dist/core/SdkPolling.js +100 -0
- package/{src/core/index.ts → dist/core/index.d.ts} +0 -2
- package/dist/core/index.js +5 -0
- package/dist/crypto/bip39.d.ts +34 -0
- package/dist/crypto/bip39.js +62 -0
- package/dist/crypto/encryption.d.ts +37 -0
- package/dist/crypto/encryption.js +46 -0
- package/dist/db.d.ts +190 -0
- package/dist/db.js +311 -0
- package/dist/gossipSdk.d.ts +274 -0
- package/dist/gossipSdk.js +690 -0
- package/dist/index.d.ts +73 -0
- package/dist/index.js +77 -0
- package/dist/services/announcement.d.ts +43 -0
- package/dist/services/announcement.js +491 -0
- package/dist/services/auth.d.ts +37 -0
- package/dist/services/auth.js +76 -0
- package/dist/services/discussion.d.ts +63 -0
- package/dist/services/discussion.js +297 -0
- package/dist/services/message.d.ts +74 -0
- package/dist/services/message.js +826 -0
- package/dist/services/refresh.d.ts +41 -0
- package/dist/services/refresh.js +205 -0
- package/{src/sw.ts → dist/sw.d.ts} +1 -8
- package/dist/sw.js +10 -0
- package/dist/types/events.d.ts +80 -0
- package/dist/types/events.js +7 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.js +7 -0
- package/dist/utils/base64.d.ts +10 -0
- package/dist/utils/base64.js +30 -0
- package/dist/utils/contacts.d.ts +42 -0
- package/dist/utils/contacts.js +113 -0
- package/dist/utils/discussions.d.ts +24 -0
- package/dist/utils/discussions.js +38 -0
- package/dist/utils/logs.d.ts +19 -0
- package/dist/utils/logs.js +89 -0
- package/dist/utils/messageSerialization.d.ts +64 -0
- package/dist/utils/messageSerialization.js +184 -0
- package/dist/utils/queue.d.ts +50 -0
- package/dist/utils/queue.js +110 -0
- package/dist/utils/type.d.ts +10 -0
- package/dist/utils/type.js +4 -0
- package/dist/utils/userId.d.ts +40 -0
- package/dist/utils/userId.js +90 -0
- package/dist/utils/validation.d.ts +50 -0
- package/dist/utils/validation.js +112 -0
- package/dist/utils.d.ts +30 -0
- package/{src/utils.ts → dist/utils.js} +9 -19
- package/dist/wasm/encryption.d.ts +56 -0
- package/{src/wasm/encryption.ts → dist/wasm/encryption.js} +22 -51
- package/dist/wasm/index.d.ts +10 -0
- package/{src/wasm/index.ts → dist/wasm/index.js} +1 -8
- package/dist/wasm/loader.d.ts +21 -0
- package/dist/wasm/loader.js +103 -0
- package/dist/wasm/session.d.ts +85 -0
- package/dist/wasm/session.js +226 -0
- package/dist/wasm/userKeys.d.ts +17 -0
- package/{src/wasm/userKeys.ts → dist/wasm/userKeys.js} +6 -13
- package/package.json +5 -1
- package/src/api/messageProtocol/index.ts +0 -53
- package/src/api/messageProtocol/rest.ts +0 -209
- package/src/api/messageProtocol/types.ts +0 -70
- package/src/config/protocol.ts +0 -97
- package/src/config/sdk.ts +0 -131
- package/src/core/SdkEventEmitter.ts +0 -91
- package/src/core/SdkPolling.ts +0 -134
- package/src/crypto/bip39.ts +0 -84
- package/src/crypto/encryption.ts +0 -77
- package/src/db.ts +0 -465
- package/src/gossipSdk.ts +0 -994
- package/src/index.ts +0 -211
- package/src/services/announcement.ts +0 -653
- package/src/services/auth.ts +0 -95
- package/src/services/discussion.ts +0 -380
- package/src/services/message.ts +0 -1055
- package/src/services/refresh.ts +0 -234
- package/src/types/events.ts +0 -108
- package/src/types.ts +0 -70
- package/src/utils/base64.ts +0 -39
- package/src/utils/contacts.ts +0 -161
- package/src/utils/discussions.ts +0 -55
- package/src/utils/logs.ts +0 -86
- package/src/utils/messageSerialization.ts +0 -257
- package/src/utils/queue.ts +0 -106
- package/src/utils/type.ts +0 -7
- package/src/utils/userId.ts +0 -114
- package/src/utils/validation.ts +0 -144
- package/src/wasm/loader.ts +0 -123
- package/src/wasm/session.ts +0 -276
- package/test/config/protocol.spec.ts +0 -31
- package/test/config/sdk.spec.ts +0 -163
- package/test/db/helpers.spec.ts +0 -142
- package/test/db/operations.spec.ts +0 -128
- package/test/db/states.spec.ts +0 -535
- package/test/integration/discussion-flow.spec.ts +0 -422
- package/test/integration/messaging-flow.spec.ts +0 -708
- package/test/integration/sdk-lifecycle.spec.ts +0 -325
- package/test/mocks/index.ts +0 -9
- package/test/mocks/mockMessageProtocol.ts +0 -100
- package/test/services/auth.spec.ts +0 -311
- package/test/services/discussion.spec.ts +0 -279
- package/test/services/message-deduplication.spec.ts +0 -299
- package/test/services/message-startup.spec.ts +0 -331
- package/test/services/message.spec.ts +0 -817
- package/test/services/refresh.spec.ts +0 -199
- package/test/services/session-status.spec.ts +0 -349
- package/test/session/wasm.spec.ts +0 -227
- package/test/setup.ts +0 -52
- package/test/utils/contacts.spec.ts +0 -156
- package/test/utils/discussions.spec.ts +0 -66
- package/test/utils/queue.spec.ts +0 -52
- package/test/utils/serialization.spec.ts +0 -120
- package/test/utils/userId.spec.ts +0 -120
- package/test/utils/validation.spec.ts +0 -223
- package/test/utils.ts +0 -212
- package/tsconfig.json +0 -26
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -28
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions for validating user input like usernames, passwords, and user IDs.
|
|
5
|
+
*/
|
|
6
|
+
import { type GossipDatabase } from '../db';
|
|
7
|
+
export type ValidationResult = {
|
|
8
|
+
valid: true;
|
|
9
|
+
error?: never;
|
|
10
|
+
} | {
|
|
11
|
+
valid: false;
|
|
12
|
+
error: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Validate a password meets requirements
|
|
16
|
+
*
|
|
17
|
+
* @param value - The password to validate
|
|
18
|
+
* @returns Validation result
|
|
19
|
+
*/
|
|
20
|
+
export declare function validatePassword(value: string): ValidationResult;
|
|
21
|
+
/**
|
|
22
|
+
* Validate a username format (without checking availability)
|
|
23
|
+
*
|
|
24
|
+
* @param value - The username to validate
|
|
25
|
+
* @returns Validation result
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateUsernameFormat(value: string): ValidationResult;
|
|
28
|
+
/**
|
|
29
|
+
* Validate a username is available (not already in use)
|
|
30
|
+
*
|
|
31
|
+
* @param value - The username to check
|
|
32
|
+
* @param db - Database instance
|
|
33
|
+
* @returns Validation result
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateUsernameAvailability(value: string, db: GossipDatabase): Promise<ValidationResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Validate a username format and availability
|
|
38
|
+
*
|
|
39
|
+
* @param value - The username to validate
|
|
40
|
+
* @param db - Database instance
|
|
41
|
+
* @returns Validation result
|
|
42
|
+
*/
|
|
43
|
+
export declare function validateUsernameFormatAndAvailability(value: string, db: GossipDatabase): Promise<ValidationResult>;
|
|
44
|
+
/**
|
|
45
|
+
* Validate a user ID format (Bech32 gossip1... format)
|
|
46
|
+
*
|
|
47
|
+
* @param value - The user ID to validate
|
|
48
|
+
* @returns Validation result
|
|
49
|
+
*/
|
|
50
|
+
export declare function validateUserIdFormat(value: string): ValidationResult;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions for validating user input like usernames, passwords, and user IDs.
|
|
5
|
+
*/
|
|
6
|
+
import { isValidUserId } from './userId';
|
|
7
|
+
/**
|
|
8
|
+
* Validate a password meets requirements
|
|
9
|
+
*
|
|
10
|
+
* @param value - The password to validate
|
|
11
|
+
* @returns Validation result
|
|
12
|
+
*/
|
|
13
|
+
export function validatePassword(value) {
|
|
14
|
+
if (!value || value.trim().length === 0) {
|
|
15
|
+
return { valid: false, error: 'Password is required' };
|
|
16
|
+
}
|
|
17
|
+
if (value.length < 8) {
|
|
18
|
+
return {
|
|
19
|
+
valid: false,
|
|
20
|
+
error: 'Password must be at least 8 characters long',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
return { valid: true };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Validate a username format (without checking availability)
|
|
27
|
+
*
|
|
28
|
+
* @param value - The username to validate
|
|
29
|
+
* @returns Validation result
|
|
30
|
+
*/
|
|
31
|
+
export function validateUsernameFormat(value) {
|
|
32
|
+
const trimmed = value.trim();
|
|
33
|
+
if (!trimmed) {
|
|
34
|
+
return { valid: false, error: 'Username is required' };
|
|
35
|
+
}
|
|
36
|
+
// Disallow any whitespace inside the username (single token only)
|
|
37
|
+
if (/\s/.test(trimmed)) {
|
|
38
|
+
return {
|
|
39
|
+
valid: false,
|
|
40
|
+
error: 'Username cannot contain spaces',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (trimmed.length < 3) {
|
|
44
|
+
return {
|
|
45
|
+
valid: false,
|
|
46
|
+
error: 'Username must be at least 3 characters long',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return { valid: true };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Validate a username is available (not already in use)
|
|
53
|
+
*
|
|
54
|
+
* @param value - The username to check
|
|
55
|
+
* @param db - Database instance
|
|
56
|
+
* @returns Validation result
|
|
57
|
+
*/
|
|
58
|
+
export async function validateUsernameAvailability(value, db) {
|
|
59
|
+
try {
|
|
60
|
+
if (!db.isOpen()) {
|
|
61
|
+
await db.open();
|
|
62
|
+
}
|
|
63
|
+
const existingProfile = await db.userProfile
|
|
64
|
+
.filter((profile) => profile.username.trim().toLowerCase() === value.trim().toLowerCase())
|
|
65
|
+
.first();
|
|
66
|
+
if (existingProfile) {
|
|
67
|
+
return {
|
|
68
|
+
valid: false,
|
|
69
|
+
error: 'This username is already in use. Please choose another.',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return { valid: true };
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
valid: false,
|
|
77
|
+
error: error instanceof Error
|
|
78
|
+
? error.message
|
|
79
|
+
: 'Unable to verify username availability. Please try again.',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Validate a username format and availability
|
|
85
|
+
*
|
|
86
|
+
* @param value - The username to validate
|
|
87
|
+
* @param db - Database instance
|
|
88
|
+
* @returns Validation result
|
|
89
|
+
*/
|
|
90
|
+
export async function validateUsernameFormatAndAvailability(value, db) {
|
|
91
|
+
const result = validateUsernameFormat(value);
|
|
92
|
+
if (!result.valid) {
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
return await validateUsernameAvailability(value, db);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Validate a user ID format (Bech32 gossip1... format)
|
|
99
|
+
*
|
|
100
|
+
* @param value - The user ID to validate
|
|
101
|
+
* @returns Validation result
|
|
102
|
+
*/
|
|
103
|
+
export function validateUserIdFormat(value) {
|
|
104
|
+
const userId = value.trim();
|
|
105
|
+
if (!isValidUserId(userId)) {
|
|
106
|
+
return {
|
|
107
|
+
valid: false,
|
|
108
|
+
error: 'Invalid format — must be a valid user ID',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return { valid: true };
|
|
112
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for SDK configuration.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { configureSdk } from 'gossip-sdk';
|
|
9
|
+
*
|
|
10
|
+
* configureSdk({
|
|
11
|
+
* db,
|
|
12
|
+
* protocolBaseUrl: 'https://api.example.com',
|
|
13
|
+
* });
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import type { GossipDatabase } from './db';
|
|
17
|
+
export interface SdkRuntimeConfig {
|
|
18
|
+
db?: GossipDatabase;
|
|
19
|
+
protocolBaseUrl?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configure runtime adapters for the SDK.
|
|
23
|
+
* Call this once during application startup.
|
|
24
|
+
*
|
|
25
|
+
* This also starts WASM initialization in the background.
|
|
26
|
+
*
|
|
27
|
+
* Note: Service instances (MessageService, AnnouncementService, etc.)
|
|
28
|
+
* should be created by the app with the required dependencies.
|
|
29
|
+
*/
|
|
30
|
+
export declare function configureSdk(config: SdkRuntimeConfig): void;
|
|
@@ -13,17 +13,9 @@
|
|
|
13
13
|
* });
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
import type { GossipDatabase } from './db';
|
|
18
16
|
import { setDb } from './db';
|
|
19
17
|
import { startWasmInitialization } from './wasm/loader';
|
|
20
18
|
import { setProtocolBaseUrl } from './config/protocol';
|
|
21
|
-
|
|
22
|
-
export interface SdkRuntimeConfig {
|
|
23
|
-
db?: GossipDatabase;
|
|
24
|
-
protocolBaseUrl?: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
19
|
/**
|
|
28
20
|
* Configure runtime adapters for the SDK.
|
|
29
21
|
* Call this once during application startup.
|
|
@@ -33,15 +25,13 @@ export interface SdkRuntimeConfig {
|
|
|
33
25
|
* Note: Service instances (MessageService, AnnouncementService, etc.)
|
|
34
26
|
* should be created by the app with the required dependencies.
|
|
35
27
|
*/
|
|
36
|
-
export function configureSdk(config
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Start WASM initialization in the background (non-blocking)
|
|
46
|
-
startWasmInitialization();
|
|
28
|
+
export function configureSdk(config) {
|
|
29
|
+
if (config.db) {
|
|
30
|
+
setDb(config.db);
|
|
31
|
+
}
|
|
32
|
+
if (config.protocolBaseUrl) {
|
|
33
|
+
setProtocolBaseUrl(config.protocolBaseUrl);
|
|
34
|
+
}
|
|
35
|
+
// Start WASM initialization in the background (non-blocking)
|
|
36
|
+
startWasmInitialization();
|
|
47
37
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encryption, Keys, and AEAD Support
|
|
3
|
+
*
|
|
4
|
+
* This file provides proxy functions for EncryptionKey, Nonce classes,
|
|
5
|
+
* and AEAD (Authenticated Encryption with Additional Data) operations,
|
|
6
|
+
* ensuring proper initialization before calling any WASM functions.
|
|
7
|
+
*/
|
|
8
|
+
import { EncryptionKey, Nonce } from '../assets/generated/wasm/gossip_wasm';
|
|
9
|
+
export { EncryptionKey, Nonce };
|
|
10
|
+
/**
|
|
11
|
+
* Generate a new random encryption key (64 bytes)
|
|
12
|
+
* This ensures WASM is initialized before calling
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateEncryptionKey(): Promise<EncryptionKey>;
|
|
15
|
+
/**
|
|
16
|
+
* Generate a deterministic encryption key (64 bytes) from a seed string.
|
|
17
|
+
* This ensures WASM is initialized before calling.
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateEncryptionKeyFromSeed(seed: string, salt: Uint8Array): Promise<EncryptionKey>;
|
|
20
|
+
/**
|
|
21
|
+
* Create an encryption key from raw bytes (must be 64 bytes)
|
|
22
|
+
* This ensures WASM is initialized before calling
|
|
23
|
+
*/
|
|
24
|
+
export declare function encryptionKeyFromBytes(bytes: Uint8Array): Promise<EncryptionKey>;
|
|
25
|
+
/**
|
|
26
|
+
* Generate a new random nonce (16 bytes)
|
|
27
|
+
* This ensures WASM is initialized before calling
|
|
28
|
+
*/
|
|
29
|
+
export declare function generateNonce(): Promise<Nonce>;
|
|
30
|
+
/**
|
|
31
|
+
* Create a nonce from raw bytes (must be 16 bytes)
|
|
32
|
+
* This ensures WASM is initialized before calling
|
|
33
|
+
*/
|
|
34
|
+
export declare function nonceFromBytes(bytes: Uint8Array): Promise<Nonce>;
|
|
35
|
+
/**
|
|
36
|
+
* Encrypt data using AES-256-SIV authenticated encryption
|
|
37
|
+
* This ensures WASM is initialized before calling
|
|
38
|
+
*
|
|
39
|
+
* @param key - The encryption key (64 bytes)
|
|
40
|
+
* @param nonce - The nonce (16 bytes, should be unique per encryption)
|
|
41
|
+
* @param plaintext - The data to encrypt
|
|
42
|
+
* @param aad - Additional authenticated data (not encrypted, but authenticated)
|
|
43
|
+
* @returns The ciphertext with authentication tag appended
|
|
44
|
+
*/
|
|
45
|
+
export declare function encryptAead(key: EncryptionKey, nonce: Nonce, plaintext: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
|
|
46
|
+
/**
|
|
47
|
+
* Decrypt data using AES-256-SIV authenticated encryption
|
|
48
|
+
* This ensures WASM is initialized before calling
|
|
49
|
+
*
|
|
50
|
+
* @param key - The encryption key (64 bytes, must match encryption key)
|
|
51
|
+
* @param nonce - The nonce (16 bytes, must match encryption nonce)
|
|
52
|
+
* @param ciphertext - The encrypted data with authentication tag
|
|
53
|
+
* @param aad - Additional authenticated data (must match encryption AAD)
|
|
54
|
+
* @returns The decrypted plaintext, or undefined if authentication fails
|
|
55
|
+
*/
|
|
56
|
+
export declare function decryptAead(key: EncryptionKey, nonce: Nonce, ciphertext: Uint8Array, aad: Uint8Array): Promise<Uint8Array | undefined>;
|
|
@@ -5,68 +5,50 @@
|
|
|
5
5
|
* and AEAD (Authenticated Encryption with Additional Data) operations,
|
|
6
6
|
* ensuring proper initialization before calling any WASM functions.
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
8
|
import { ensureWasmInitialized } from './loader';
|
|
10
|
-
import {
|
|
11
|
-
EncryptionKey,
|
|
12
|
-
Nonce,
|
|
13
|
-
aead_encrypt as _aead_encrypt,
|
|
14
|
-
aead_decrypt as _aead_decrypt,
|
|
15
|
-
} from '../assets/generated/wasm/gossip_wasm';
|
|
16
|
-
|
|
9
|
+
import { EncryptionKey, Nonce, aead_encrypt as _aead_encrypt, aead_decrypt as _aead_decrypt, } from '../assets/generated/wasm/gossip_wasm';
|
|
17
10
|
// Re-export classes
|
|
18
11
|
export { EncryptionKey, Nonce };
|
|
19
|
-
|
|
20
12
|
/**
|
|
21
13
|
* Generate a new random encryption key (64 bytes)
|
|
22
14
|
* This ensures WASM is initialized before calling
|
|
23
15
|
*/
|
|
24
|
-
export async function generateEncryptionKey()
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
export async function generateEncryptionKey() {
|
|
17
|
+
await ensureWasmInitialized();
|
|
18
|
+
return EncryptionKey.generate();
|
|
27
19
|
}
|
|
28
|
-
|
|
29
20
|
/**
|
|
30
21
|
* Generate a deterministic encryption key (64 bytes) from a seed string.
|
|
31
22
|
* This ensures WASM is initialized before calling.
|
|
32
23
|
*/
|
|
33
|
-
export async function generateEncryptionKeyFromSeed(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
): Promise<EncryptionKey> {
|
|
37
|
-
await ensureWasmInitialized();
|
|
38
|
-
return EncryptionKey.from_seed(seed, salt);
|
|
24
|
+
export async function generateEncryptionKeyFromSeed(seed, salt) {
|
|
25
|
+
await ensureWasmInitialized();
|
|
26
|
+
return EncryptionKey.from_seed(seed, salt);
|
|
39
27
|
}
|
|
40
|
-
|
|
41
28
|
/**
|
|
42
29
|
* Create an encryption key from raw bytes (must be 64 bytes)
|
|
43
30
|
* This ensures WASM is initialized before calling
|
|
44
31
|
*/
|
|
45
|
-
export async function encryptionKeyFromBytes(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
await ensureWasmInitialized();
|
|
49
|
-
return EncryptionKey.from_bytes(bytes);
|
|
32
|
+
export async function encryptionKeyFromBytes(bytes) {
|
|
33
|
+
await ensureWasmInitialized();
|
|
34
|
+
return EncryptionKey.from_bytes(bytes);
|
|
50
35
|
}
|
|
51
|
-
|
|
52
36
|
/**
|
|
53
37
|
* Generate a new random nonce (16 bytes)
|
|
54
38
|
* This ensures WASM is initialized before calling
|
|
55
39
|
*/
|
|
56
|
-
export async function generateNonce()
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
export async function generateNonce() {
|
|
41
|
+
await ensureWasmInitialized();
|
|
42
|
+
return Nonce.generate();
|
|
59
43
|
}
|
|
60
|
-
|
|
61
44
|
/**
|
|
62
45
|
* Create a nonce from raw bytes (must be 16 bytes)
|
|
63
46
|
* This ensures WASM is initialized before calling
|
|
64
47
|
*/
|
|
65
|
-
export async function nonceFromBytes(bytes
|
|
66
|
-
|
|
67
|
-
|
|
48
|
+
export async function nonceFromBytes(bytes) {
|
|
49
|
+
await ensureWasmInitialized();
|
|
50
|
+
return Nonce.from_bytes(bytes);
|
|
68
51
|
}
|
|
69
|
-
|
|
70
52
|
/**
|
|
71
53
|
* Encrypt data using AES-256-SIV authenticated encryption
|
|
72
54
|
* This ensures WASM is initialized before calling
|
|
@@ -77,16 +59,10 @@ export async function nonceFromBytes(bytes: Uint8Array): Promise<Nonce> {
|
|
|
77
59
|
* @param aad - Additional authenticated data (not encrypted, but authenticated)
|
|
78
60
|
* @returns The ciphertext with authentication tag appended
|
|
79
61
|
*/
|
|
80
|
-
export async function encryptAead(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
plaintext: Uint8Array,
|
|
84
|
-
aad: Uint8Array
|
|
85
|
-
): Promise<Uint8Array> {
|
|
86
|
-
await ensureWasmInitialized();
|
|
87
|
-
return _aead_encrypt(key, nonce, plaintext, aad);
|
|
62
|
+
export async function encryptAead(key, nonce, plaintext, aad) {
|
|
63
|
+
await ensureWasmInitialized();
|
|
64
|
+
return _aead_encrypt(key, nonce, plaintext, aad);
|
|
88
65
|
}
|
|
89
|
-
|
|
90
66
|
/**
|
|
91
67
|
* Decrypt data using AES-256-SIV authenticated encryption
|
|
92
68
|
* This ensures WASM is initialized before calling
|
|
@@ -97,12 +73,7 @@ export async function encryptAead(
|
|
|
97
73
|
* @param aad - Additional authenticated data (must match encryption AAD)
|
|
98
74
|
* @returns The decrypted plaintext, or undefined if authentication fails
|
|
99
75
|
*/
|
|
100
|
-
export async function decryptAead(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
ciphertext: Uint8Array,
|
|
104
|
-
aad: Uint8Array
|
|
105
|
-
): Promise<Uint8Array | undefined> {
|
|
106
|
-
await ensureWasmInitialized();
|
|
107
|
-
return _aead_decrypt(key, nonce, ciphertext, aad);
|
|
76
|
+
export async function decryptAead(key, nonce, ciphertext, aad) {
|
|
77
|
+
await ensureWasmInitialized();
|
|
78
|
+
return _aead_decrypt(key, nonce, ciphertext, aad);
|
|
108
79
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM Module Exports
|
|
3
|
+
*
|
|
4
|
+
* This file provides a clean interface for importing WASM modules
|
|
5
|
+
* and related functionality.
|
|
6
|
+
*/
|
|
7
|
+
export { SessionModule, sessionStatusToString } from './session';
|
|
8
|
+
export { initializeWasm, ensureWasmInitialized, startWasmInitialization, } from './loader';
|
|
9
|
+
export * from './encryption';
|
|
10
|
+
export * from './userKeys';
|
|
@@ -4,17 +4,10 @@
|
|
|
4
4
|
* This file provides a clean interface for importing WASM modules
|
|
5
5
|
* and related functionality.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
7
|
// Export modules
|
|
9
8
|
export { SessionModule, sessionStatusToString } from './session';
|
|
10
|
-
|
|
11
9
|
// Export initialization functions
|
|
12
|
-
export {
|
|
13
|
-
initializeWasm,
|
|
14
|
-
ensureWasmInitialized,
|
|
15
|
-
startWasmInitialization,
|
|
16
|
-
} from './loader';
|
|
17
|
-
|
|
10
|
+
export { initializeWasm, ensureWasmInitialized, startWasmInitialization, } from './loader';
|
|
18
11
|
// Export specialized WASM functionality
|
|
19
12
|
export * from './encryption';
|
|
20
13
|
export * from './userKeys';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM Module Loader and Initialization Service
|
|
3
|
+
*
|
|
4
|
+
* This file handles both WASM core initialization and module loading.
|
|
5
|
+
* It ensures WASM modules are initialized once and properly throughout
|
|
6
|
+
* the application lifecycle.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Initialize WASM modules if not already initialized
|
|
10
|
+
* This function is idempotent - safe to call multiple times
|
|
11
|
+
*/
|
|
12
|
+
export declare function initializeWasm(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Ensure WASM is initialized, throwing an error if initialization failed
|
|
15
|
+
*/
|
|
16
|
+
export declare function ensureWasmInitialized(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Start WASM initialization in the background.
|
|
19
|
+
* Call this early in the app lifecycle (for example in main.tsx).
|
|
20
|
+
*/
|
|
21
|
+
export declare function startWasmInitialization(): void;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM Module Loader and Initialization Service
|
|
3
|
+
*
|
|
4
|
+
* This file handles both WASM core initialization and module loading.
|
|
5
|
+
* It ensures WASM modules are initialized once and properly throughout
|
|
6
|
+
* the application lifecycle.
|
|
7
|
+
*/
|
|
8
|
+
import init from '../assets/generated/wasm/gossip_wasm';
|
|
9
|
+
/**
|
|
10
|
+
* Check if we're running in Node.js environment
|
|
11
|
+
*/
|
|
12
|
+
function isNodeEnvironment() {
|
|
13
|
+
return (typeof process !== 'undefined' &&
|
|
14
|
+
process.versions != null &&
|
|
15
|
+
process.versions.node != null);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Load WASM module for Node.js environment using fs.readFileSync
|
|
19
|
+
*/
|
|
20
|
+
async function loadWasmForNode() {
|
|
21
|
+
// Dynamic import to avoid bundling Node.js modules in browser builds
|
|
22
|
+
const fs = await import('node:fs');
|
|
23
|
+
const path = await import('node:path');
|
|
24
|
+
const { fileURLToPath } = await import('node:url');
|
|
25
|
+
// Get the directory of the current module
|
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
const __dirname = path.dirname(__filename);
|
|
28
|
+
// Resolve path to WASM file - WASM is in the SDK's generated folder
|
|
29
|
+
const wasmPath = path.resolve(__dirname, '../assets/generated/wasm/gossip_wasm_bg.wasm');
|
|
30
|
+
// Read WASM file as binary
|
|
31
|
+
const wasmBuffer = fs.readFileSync(wasmPath);
|
|
32
|
+
// Instantiate WASM module
|
|
33
|
+
const wasmModule = await WebAssembly.compile(wasmBuffer);
|
|
34
|
+
return wasmModule;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* WASM Initialization State
|
|
38
|
+
*/
|
|
39
|
+
let isInitializing = false;
|
|
40
|
+
let isInitialized = false;
|
|
41
|
+
let initializationPromise = null;
|
|
42
|
+
let initError = null;
|
|
43
|
+
/**
|
|
44
|
+
* Initialize WASM modules if not already initialized
|
|
45
|
+
* This function is idempotent - safe to call multiple times
|
|
46
|
+
*/
|
|
47
|
+
export async function initializeWasm() {
|
|
48
|
+
// If already initialized, return immediately
|
|
49
|
+
if (isInitialized) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// If initialization is in progress, wait for it to complete
|
|
53
|
+
if (isInitializing && initializationPromise) {
|
|
54
|
+
return initializationPromise;
|
|
55
|
+
}
|
|
56
|
+
// Start initialization
|
|
57
|
+
isInitializing = true;
|
|
58
|
+
initError = null;
|
|
59
|
+
initializationPromise = (async () => {
|
|
60
|
+
try {
|
|
61
|
+
// In Node.js environment, load WASM using fs.readFileSync
|
|
62
|
+
if (isNodeEnvironment()) {
|
|
63
|
+
const wasmModule = await loadWasmForNode();
|
|
64
|
+
await init(wasmModule);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
// In browser/jsdom, use default init (which uses fetch)
|
|
68
|
+
await init();
|
|
69
|
+
}
|
|
70
|
+
isInitialized = true;
|
|
71
|
+
isInitializing = false;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
initError = error;
|
|
75
|
+
isInitializing = false;
|
|
76
|
+
console.error('[WASM] Failed to initialize WASM modules:', error);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
})();
|
|
80
|
+
return initializationPromise;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Ensure WASM is initialized, throwing an error if initialization failed
|
|
84
|
+
*/
|
|
85
|
+
export async function ensureWasmInitialized() {
|
|
86
|
+
await initializeWasm();
|
|
87
|
+
if (initError) {
|
|
88
|
+
throw new Error(`WASM initialization failed: ${initError.message}`);
|
|
89
|
+
}
|
|
90
|
+
if (!isInitialized) {
|
|
91
|
+
throw new Error('WASM not initialized');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Start WASM initialization in the background.
|
|
96
|
+
* Call this early in the app lifecycle (for example in main.tsx).
|
|
97
|
+
*/
|
|
98
|
+
export function startWasmInitialization() {
|
|
99
|
+
// Fire and forget - start initialization in background
|
|
100
|
+
initializeWasm().catch(error => {
|
|
101
|
+
console.error('[WASM] Background initialization error:', error);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Module Implementation
|
|
3
|
+
*
|
|
4
|
+
* This file contains the real WASM implementation of the SessionModule
|
|
5
|
+
* using SessionManagerWrapper and related WASM classes.
|
|
6
|
+
*/
|
|
7
|
+
import { UserPublicKeys, UserSecretKeys, ReceiveMessageOutput, SendMessageOutput, SessionStatus, EncryptionKey, SessionConfig, AnnouncementResult, UserKeys } from '../assets/generated/wasm/gossip_wasm';
|
|
8
|
+
import { UserProfile } from '../db';
|
|
9
|
+
export declare class SessionModule {
|
|
10
|
+
private sessionManager;
|
|
11
|
+
private onPersist?;
|
|
12
|
+
ourPk: UserPublicKeys;
|
|
13
|
+
ourSk: UserSecretKeys;
|
|
14
|
+
userId: Uint8Array;
|
|
15
|
+
userIdEncoded: string;
|
|
16
|
+
constructor(userKeys: UserKeys, onPersist?: () => Promise<void>, config?: SessionConfig);
|
|
17
|
+
/**
|
|
18
|
+
* Set the persistence callback
|
|
19
|
+
*/
|
|
20
|
+
setOnPersist(callback: () => Promise<void>): void;
|
|
21
|
+
/**
|
|
22
|
+
* Helper to trigger persistence after state changes.
|
|
23
|
+
* Returns a promise that resolves when persistence is complete.
|
|
24
|
+
* IMPORTANT: Callers should await this before sending data to network
|
|
25
|
+
* to prevent state loss on app crash.
|
|
26
|
+
*/
|
|
27
|
+
private persistIfNeeded;
|
|
28
|
+
/**
|
|
29
|
+
* Trigger persistence explicitly and wait for completion.
|
|
30
|
+
* Use this when you need to ensure state is saved before proceeding.
|
|
31
|
+
*/
|
|
32
|
+
persist(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Initialize session from an encrypted blob
|
|
35
|
+
*/
|
|
36
|
+
load(profile: UserProfile, encryptionKey: EncryptionKey): void;
|
|
37
|
+
/**
|
|
38
|
+
* Serialize session to an encrypted blob
|
|
39
|
+
*/
|
|
40
|
+
toEncryptedBlob(key: EncryptionKey): Uint8Array;
|
|
41
|
+
cleanup(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Establish an outgoing session with a peer via the underlying WASM wrapper
|
|
44
|
+
* @param peerPk - The peer's public keys
|
|
45
|
+
* @param userData - Optional user data to include in the announcement (defaults to empty array)
|
|
46
|
+
* @returns The announcement bytes to publish
|
|
47
|
+
*/
|
|
48
|
+
establishOutgoingSession(peerPk: UserPublicKeys, userData?: Uint8Array): Promise<Uint8Array>;
|
|
49
|
+
/**
|
|
50
|
+
* Feed an incoming announcement into the session manager
|
|
51
|
+
* @returns AnnouncementResult containing the announcer's public keys, timestamp, and user data, or undefined if invalid
|
|
52
|
+
*/
|
|
53
|
+
feedIncomingAnnouncement(announcementBytes: Uint8Array): Promise<AnnouncementResult | undefined>;
|
|
54
|
+
/**
|
|
55
|
+
* Get the list of message board read keys (seekers) to monitor
|
|
56
|
+
*/
|
|
57
|
+
getMessageBoardReadKeys(): Array<Uint8Array>;
|
|
58
|
+
/**
|
|
59
|
+
* Process an incoming ciphertext from the message board
|
|
60
|
+
*/
|
|
61
|
+
feedIncomingMessageBoardRead(seeker: Uint8Array, ciphertext: Uint8Array): Promise<ReceiveMessageOutput | undefined>;
|
|
62
|
+
/**
|
|
63
|
+
* Send a message to a peer.
|
|
64
|
+
* IMPORTANT: This persists session state before returning.
|
|
65
|
+
* The returned output should only be sent to network AFTER this resolves.
|
|
66
|
+
*/
|
|
67
|
+
sendMessage(peerId: Uint8Array, message: Uint8Array): Promise<SendMessageOutput | undefined>;
|
|
68
|
+
/**
|
|
69
|
+
* List all known peer IDs
|
|
70
|
+
*/
|
|
71
|
+
peerList(): Array<Uint8Array>;
|
|
72
|
+
/**
|
|
73
|
+
* Get the session status for a peer
|
|
74
|
+
*/
|
|
75
|
+
peerSessionStatus(peerId: Uint8Array): SessionStatus;
|
|
76
|
+
/**
|
|
77
|
+
* Discard a peer and all associated session state
|
|
78
|
+
*/
|
|
79
|
+
peerDiscard(peerId: Uint8Array): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Refresh sessions, returning peer IDs that need keep-alive messages
|
|
82
|
+
*/
|
|
83
|
+
refresh(): Promise<Array<Uint8Array>>;
|
|
84
|
+
}
|
|
85
|
+
export declare function sessionStatusToString(status: SessionStatus): string;
|