@msssystems/mss-link-sdk 0.1.11 → 0.2.1
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/client/browser-client.d.ts +16 -0
- package/dist/client/browser-client.js +35 -0
- package/dist/client/index.d.ts +3 -20
- package/dist/client/index.js +3 -20
- package/dist/client/mss-link-client.d.ts +12 -0
- package/dist/client/mss-link-client.js +17 -0
- package/dist/client/wasm-client.types.d.ts +1 -1
- package/dist/contracts/chat.contract.d.ts +189 -0
- package/dist/contracts/user-search.contract.d.ts +9 -0
- package/dist/core/http-client.d.ts +24 -0
- package/dist/core/http-client.js +80 -0
- package/dist/{client → core}/local-crypto-health.contracts.d.ts +1 -1
- package/dist/{client → core}/local-crypto-health.js +1 -1
- package/dist/core/wasm-crypto-engine.d.ts +34 -0
- package/dist/core/wasm-crypto-engine.js +75 -0
- package/dist/errors/api-error.d.ts +6 -0
- package/dist/errors/api-error.js +11 -0
- package/dist/errors/sdk-error.d.ts +3 -0
- package/dist/errors/sdk-error.js +6 -0
- package/dist/modules/chats/chats.client.d.ts +11 -0
- package/dist/modules/chats/chats.client.js +25 -0
- package/dist/modules/media/media-crypto.client.d.ts +10 -0
- package/dist/modules/media/media-crypto.client.js +90 -0
- package/dist/{client → modules/messages}/message-decryption-state.js +1 -1
- package/dist/{client → modules/messages}/message-decryption.contracts.d.ts +1 -1
- package/dist/modules/messages/messages-crypto.client.d.ts +14 -0
- package/dist/modules/messages/messages-crypto.client.js +34 -0
- package/dist/modules/messages/messages.client.d.ts +8 -0
- package/dist/modules/messages/messages.client.js +24 -0
- package/dist/{client → modules/storage}/drive-file-runtime.contracts.d.ts +2 -2
- package/dist/{client → modules/storage}/drive-file-runtime.d.ts +1 -1
- package/dist/{client → modules/storage}/drive-key-wrapping.contracts.d.ts +12 -0
- package/dist/modules/storage/drive-key-wrapping.d.ts +3 -0
- package/dist/{client → modules/storage}/drive-key-wrapping.js +30 -0
- package/dist/modules/storage/drive-sharing.contracts.js +1 -0
- package/dist/modules/storage/storage-crypto.client.d.ts +13 -0
- package/dist/modules/storage/storage-crypto.client.js +73 -0
- package/dist/modules/storage/storage-metadata-crypto.contracts.js +1 -0
- package/package.json +1 -1
- package/dist/client/drive-key-wrapping.d.ts +0 -2
- package/dist/client/mss-link-browser-client.d.ts +0 -45
- package/dist/client/mss-link-browser-client.js +0 -256
- /package/dist/{client/drive-file-runtime.contracts.js → contracts/chat.contract.js} +0 -0
- /package/dist/{client/drive-key-wrapping.contracts.js → contracts/user-search.contract.js} +0 -0
- /package/dist/{client → core}/api-base-url.d.ts +0 -0
- /package/dist/{client → core}/api-base-url.js +0 -0
- /package/dist/{client → core}/local-crypto-health.contracts.js +0 -0
- /package/dist/{client → core}/local-crypto-health.d.ts +0 -0
- /package/dist/{client → core}/wasm-call-queue.d.ts +0 -0
- /package/dist/{client → core}/wasm-call-queue.js +0 -0
- /package/dist/{client → errors}/decryption-errors.d.ts +0 -0
- /package/dist/{client → errors}/decryption-errors.js +0 -0
- /package/dist/{client → modules/media}/media-crypto.contracts.d.ts +0 -0
- /package/dist/{client → modules/media}/media-crypto.contracts.js +0 -0
- /package/dist/{client → modules/media}/media-message-metadata.d.ts +0 -0
- /package/dist/{client → modules/media}/media-message-metadata.js +0 -0
- /package/dist/{client → modules/media}/media-message.contracts.d.ts +0 -0
- /package/dist/{client → modules/media}/media-message.contracts.js +0 -0
- /package/dist/{client → modules/messages}/message-decryption-state.d.ts +0 -0
- /package/dist/{client → modules/messages}/message-decryption.contracts.js +0 -0
- /package/dist/{client → modules/messages}/message.contracts.d.ts +0 -0
- /package/dist/{client → modules/messages}/message.contracts.js +0 -0
- /package/dist/{client → modules/messages}/message.mapper.d.ts +0 -0
- /package/dist/{client → modules/messages}/message.mapper.js +0 -0
- /package/dist/{client/drive-sharing.contracts.js → modules/storage/drive-file-runtime.contracts.js} +0 -0
- /package/dist/{client → modules/storage}/drive-file-runtime.js +0 -0
- /package/dist/{client/storage-metadata-crypto.contracts.js → modules/storage/drive-key-wrapping.contracts.js} +0 -0
- /package/dist/{client → modules/storage}/drive-sharing.contracts.d.ts +0 -0
- /package/dist/{client → modules/storage}/drive-sharing.d.ts +0 -0
- /package/dist/{client → modules/storage}/drive-sharing.js +0 -0
- /package/dist/{client → modules/storage}/storage-metadata-crypto.contracts.d.ts +0 -0
- /package/dist/{client → modules/storage}/storage-metadata-crypto.d.ts +0 -0
- /package/dist/{client → modules/storage}/storage-metadata-crypto.js +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { normalizeLocalCryptoError } from '../../errors/decryption-errors';
|
|
2
|
+
import { buildMediaMessageMetadataPayload, extractMediaAssetIds, serializeMediaMessageMetadata, } from './media-message-metadata';
|
|
3
|
+
export class MediaCryptoClient {
|
|
4
|
+
engine;
|
|
5
|
+
constructor(engine) {
|
|
6
|
+
this.engine = engine;
|
|
7
|
+
}
|
|
8
|
+
async sendMediaMessage(params) {
|
|
9
|
+
try {
|
|
10
|
+
await this.engine.ensureReady();
|
|
11
|
+
const payload = buildMediaMessageMetadataPayload(params.attachments, params.caption);
|
|
12
|
+
const metadataJson = serializeMediaMessageMetadata(payload);
|
|
13
|
+
const mediaAssetIds = extractMediaAssetIds(params.attachments);
|
|
14
|
+
return this.engine.runWithClient((client) => client.sendMediaMessage(params.chatId, params.targetUserId, metadataJson, mediaAssetIds));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
throw normalizeLocalCryptoError(error);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async encryptMediaBlob(input) {
|
|
21
|
+
try {
|
|
22
|
+
const plaintext = new Uint8Array(await input.blob.arrayBuffer());
|
|
23
|
+
const encrypted = await this.engine.queue.run(async () => {
|
|
24
|
+
const module = await this.engine.loadWasmModule();
|
|
25
|
+
return module.encryptMediaBytes(plaintext);
|
|
26
|
+
});
|
|
27
|
+
const encryptedBytes = new Uint8Array(encrypted.ciphertext);
|
|
28
|
+
return {
|
|
29
|
+
encryptedBlob: new Blob([encryptedBytes], {
|
|
30
|
+
type: 'application/octet-stream',
|
|
31
|
+
}),
|
|
32
|
+
encryption: {
|
|
33
|
+
schema: 'mss.link.media-encryption.v1',
|
|
34
|
+
algorithm: 'AES-256-GCM',
|
|
35
|
+
keyId: input.assetId,
|
|
36
|
+
nonce: encrypted.nonce,
|
|
37
|
+
wrappedKey: encrypted.key,
|
|
38
|
+
},
|
|
39
|
+
attachment: {
|
|
40
|
+
assetId: input.assetId,
|
|
41
|
+
mimeType: input.mimeType,
|
|
42
|
+
size: input.size,
|
|
43
|
+
...(input.originalName ? { originalName: input.originalName } : {}),
|
|
44
|
+
...(input.uploadedAt ? { uploadedAt: input.uploadedAt } : {}),
|
|
45
|
+
encryption: {
|
|
46
|
+
schema: 'mss.link.media-encryption.v1',
|
|
47
|
+
algorithm: 'AES-256-GCM',
|
|
48
|
+
keyId: input.assetId,
|
|
49
|
+
nonce: encrypted.nonce,
|
|
50
|
+
wrappedKey: encrypted.key,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw normalizeLocalCryptoError(error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async decryptMediaBlob(input) {
|
|
60
|
+
const encryption = input.metadata.encryption;
|
|
61
|
+
if (!encryption) {
|
|
62
|
+
return {
|
|
63
|
+
blob: input.encryptedBlob,
|
|
64
|
+
mimeType: input.metadata.mimeType,
|
|
65
|
+
...(input.metadata.originalName
|
|
66
|
+
? { fileName: input.metadata.originalName }
|
|
67
|
+
: {}),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const ciphertext = new Uint8Array(await input.encryptedBlob.arrayBuffer());
|
|
72
|
+
const plaintext = await this.engine.queue.run(async () => {
|
|
73
|
+
const module = await this.engine.loadWasmModule();
|
|
74
|
+
return module.decryptMediaBytes(ciphertext, encryption.wrappedKey, encryption.nonce);
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
blob: new Blob([new Uint8Array(plaintext)], {
|
|
78
|
+
type: input.metadata.mimeType,
|
|
79
|
+
}),
|
|
80
|
+
mimeType: input.metadata.mimeType,
|
|
81
|
+
...(input.metadata.originalName
|
|
82
|
+
? { fileName: input.metadata.originalName }
|
|
83
|
+
: {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw normalizeLocalCryptoError(error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeLocalCryptoError } from '
|
|
1
|
+
import { normalizeLocalCryptoError } from '../../errors/decryption-errors';
|
|
2
2
|
export function createMessageDecryptionStateIndex({ messages, decryptedMessages, isDecrypting, decryptError, }) {
|
|
3
3
|
const decryptedById = createDecryptedMessageIndex(decryptedMessages);
|
|
4
4
|
const index = new Map();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LocalCryptoErrorCode } from '
|
|
1
|
+
import type { LocalCryptoErrorCode } from '../../errors/decryption-errors';
|
|
2
2
|
import type { DecryptedMessage } from './message.contracts';
|
|
3
3
|
export type MessageDecryptStatus = 'decrypted' | 'pending' | 'failed' | 'recovery_required';
|
|
4
4
|
export type MessageDecryptReason = 'local_sync_in_progress' | 'local_message_missing' | 'local_crypto_error';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { WasmCryptoEngine } from '../../core/wasm-crypto-engine';
|
|
2
|
+
import type { DecryptedMessage } from './message.contracts';
|
|
3
|
+
export declare class MessagesCryptoClient {
|
|
4
|
+
private readonly engine;
|
|
5
|
+
constructor(engine: WasmCryptoEngine);
|
|
6
|
+
sendMessage(params: {
|
|
7
|
+
chatId: string;
|
|
8
|
+
targetUserId: string;
|
|
9
|
+
text: string;
|
|
10
|
+
kind?: string;
|
|
11
|
+
}): Promise<string>;
|
|
12
|
+
syncMessages(): Promise<void>;
|
|
13
|
+
getLocalMessages(chatId: string): Promise<DecryptedMessage[]>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { normalizeLocalCryptoError } from '../../errors/decryption-errors';
|
|
2
|
+
import { mapLocalSdkMessage } from './message.mapper';
|
|
3
|
+
export class MessagesCryptoClient {
|
|
4
|
+
engine;
|
|
5
|
+
constructor(engine) {
|
|
6
|
+
this.engine = engine;
|
|
7
|
+
}
|
|
8
|
+
async sendMessage(params) {
|
|
9
|
+
try {
|
|
10
|
+
await this.engine.ensureReady();
|
|
11
|
+
return this.engine.runWithClient((client) => client.sendMessage(params.chatId, params.targetUserId, params.text, params.kind ?? 'TEXT'));
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
throw normalizeLocalCryptoError(error);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
async syncMessages() {
|
|
18
|
+
try {
|
|
19
|
+
await this.engine.runWithClient((client) => client.syncMessages());
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw normalizeLocalCryptoError(error);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async getLocalMessages(chatId) {
|
|
26
|
+
try {
|
|
27
|
+
const rawMessages = await this.engine.runWithClient((client) => client.getLocalMessages(chatId));
|
|
28
|
+
return rawMessages.map((message) => mapLocalSdkMessage(message));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw normalizeLocalCryptoError(error);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { HttpClient } from '../../core/http-client';
|
|
2
|
+
export declare class MessagesClient {
|
|
3
|
+
private readonly http;
|
|
4
|
+
constructor(http: HttpClient);
|
|
5
|
+
list(chatId: string, limit?: number, before?: string, after?: string): Promise<any>;
|
|
6
|
+
markDelivered(chatId: string, throughMessageId: string, limit?: number): Promise<any>;
|
|
7
|
+
markRead(chatId: string, throughMessageId: string, limit?: number): Promise<any>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// TODO: Import proper types from contracts
|
|
2
|
+
export class MessagesClient {
|
|
3
|
+
http;
|
|
4
|
+
constructor(http) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
}
|
|
7
|
+
async list(chatId, limit = 30, before, after) {
|
|
8
|
+
return this.http.get(`/link/v1/chats/${chatId}/messages`, {
|
|
9
|
+
params: { limit, before, after }
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
async markDelivered(chatId, throughMessageId, limit) {
|
|
13
|
+
return this.http.post(`/link/v1/chats/${chatId}/messages/delivered`, {
|
|
14
|
+
throughMessageId,
|
|
15
|
+
limit
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async markRead(chatId, throughMessageId, limit) {
|
|
19
|
+
return this.http.post(`/link/v1/chats/${chatId}/messages/read`, {
|
|
20
|
+
throughMessageId,
|
|
21
|
+
limit
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { DecryptedMediaBlobResult } from '
|
|
2
|
-
import type { MediaMessageAttachmentMetadata } from '
|
|
1
|
+
import type { DecryptedMediaBlobResult } from '../media/media-crypto.contracts';
|
|
2
|
+
import type { MediaMessageAttachmentMetadata } from '../media/media-message.contracts';
|
|
3
3
|
export type DriveFilePreviewKind = 'image' | 'pdf' | 'text' | 'unsupported' | 'video';
|
|
4
4
|
export interface DriveFileContentEnvelope {
|
|
5
5
|
algorithm?: 'AES-256-GCM' | string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DecryptedMediaBlobResult } from '
|
|
1
|
+
import type { DecryptedMediaBlobResult } from '../media/media-crypto.contracts';
|
|
2
2
|
import type { DriveFileAttachmentInput, DriveFileMediaMetadata, DriveFilePreviewInput, DriveFilePreviewKind, DriveFileRuntimeMetadataInput, PreparedDriveFileAttachment, PreparedDriveFilePreview } from './drive-file-runtime.contracts';
|
|
3
3
|
export declare function buildDriveFileMediaMetadata(input: DriveFileRuntimeMetadataInput): DriveFileMediaMetadata;
|
|
4
4
|
export declare function getDriveFilePreviewKind(mimeType: string): DriveFilePreviewKind;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DriveItemType, DriveWrappedItemKey } from './drive-sharing.contracts';
|
|
2
2
|
export type DriveRecipientPublicKeyAlgorithm = 'X25519';
|
|
3
3
|
export type DriveWrappedItemKeyAlgorithm = 'MSS-DRIVE-PUBLIC-KEY-WRAPPED-ITEM-KEY-v1';
|
|
4
|
+
export type DriveItemKeyMaterialKind = 'content-key' | 'folder-metadata-envelope';
|
|
4
5
|
export interface DriveRecipientPublicKey {
|
|
5
6
|
algorithm: DriveRecipientPublicKeyAlgorithm;
|
|
6
7
|
keyId: string;
|
|
@@ -14,6 +15,7 @@ export interface DriveRecipientKeyTarget {
|
|
|
14
15
|
}
|
|
15
16
|
export interface DriveItemContentKeyEnvelope {
|
|
16
17
|
algorithm?: 'AES-256-GCM' | string | null;
|
|
18
|
+
keyMaterialKind?: DriveItemKeyMaterialKind | string | null;
|
|
17
19
|
keyId?: string | null;
|
|
18
20
|
nonce?: string | null;
|
|
19
21
|
wrappedKey: string;
|
|
@@ -39,10 +41,20 @@ export interface CreateDriveWrappedItemKeyForRecipientInput {
|
|
|
39
41
|
recipient: DriveRecipientKeyTarget;
|
|
40
42
|
wrappingAdapter: DrivePublicKeyWrappingAdapter;
|
|
41
43
|
}
|
|
44
|
+
export interface CreateDriveWrappedFolderKeyForRecipientInput {
|
|
45
|
+
encryptedFolderMetadata: {
|
|
46
|
+
encryptedName: string;
|
|
47
|
+
schema?: 'mss.link.drive-folder-metadata.v1' | string;
|
|
48
|
+
};
|
|
49
|
+
folderId: string;
|
|
50
|
+
recipient: DriveRecipientKeyTarget;
|
|
51
|
+
wrappingAdapter: DrivePublicKeyWrappingAdapter;
|
|
52
|
+
}
|
|
42
53
|
export interface DriveWrappedItemKeyPayload {
|
|
43
54
|
contentAlgorithm: string;
|
|
44
55
|
contentKey: string;
|
|
45
56
|
contentKeyId?: string;
|
|
57
|
+
contentKeyMaterialKind: DriveItemKeyMaterialKind;
|
|
46
58
|
contentNonce?: string;
|
|
47
59
|
createdAt: string;
|
|
48
60
|
itemId: string;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { CreateDriveWrappedFolderKeyForRecipientInput, CreateDriveWrappedItemKeyForRecipientInput, DriveWrappedItemKeyForRecipientResult } from './drive-key-wrapping.contracts';
|
|
2
|
+
export declare function createDriveWrappedItemKeyForRecipient(input: CreateDriveWrappedItemKeyForRecipientInput): Promise<DriveWrappedItemKeyForRecipientResult>;
|
|
3
|
+
export declare function createDriveWrappedFolderKeyForRecipient(input: CreateDriveWrappedFolderKeyForRecipientInput): Promise<DriveWrappedItemKeyForRecipientResult>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { normalizeEncryptedDriveFolderMetadataInput } from './storage-metadata-crypto';
|
|
1
2
|
const CONTENT_KEY_SCHEMA = 'mss.link.drive.item-key.v1';
|
|
2
3
|
const WRAPPED_ITEM_KEY_ALGORITHM = 'MSS-DRIVE-PUBLIC-KEY-WRAPPED-ITEM-KEY-v1';
|
|
4
|
+
const FOLDER_METADATA_KEY_ID_PREFIX = 'drive-folder-metadata';
|
|
3
5
|
export async function createDriveWrappedItemKeyForRecipient(input) {
|
|
4
6
|
const itemId = normalizeRequiredText(input.itemId, 'Drive item id is required for key wrapping.');
|
|
5
7
|
const itemType = input.itemType;
|
|
@@ -29,6 +31,24 @@ export async function createDriveWrappedItemKeyForRecipient(input) {
|
|
|
29
31
|
}),
|
|
30
32
|
};
|
|
31
33
|
}
|
|
34
|
+
export function createDriveWrappedFolderKeyForRecipient(input) {
|
|
35
|
+
const folderId = normalizeRequiredText(input.folderId, 'Drive folder id is required for key wrapping.');
|
|
36
|
+
const metadata = normalizeEncryptedDriveFolderMetadataInput({
|
|
37
|
+
encryptedName: input.encryptedFolderMetadata.encryptedName,
|
|
38
|
+
});
|
|
39
|
+
return createDriveWrappedItemKeyForRecipient({
|
|
40
|
+
contentKey: {
|
|
41
|
+
algorithm: 'AES-256-GCM',
|
|
42
|
+
keyId: `${FOLDER_METADATA_KEY_ID_PREFIX}:${folderId}`,
|
|
43
|
+
keyMaterialKind: 'folder-metadata-envelope',
|
|
44
|
+
wrappedKey: metadata.encryptedName,
|
|
45
|
+
},
|
|
46
|
+
itemId: folderId,
|
|
47
|
+
itemType: 'folder',
|
|
48
|
+
recipient: input.recipient,
|
|
49
|
+
wrappingAdapter: input.wrappingAdapter,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
32
52
|
function buildWrappedItemKeyPayload({ contentKey, itemId, itemType, }) {
|
|
33
53
|
return {
|
|
34
54
|
schema: CONTENT_KEY_SCHEMA,
|
|
@@ -36,6 +56,7 @@ function buildWrappedItemKeyPayload({ contentKey, itemId, itemType, }) {
|
|
|
36
56
|
itemType,
|
|
37
57
|
contentAlgorithm: contentKey.algorithm,
|
|
38
58
|
contentKey: contentKey.wrappedKey,
|
|
59
|
+
contentKeyMaterialKind: contentKey.keyMaterialKind,
|
|
39
60
|
createdAt: new Date().toISOString(),
|
|
40
61
|
...(contentKey.keyId ? { contentKeyId: contentKey.keyId } : {}),
|
|
41
62
|
...(contentKey.nonce ? { contentNonce: contentKey.nonce } : {}),
|
|
@@ -74,10 +95,19 @@ function normalizeContentKey(contentKey) {
|
|
|
74
95
|
return {
|
|
75
96
|
algorithm,
|
|
76
97
|
keyId: normalizeOptionalText(contentKey.keyId) ?? '',
|
|
98
|
+
keyMaterialKind: normalizeKeyMaterialKind(contentKey.keyMaterialKind),
|
|
77
99
|
nonce: normalizeOptionalText(contentKey.nonce) ?? '',
|
|
78
100
|
wrappedKey: normalizeRequiredText(contentKey.wrappedKey, 'Drive item content key is required.'),
|
|
79
101
|
};
|
|
80
102
|
}
|
|
103
|
+
function normalizeKeyMaterialKind(kind) {
|
|
104
|
+
const normalized = normalizeOptionalText(kind) ?? 'content-key';
|
|
105
|
+
if (normalized !== 'content-key' &&
|
|
106
|
+
normalized !== 'folder-metadata-envelope') {
|
|
107
|
+
throw new Error(`Unsupported Drive item key material kind: ${normalized}`);
|
|
108
|
+
}
|
|
109
|
+
return normalized;
|
|
110
|
+
}
|
|
81
111
|
function normalizeWrappingAdapter(adapter) {
|
|
82
112
|
if (!adapter || typeof adapter.wrapDriveItemKey !== 'function') {
|
|
83
113
|
throw new Error('Drive public-key wrapping adapter is not configured.');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { WasmCryptoEngine } from '../../core/wasm-crypto-engine';
|
|
2
|
+
import type { DecryptDriveFileMetadataInput, DecryptDriveFolderMetadataInput, DecryptedDriveFileMetadata, DecryptedDriveFolderMetadata, EncryptedDriveFileMetadata, EncryptedDriveFolderMetadata, EncryptDriveFileMetadataInput, EncryptDriveFolderMetadataInput } from './storage-metadata-crypto.contracts';
|
|
3
|
+
import type { CreateDriveWrappedFolderKeyForRecipientInput, CreateDriveWrappedItemKeyForRecipientInput, DriveWrappedItemKeyForRecipientResult } from './drive-key-wrapping.contracts';
|
|
4
|
+
export declare class StorageCryptoClient {
|
|
5
|
+
private readonly engine;
|
|
6
|
+
constructor(engine: WasmCryptoEngine);
|
|
7
|
+
encryptDriveFolderMetadata(input: EncryptDriveFolderMetadataInput): Promise<EncryptedDriveFolderMetadata>;
|
|
8
|
+
decryptDriveFolderMetadata(input: DecryptDriveFolderMetadataInput): Promise<DecryptedDriveFolderMetadata>;
|
|
9
|
+
encryptDriveFileMetadata(input: EncryptDriveFileMetadataInput): Promise<EncryptedDriveFileMetadata>;
|
|
10
|
+
decryptDriveFileMetadata(input: DecryptDriveFileMetadataInput): Promise<DecryptedDriveFileMetadata>;
|
|
11
|
+
createDriveWrappedItemKeyForRecipient(input: CreateDriveWrappedItemKeyForRecipientInput): Promise<DriveWrappedItemKeyForRecipientResult>;
|
|
12
|
+
createDriveWrappedFolderKeyForRecipient(input: CreateDriveWrappedFolderKeyForRecipientInput): Promise<DriveWrappedItemKeyForRecipientResult>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { normalizeLocalCryptoError } from '../../errors/decryption-errors';
|
|
2
|
+
import { buildDecryptedDriveFileMetadata, buildDecryptedDriveFolderMetadata, buildEncryptedDriveFileMetadata, buildEncryptedDriveFolderMetadata, normalizeDriveFileMetadataInput, normalizeDriveFolderMetadataInput, normalizeEncryptedDriveFileMetadataInput, normalizeEncryptedDriveFolderMetadataInput, } from './storage-metadata-crypto';
|
|
3
|
+
import { createDriveWrappedFolderKeyForRecipient, createDriveWrappedItemKeyForRecipient, } from './drive-key-wrapping';
|
|
4
|
+
export class StorageCryptoClient {
|
|
5
|
+
engine;
|
|
6
|
+
constructor(engine) {
|
|
7
|
+
this.engine = engine;
|
|
8
|
+
}
|
|
9
|
+
async encryptDriveFolderMetadata(input) {
|
|
10
|
+
try {
|
|
11
|
+
const metadata = normalizeDriveFolderMetadataInput(input);
|
|
12
|
+
const encryptedName = await this.engine.queue.run(async () => {
|
|
13
|
+
const module = await this.engine.loadWasmModule();
|
|
14
|
+
return module.encryptStorageMetadata(metadata.name);
|
|
15
|
+
});
|
|
16
|
+
return buildEncryptedDriveFolderMetadata(encryptedName);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
throw normalizeLocalCryptoError(error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async decryptDriveFolderMetadata(input) {
|
|
23
|
+
try {
|
|
24
|
+
const metadata = normalizeEncryptedDriveFolderMetadataInput(input);
|
|
25
|
+
const name = await this.engine.queue.run(async () => {
|
|
26
|
+
const module = await this.engine.loadWasmModule();
|
|
27
|
+
return module.decryptStorageMetadata(metadata.encryptedName);
|
|
28
|
+
});
|
|
29
|
+
return buildDecryptedDriveFolderMetadata(name);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw normalizeLocalCryptoError(error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async encryptDriveFileMetadata(input) {
|
|
36
|
+
try {
|
|
37
|
+
const metadata = normalizeDriveFileMetadataInput(input);
|
|
38
|
+
const [encryptedName, encryptedMimeType] = await this.engine.queue.run(async () => {
|
|
39
|
+
const module = await this.engine.loadWasmModule();
|
|
40
|
+
return [
|
|
41
|
+
module.encryptStorageMetadata(metadata.name),
|
|
42
|
+
module.encryptStorageMetadata(metadata.mimeType),
|
|
43
|
+
];
|
|
44
|
+
});
|
|
45
|
+
return buildEncryptedDriveFileMetadata(encryptedName, encryptedMimeType);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw normalizeLocalCryptoError(error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async decryptDriveFileMetadata(input) {
|
|
52
|
+
try {
|
|
53
|
+
const metadata = normalizeEncryptedDriveFileMetadataInput(input);
|
|
54
|
+
const [name, mimeType] = await this.engine.queue.run(async () => {
|
|
55
|
+
const module = await this.engine.loadWasmModule();
|
|
56
|
+
return [
|
|
57
|
+
module.decryptStorageMetadata(metadata.encryptedName),
|
|
58
|
+
module.decryptStorageMetadata(metadata.encryptedMimeType),
|
|
59
|
+
];
|
|
60
|
+
});
|
|
61
|
+
return buildDecryptedDriveFileMetadata(name, mimeType);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw normalizeLocalCryptoError(error);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
createDriveWrappedItemKeyForRecipient(input) {
|
|
68
|
+
return createDriveWrappedItemKeyForRecipient(input);
|
|
69
|
+
}
|
|
70
|
+
createDriveWrappedFolderKeyForRecipient(input) {
|
|
71
|
+
return createDriveWrappedFolderKeyForRecipient(input);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import type { CreateDriveWrappedItemKeyForRecipientInput, DriveWrappedItemKeyForRecipientResult } from './drive-key-wrapping.contracts';
|
|
2
|
-
export declare function createDriveWrappedItemKeyForRecipient(input: CreateDriveWrappedItemKeyForRecipientInput): Promise<DriveWrappedItemKeyForRecipientResult>;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { MssLinkBrowserClientOptions } from './client-options';
|
|
2
|
-
import type { LocalCryptoHealth } from './local-crypto-health.contracts';
|
|
3
|
-
import type { DecryptMediaBlobInput, DecryptedMediaBlobResult, EncryptedMediaBlobResult, EncryptMediaBlobInput } from './media-crypto.contracts';
|
|
4
|
-
import type { SendMediaMessageParams } from './media-message.contracts';
|
|
5
|
-
import type { DecryptedMessage } from './message.contracts';
|
|
6
|
-
import type { DecryptDriveFileMetadataInput, DecryptDriveFolderMetadataInput, DecryptedDriveFileMetadata, DecryptedDriveFolderMetadata, EncryptedDriveFileMetadata, EncryptedDriveFolderMetadata, EncryptDriveFileMetadataInput, EncryptDriveFolderMetadataInput } from './storage-metadata-crypto.contracts';
|
|
7
|
-
import type { CreateDriveWrappedItemKeyForRecipientInput, DriveWrappedItemKeyForRecipientResult } from './drive-key-wrapping.contracts';
|
|
8
|
-
export declare class MssLinkBrowserClient {
|
|
9
|
-
private readonly userId;
|
|
10
|
-
private readonly apiBaseUrl;
|
|
11
|
-
private readonly deviceId;
|
|
12
|
-
private readonly registrationId;
|
|
13
|
-
private readonly signedPrekeyId;
|
|
14
|
-
private readonly initialOneTimePrekeyCount;
|
|
15
|
-
private readonly minOneTimePrekeys;
|
|
16
|
-
private readonly replenishOneTimePrekeys;
|
|
17
|
-
private readonly queue;
|
|
18
|
-
private wasmClient;
|
|
19
|
-
private wasmModulePromise;
|
|
20
|
-
private accessToken;
|
|
21
|
-
constructor(options: MssLinkBrowserClientOptions);
|
|
22
|
-
setAccessToken(accessToken: string | null): void;
|
|
23
|
-
ensureReady(): Promise<void>;
|
|
24
|
-
getLocalCryptoHealth(): Promise<LocalCryptoHealth>;
|
|
25
|
-
sendMessage(params: {
|
|
26
|
-
chatId: string;
|
|
27
|
-
targetUserId: string;
|
|
28
|
-
text: string;
|
|
29
|
-
kind?: string;
|
|
30
|
-
}): Promise<string>;
|
|
31
|
-
sendMediaMessage(params: SendMediaMessageParams): Promise<string>;
|
|
32
|
-
encryptMediaBlob(input: EncryptMediaBlobInput): Promise<EncryptedMediaBlobResult>;
|
|
33
|
-
decryptMediaBlob(input: DecryptMediaBlobInput): Promise<DecryptedMediaBlobResult>;
|
|
34
|
-
encryptDriveFolderMetadata(input: EncryptDriveFolderMetadataInput): Promise<EncryptedDriveFolderMetadata>;
|
|
35
|
-
decryptDriveFolderMetadata(input: DecryptDriveFolderMetadataInput): Promise<DecryptedDriveFolderMetadata>;
|
|
36
|
-
encryptDriveFileMetadata(input: EncryptDriveFileMetadataInput): Promise<EncryptedDriveFileMetadata>;
|
|
37
|
-
decryptDriveFileMetadata(input: DecryptDriveFileMetadataInput): Promise<DecryptedDriveFileMetadata>;
|
|
38
|
-
createDriveWrappedItemKeyForRecipient(input: CreateDriveWrappedItemKeyForRecipientInput): Promise<DriveWrappedItemKeyForRecipientResult>;
|
|
39
|
-
syncMessages(): Promise<void>;
|
|
40
|
-
getLocalMessages(chatId: string): Promise<DecryptedMessage[]>;
|
|
41
|
-
reset(): void;
|
|
42
|
-
private runWithClient;
|
|
43
|
-
private getClient;
|
|
44
|
-
private loadWasmModule;
|
|
45
|
-
}
|