@secrecy/lib 1.62.0-feat-node-sharing.2 → 1.62.0-feat-node-sharing.4
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/lib/base-client.js +17 -15
- package/dist/lib/client/SecrecyAppClient.js +2 -2
- package/dist/lib/client/SecrecyCloudClient.js +96 -51
- package/dist/lib/client/convert/node.js +26 -2
- package/dist/lib/client/index.js +1 -7
- package/dist/lib/crypto/domain.js +17 -0
- package/dist/lib/utils/object.js +29 -0
- package/dist/lib/worker/md5.js +31 -16
- package/dist/lib/worker/sodium.js +83 -74
- package/dist/lib/worker/workerDependencies.js +140 -0
- package/dist/types/base-client.d.ts +1 -0
- package/dist/types/client/SecrecyCloudClient.d.ts +1 -1
- package/dist/types/client/convert/node.d.ts +2 -1
- package/dist/types/client/index.d.ts +2 -2
- package/dist/types/client/types/node.d.ts +18 -0
- package/dist/types/client.d.ts +4 -0
- package/dist/types/crypto/domain.d.ts +10 -0
- package/dist/types/utils/object.d.ts +1 -0
- package/dist/types/worker/md5.d.ts +1 -1
- package/dist/types/worker/sodium.d.ts +3 -3
- package/dist/types/worker/workerDependencies.d.ts +6 -0
- package/package.json +2 -2
package/dist/lib/base-client.js
CHANGED
|
@@ -25,21 +25,23 @@ export class BaseClient {
|
|
|
25
25
|
account: opts.secrecyUrls?.account ?? 'https://account.secrecy.tech',
|
|
26
26
|
api: opts.secrecyUrls?.api ?? 'https://api.secrecy.tech',
|
|
27
27
|
};
|
|
28
|
-
this.client =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
this.client =
|
|
29
|
+
opts.apiClient ??
|
|
30
|
+
BaseClient.getBaseClient({
|
|
31
|
+
session: opts.session,
|
|
32
|
+
apiUrl: this.secrecyUrls.api,
|
|
33
|
+
onAccessDenied: async () => {
|
|
34
|
+
console.log('[BASE_CLIENT - BEFORE] - Access denied');
|
|
35
|
+
await opts.onAccessDenied?.();
|
|
36
|
+
console.log('[BASE_CLIENT - AFTER] - Access denied');
|
|
37
|
+
try {
|
|
38
|
+
await this.logout();
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
location.reload();
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
});
|
|
43
45
|
}
|
|
44
46
|
async logout(sessionId) {
|
|
45
47
|
if (sessionId === null || sessionId === undefined) {
|
|
@@ -76,12 +76,12 @@ export class SecrecyAppClient {
|
|
|
76
76
|
...new Set(userIds.filter((userId) => publicKeys[userId] === undefined)),
|
|
77
77
|
];
|
|
78
78
|
if (missingKeys.length > 0) {
|
|
79
|
-
const userKeysMap = await this.#apiClient.application.userPublicKey.query(
|
|
79
|
+
const userKeysMap = await this.#apiClient.application.userPublicKey.query(missingKeys);
|
|
80
80
|
if ('publicKey' in userKeysMap) {
|
|
81
81
|
throw Error('Should not happen!');
|
|
82
82
|
}
|
|
83
83
|
if (Object.keys(userKeysMap).length !== missingKeys.length) {
|
|
84
|
-
throw new Error("Unable to load some user's
|
|
84
|
+
throw new Error("Unable to load some user's public keys!");
|
|
85
85
|
}
|
|
86
86
|
for (const userId in userKeysMap) {
|
|
87
87
|
publicKeys[userId] = userKeysMap[userId];
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
2
|
import ky from 'ky';
|
|
3
|
-
import { encryptName } from '../index.js';
|
|
4
3
|
import { nodesCache, dataCache, dataContentCache, nodesEncryptionCache, } from '../cache.js';
|
|
5
4
|
import { secretStreamKeygen } from '../crypto/data.js';
|
|
6
5
|
import { decryptCryptoBox, encryptCryptoBox } from '../crypto/index.js';
|
|
@@ -10,10 +9,12 @@ import { enumerate, chunks, concatenate } from '../utils/array.js';
|
|
|
10
9
|
import { md5 } from '../worker/md5.js';
|
|
11
10
|
import { decrypt, encrypt } from '../worker/sodium.js';
|
|
12
11
|
import { apiDataToExternal, apiDataToInternal } from './convert/data.js';
|
|
13
|
-
import { apiNodeFullToInternalFull, apiNodeToExternal, apiNodeToExternalNodeFull, internalNodeFullToNodeFull, } from './convert/node.js';
|
|
12
|
+
import { apiNodeForEncryptionToInternal, apiNodeFullToInternalFull, apiNodeToExternal, apiNodeToExternalNodeFull, internalNodeFullToNodeFull, } from './convert/node.js';
|
|
14
13
|
import { promiseAllLimit } from '../utils/promise.js';
|
|
15
14
|
import { kiloToBytes } from '../utils.js';
|
|
16
15
|
import { fileTypeFromBuffer } from 'file-type';
|
|
16
|
+
import { encryptName, generateAndEncryptNameAndKey } from '../crypto/domain.js';
|
|
17
|
+
import { chunkByTotalItems } from '../utils/object.js';
|
|
17
18
|
export class SecrecyCloudClient {
|
|
18
19
|
#client;
|
|
19
20
|
#keys;
|
|
@@ -32,18 +33,24 @@ export class SecrecyCloudClient {
|
|
|
32
33
|
const data = node.history.find((d) => d.id === dataId);
|
|
33
34
|
if (data !== undefined) {
|
|
34
35
|
const users = node.users.filter(([u]) => u.id !== this.#client.app.userId);
|
|
36
|
+
const userIds = users.map(([user]) => user.id);
|
|
37
|
+
const userKeys = await this.#client.app.userPublicKey(userIds);
|
|
38
|
+
const shares = users.map(([user]) => {
|
|
39
|
+
const publicKey = userKeys[user.id];
|
|
40
|
+
if (!publicKey) {
|
|
41
|
+
throw new Error('Unable to retreive share by public key!');
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
id: user.id,
|
|
45
|
+
key: data.key
|
|
46
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), publicKey, this.#keys.privateKey))
|
|
47
|
+
: null,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
35
50
|
await this.#apiClient.cloud.shareDataInHistory.mutate({
|
|
36
51
|
dataId: data.id,
|
|
37
52
|
nodeId,
|
|
38
|
-
users:
|
|
39
|
-
const userPubKey = await this.#client.app.userPublicKey(u.id);
|
|
40
|
-
return {
|
|
41
|
-
id: u.id,
|
|
42
|
-
key: data.key
|
|
43
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), userPubKey, this.#keys.privateKey))
|
|
44
|
-
: null,
|
|
45
|
-
};
|
|
46
|
-
})),
|
|
53
|
+
users: shares,
|
|
47
54
|
});
|
|
48
55
|
}
|
|
49
56
|
return internalNodeFullToNodeFull(node);
|
|
@@ -284,15 +291,17 @@ export class SecrecyCloudClient {
|
|
|
284
291
|
return isDeleted;
|
|
285
292
|
}
|
|
286
293
|
async createFolder({ name, parentFolderId, }) {
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
294
|
+
const { encryptedNameKey, encryptedName } = await generateAndEncryptNameAndKey({
|
|
295
|
+
name,
|
|
296
|
+
privateKey: this.#keys.privateKey,
|
|
297
|
+
publicKey: this.#keys.publicKey,
|
|
298
|
+
});
|
|
299
|
+
const createdFolder = await this.#apiClient.cloud.createFolder.mutate({
|
|
291
300
|
name: encryptedName,
|
|
292
301
|
parentId: parentFolderId ?? null,
|
|
293
|
-
nameKey: sodium.to_hex(
|
|
302
|
+
nameKey: sodium.to_hex(encryptedNameKey),
|
|
294
303
|
});
|
|
295
|
-
const folder = await apiNodeToExternalNodeFull(
|
|
304
|
+
const folder = await apiNodeToExternalNodeFull(createdFolder, this.#keys);
|
|
296
305
|
const users = folder.parent?.users?.filter(([u]) => u.id !== this.#client.app.userId) ??
|
|
297
306
|
[];
|
|
298
307
|
if (users.length > 0) {
|
|
@@ -316,7 +325,7 @@ export class SecrecyCloudClient {
|
|
|
316
325
|
});
|
|
317
326
|
return apiDataToExternal(data, this.#keys);
|
|
318
327
|
}
|
|
319
|
-
async shareNode(input) {
|
|
328
|
+
async shareNode(input, progress) {
|
|
320
329
|
const userIds = 'rights' in input
|
|
321
330
|
? Array.isArray(input.nodes)
|
|
322
331
|
? input.nodes.map(({ userId }) => userId)
|
|
@@ -324,27 +333,70 @@ export class SecrecyCloudClient {
|
|
|
324
333
|
? input.nodes.userIds
|
|
325
334
|
: [input.nodes.userId]
|
|
326
335
|
: input.users.map(({ id }) => id);
|
|
327
|
-
const nodesToShare = 'nodes' in input
|
|
328
|
-
? input.nodes
|
|
329
|
-
: {
|
|
330
|
-
nodeId: input.nodeId,
|
|
331
|
-
userIds: input.users.map(({ id }) => id),
|
|
332
|
-
};
|
|
333
336
|
const [publicKeysMap, nodesIdsMap] = await Promise.all([
|
|
334
337
|
this.#client.app.userPublicKey(userIds),
|
|
335
|
-
this.#apiClient.cloud.shareNode.mutate(
|
|
338
|
+
this.#apiClient.cloud.shareNode.mutate('nodes' in input
|
|
339
|
+
? input.nodes
|
|
340
|
+
: {
|
|
341
|
+
nodeId: input.nodeId,
|
|
342
|
+
userIds: input.users.map(({ id }) => id),
|
|
343
|
+
}),
|
|
336
344
|
]);
|
|
337
|
-
const
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
const maxNodesBatchSize = 1000;
|
|
346
|
+
const totalNodesToShare = Object.values(nodesIdsMap).reduce((size, ids) => size + ids.length, 0);
|
|
347
|
+
const chunks = totalNodesToShare > maxNodesBatchSize
|
|
348
|
+
? chunkByTotalItems(nodesIdsMap, maxNodesBatchSize)
|
|
349
|
+
: [nodesIdsMap];
|
|
350
|
+
const details = await chunks.reduce(async (pendingState, nodesMap, index) => {
|
|
351
|
+
const state = await pendingState;
|
|
352
|
+
const infos = await this.encryptNodesForUsers(nodesMap, publicKeysMap);
|
|
353
|
+
const subState = await this.#apiClient.cloud.shareNodeFinish.mutate(Object.entries(infos).map('rights' in input
|
|
354
|
+
? ([userId, nodes]) => ({ userId, nodes, rights: input.rights })
|
|
355
|
+
: ([userId, nodes]) => {
|
|
356
|
+
const user = input.users.find((user) => user.id === userId);
|
|
357
|
+
if (!user) {
|
|
358
|
+
throw new Error(`Unable to find rights for user: ${userId}`);
|
|
359
|
+
}
|
|
360
|
+
return { userId, nodes, rights: user.rights };
|
|
361
|
+
}));
|
|
362
|
+
const currentProgress = Math.min((index + 1) * maxNodesBatchSize, totalNodesToShare);
|
|
363
|
+
progress?.({
|
|
364
|
+
total: totalNodesToShare,
|
|
365
|
+
current: currentProgress,
|
|
366
|
+
percent: Math.round((currentProgress / totalNodesToShare) * 100),
|
|
367
|
+
});
|
|
368
|
+
return {
|
|
369
|
+
missingNodeAccesses: [
|
|
370
|
+
...state.missingNodeAccesses,
|
|
371
|
+
...(subState.isFinished
|
|
372
|
+
? []
|
|
373
|
+
: subState.details.missingNodeAccesses),
|
|
374
|
+
],
|
|
375
|
+
missingDataAccesses: [
|
|
376
|
+
...state.missingDataAccesses,
|
|
377
|
+
...(subState.isFinished
|
|
378
|
+
? []
|
|
379
|
+
: subState.details.missingDataAccesses),
|
|
380
|
+
],
|
|
381
|
+
invalidRightsAccesses: [
|
|
382
|
+
...state.invalidRightsAccesses,
|
|
383
|
+
...(subState.isFinished
|
|
384
|
+
? []
|
|
385
|
+
: subState.details.invalidRightsAccesses),
|
|
386
|
+
],
|
|
387
|
+
};
|
|
388
|
+
}, Promise.resolve({
|
|
389
|
+
missingNodeAccesses: [],
|
|
390
|
+
missingDataAccesses: [],
|
|
391
|
+
invalidRightsAccesses: [],
|
|
392
|
+
}));
|
|
393
|
+
const errorDetailsLength = details.invalidRightsAccesses.length +
|
|
394
|
+
details.missingDataAccesses.length +
|
|
395
|
+
details.missingNodeAccesses.length;
|
|
396
|
+
return {
|
|
397
|
+
isFinished: errorDetailsLength === 0,
|
|
398
|
+
details: details,
|
|
399
|
+
};
|
|
348
400
|
}
|
|
349
401
|
async updateNode({ nodeId, name, isFavorite, deletedAt, }) {
|
|
350
402
|
let node = nodesCache.get(nodeId);
|
|
@@ -514,9 +566,11 @@ export class SecrecyCloudClient {
|
|
|
514
566
|
key = key
|
|
515
567
|
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), this.#keys.publicKey, this.#keys.privateKey))
|
|
516
568
|
: null;
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
569
|
+
const { encryptedNameKey, encryptedName } = await generateAndEncryptNameAndKey({
|
|
570
|
+
name,
|
|
571
|
+
privateKey: this.#keys.privateKey,
|
|
572
|
+
publicKey: this.#keys.publicKey,
|
|
573
|
+
});
|
|
520
574
|
const saveInCloud = await this.#apiClient.cloud.saveInCloud.mutate({
|
|
521
575
|
dataId,
|
|
522
576
|
key,
|
|
@@ -581,18 +635,10 @@ export class SecrecyCloudClient {
|
|
|
581
635
|
const diff = missingNodeIds.filter((id) => !fetchedNodes.some((node) => node.id === id));
|
|
582
636
|
throw new Error(`Unable to fetch some node infos (${diff.join(', ')})`);
|
|
583
637
|
}
|
|
584
|
-
|
|
585
|
-
return
|
|
586
|
-
id: node.id,
|
|
587
|
-
type: node.type,
|
|
588
|
-
name: node.name,
|
|
589
|
-
access: { nameKey: node.access.nameKey },
|
|
590
|
-
history: node.history.map((data) => ({
|
|
591
|
-
id: data.id,
|
|
592
|
-
key: data.access.key,
|
|
593
|
-
})),
|
|
594
|
-
};
|
|
638
|
+
const finalNodes = await Promise.all(fetchedNodes.map((node) => {
|
|
639
|
+
return apiNodeForEncryptionToInternal(node, this.#keys);
|
|
595
640
|
}));
|
|
641
|
+
nodes.push(...finalNodes);
|
|
596
642
|
const nodesMappedUsers = {};
|
|
597
643
|
for (const userId in userNodes) {
|
|
598
644
|
nodesMappedUsers[userId] ??= [];
|
|
@@ -607,7 +653,6 @@ export class SecrecyCloudClient {
|
|
|
607
653
|
}
|
|
608
654
|
const nameKey = node.access?.nameKey;
|
|
609
655
|
const publicKey = userPublicKeys[userId];
|
|
610
|
-
nodesEncryptionCache.set(node.id, node);
|
|
611
656
|
nodesMappedUsers[userId].push({
|
|
612
657
|
id: node.id,
|
|
613
658
|
nameKey: nameKey !== null
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sodium } from '../../sodium.js';
|
|
2
2
|
import { decryptCryptoBox } from '../../crypto/index.js';
|
|
3
|
-
import { nodesCache } from '../../cache.js';
|
|
3
|
+
import { nodesCache, nodesEncryptionCache } from '../../cache.js';
|
|
4
4
|
import { decryptSecretStream } from '../../crypto/data.js';
|
|
5
5
|
import { apiDataToInternal, internalDataToExternalData } from './data.js';
|
|
6
6
|
async function apiNodeToInternal(apiNode, keyPair) {
|
|
@@ -46,7 +46,7 @@ export async function apiNodeFullToInternalFull(apiNodeFull, keyPair) {
|
|
|
46
46
|
const f = await apiNodeToInternal(apiNodeFull, keyPair);
|
|
47
47
|
const nodeFull = {
|
|
48
48
|
...f,
|
|
49
|
-
current: apiNodeFull.current
|
|
49
|
+
current: !!apiNodeFull.current
|
|
50
50
|
? apiDataToInternal(apiNodeFull.current, keyPair)
|
|
51
51
|
: undefined,
|
|
52
52
|
parent: apiNodeFull.parent !== null
|
|
@@ -92,3 +92,27 @@ export async function apiNodeToExternal(apiNode, keyPair) {
|
|
|
92
92
|
const internal = await apiNodeToInternal(apiNode, keyPair);
|
|
93
93
|
return internalNodeToNode(internal);
|
|
94
94
|
}
|
|
95
|
+
export async function apiNodeForEncryptionToInternal(apiNode, keyPair) {
|
|
96
|
+
const history = apiNode.history.map((history) => {
|
|
97
|
+
const key = decryptCryptoBox(sodium.from_hex(history.access.key), history.access.sharedByPublicKey, keyPair.privateKey);
|
|
98
|
+
return {
|
|
99
|
+
id: history.id,
|
|
100
|
+
key: sodium.to_hex(key),
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
const internal = {
|
|
104
|
+
id: apiNode.id,
|
|
105
|
+
type: apiNode.type,
|
|
106
|
+
access: apiNode.access,
|
|
107
|
+
name: apiNode.name,
|
|
108
|
+
history: history,
|
|
109
|
+
};
|
|
110
|
+
internal.access = { ...apiNode.access };
|
|
111
|
+
if (apiNode.access.nameKey !== null) {
|
|
112
|
+
const key = decryptCryptoBox(sodium.from_hex(apiNode.access.nameKey), apiNode.access.sharedByPublicKey, keyPair.privateKey);
|
|
113
|
+
internal.name = sodium.to_string(await decryptSecretStream(key, sodium.from_hex(internal.name)));
|
|
114
|
+
internal.access.nameKey = sodium.to_hex(key);
|
|
115
|
+
}
|
|
116
|
+
nodesEncryptionCache.set(apiNode.id, internal);
|
|
117
|
+
return internal;
|
|
118
|
+
}
|
package/dist/lib/client/index.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { BaseClient } from '../base-client.js';
|
|
2
|
-
import { encryptSecretStream } from '../crypto/data.js';
|
|
3
|
-
import { sodium } from '../sodium.js';
|
|
4
2
|
import { SecrecyCloudClient } from './SecrecyCloudClient.js';
|
|
5
3
|
import { SecrecyMailClient } from './SecrecyMailClient.js';
|
|
6
4
|
import { SecrecyAppClient } from './SecrecyAppClient.js';
|
|
@@ -11,11 +9,6 @@ import { SecrecyPayClient } from './SecrecyPayClient.js';
|
|
|
11
9
|
import { SecrecyUserClient } from './SecrecyUserClient.js';
|
|
12
10
|
import { SecrecyPseudonymClient } from './SecrecyPseudonymClient.js';
|
|
13
11
|
import { decryptAnonymous } from '../crypto/index.js';
|
|
14
|
-
export const encryptName = async (name, nameKey) => {
|
|
15
|
-
const { data } = await encryptSecretStream(sodium.from_hex(nameKey), sodium.from_string(name));
|
|
16
|
-
const nameEncrypted = sodium.to_hex(data);
|
|
17
|
-
return nameEncrypted;
|
|
18
|
-
};
|
|
19
12
|
export class SecrecyClient extends BaseClient {
|
|
20
13
|
#keys;
|
|
21
14
|
cloud;
|
|
@@ -30,6 +23,7 @@ export class SecrecyClient extends BaseClient {
|
|
|
30
23
|
super({
|
|
31
24
|
session: opts.uaSession,
|
|
32
25
|
secrecyUrls: opts.secrecyUrls,
|
|
26
|
+
apiClient: opts.apiClient,
|
|
33
27
|
onAccessDenied: async () => {
|
|
34
28
|
console.log('[CLIENT] - Access denied');
|
|
35
29
|
try {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { encryptCryptoBox } from '.';
|
|
2
|
+
import { sodium } from '../sodium';
|
|
3
|
+
import { encryptSecretStream, secretStreamKeygen } from './data';
|
|
4
|
+
export async function encryptName(name, nameKey) {
|
|
5
|
+
const { data } = await encryptSecretStream(sodium.from_hex(nameKey), sodium.from_string(name));
|
|
6
|
+
return sodium.to_hex(data);
|
|
7
|
+
}
|
|
8
|
+
export async function generateAndEncryptNameAndKey(args) {
|
|
9
|
+
const nameKey = secretStreamKeygen();
|
|
10
|
+
const encryptedName = await encryptName(args.name, sodium.to_hex(nameKey));
|
|
11
|
+
const encryptedNameKey = sodium.to_hex(encryptCryptoBox(nameKey, args.publicKey, args.privateKey));
|
|
12
|
+
return {
|
|
13
|
+
nameKey,
|
|
14
|
+
encryptedName,
|
|
15
|
+
encryptedNameKey,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function chunkByTotalItems(input, maxItemsPerChunk = 1000) {
|
|
2
|
+
const entries = Object.entries(input);
|
|
3
|
+
const chunks = [];
|
|
4
|
+
let currentChunk = {};
|
|
5
|
+
let currentCount = 0;
|
|
6
|
+
for (const [key, values] of entries) {
|
|
7
|
+
let i = 0;
|
|
8
|
+
while (i < values.length) {
|
|
9
|
+
const remaining = maxItemsPerChunk - currentCount;
|
|
10
|
+
const take = Math.min(remaining, values.length - i);
|
|
11
|
+
if (!currentChunk[key]) {
|
|
12
|
+
currentChunk[key] = [];
|
|
13
|
+
}
|
|
14
|
+
currentChunk[key].push(...values.slice(i, i + take));
|
|
15
|
+
currentCount += take;
|
|
16
|
+
i += take;
|
|
17
|
+
if (currentCount === maxItemsPerChunk) {
|
|
18
|
+
chunks.push(currentChunk);
|
|
19
|
+
currentChunk = {};
|
|
20
|
+
currentCount = 0;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Last chunk
|
|
25
|
+
if (currentCount > 0) {
|
|
26
|
+
chunks.push(currentChunk);
|
|
27
|
+
}
|
|
28
|
+
return chunks;
|
|
29
|
+
}
|
package/dist/lib/worker/md5.js
CHANGED
|
@@ -1,18 +1,33 @@
|
|
|
1
|
+
import SparkMD5 from 'spark-md5';
|
|
1
2
|
import { workerMd5Script } from './workerCodes.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
worker.addEventListener('messageerror', reject);
|
|
7
|
-
worker.addEventListener('message', ({ data }) => {
|
|
8
|
-
if (data.event === 'md5-result') {
|
|
9
|
-
worker.terminate();
|
|
10
|
-
resolve(data.data);
|
|
11
|
-
}
|
|
12
|
-
});
|
|
13
|
-
worker.postMessage({
|
|
14
|
-
event: 'md5',
|
|
15
|
-
data,
|
|
16
|
-
});
|
|
17
|
-
});
|
|
3
|
+
function* chunks(arr, n) {
|
|
4
|
+
for (let i = 0; i < arr.length; i += n) {
|
|
5
|
+
yield arr.slice(i, i + n);
|
|
6
|
+
}
|
|
18
7
|
}
|
|
8
|
+
const CHUNK_SIZE = 8192;
|
|
9
|
+
export const md5 = process.env.NODE_ENV !== 'test'
|
|
10
|
+
? async (data) => {
|
|
11
|
+
return await new Promise((resolve, reject) => {
|
|
12
|
+
const worker = new Worker(URL.createObjectURL(new Blob([workerMd5Script], { type: 'text/javascript' })));
|
|
13
|
+
worker.addEventListener('error', reject);
|
|
14
|
+
worker.addEventListener('messageerror', reject);
|
|
15
|
+
worker.addEventListener('message', ({ data }) => {
|
|
16
|
+
if (data.event === 'md5-result') {
|
|
17
|
+
worker.terminate();
|
|
18
|
+
resolve(data.data);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
worker.postMessage({
|
|
22
|
+
event: 'md5',
|
|
23
|
+
data,
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
: async (data) => {
|
|
28
|
+
const spark = new SparkMD5.ArrayBuffer();
|
|
29
|
+
for (const chunk of chunks(data, CHUNK_SIZE)) {
|
|
30
|
+
spark.append(chunk.buffer);
|
|
31
|
+
}
|
|
32
|
+
return spark.end();
|
|
33
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { decryptSecretStream, encryptSecretStream, } from '../crypto/data.js';
|
|
1
2
|
import { workerSodiumScript } from './workerCodes.js';
|
|
2
3
|
// const ensureNonDetachedUniqueBuffers = (
|
|
3
4
|
// values: Transferable[]
|
|
@@ -11,85 +12,93 @@ import { workerSodiumScript } from './workerCodes.js';
|
|
|
11
12
|
// }
|
|
12
13
|
// })
|
|
13
14
|
// );
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
15
|
+
export const encrypt = process.env.NODE_ENV !== 'test'
|
|
16
|
+
? async (key, dataToEncrypt, progress, signal) => {
|
|
17
|
+
return await new Promise((resolve, reject) => {
|
|
18
|
+
void progress?.({
|
|
19
|
+
current: 0,
|
|
20
|
+
percent: 0,
|
|
21
|
+
total: dataToEncrypt.byteLength,
|
|
22
|
+
});
|
|
23
|
+
const worker = new Worker(URL.createObjectURL(new Blob([workerSodiumScript], { type: 'text/javascript' })));
|
|
24
|
+
worker.addEventListener('error', reject);
|
|
25
|
+
worker.addEventListener('messageerror', reject);
|
|
26
|
+
worker.addEventListener('message', ({ data }) => {
|
|
27
|
+
switch (data.event) {
|
|
28
|
+
case 'ready': {
|
|
29
|
+
const postData = {
|
|
30
|
+
event: 'encrypt',
|
|
31
|
+
data: dataToEncrypt,
|
|
32
|
+
key,
|
|
33
|
+
};
|
|
34
|
+
worker.postMessage(postData, {
|
|
35
|
+
transfer: [postData.data.buffer],
|
|
36
|
+
});
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case 'encrypt-progress': {
|
|
40
|
+
if (signal?.aborted === true) {
|
|
41
|
+
const abortError = new Error('Aborted');
|
|
42
|
+
abortError.name = 'AbortError';
|
|
43
|
+
worker.terminate();
|
|
44
|
+
reject(abortError);
|
|
45
|
+
}
|
|
46
|
+
void progress?.(data.data);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case 'encrypt-result': {
|
|
41
50
|
worker.terminate();
|
|
42
|
-
|
|
51
|
+
resolve(data.data);
|
|
43
52
|
}
|
|
44
|
-
void progress?.(data.data);
|
|
45
|
-
break;
|
|
46
|
-
}
|
|
47
|
-
case 'encrypt-result': {
|
|
48
|
-
worker.terminate();
|
|
49
|
-
resolve(data.data);
|
|
50
53
|
}
|
|
51
|
-
}
|
|
54
|
+
});
|
|
52
55
|
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
56
|
+
}
|
|
57
|
+
: async (key, dataToEncrypt, progress, signal) => {
|
|
58
|
+
return encryptSecretStream(key, dataToEncrypt);
|
|
59
|
+
};
|
|
60
|
+
export const decrypt = process.env.NODE_ENV !== 'test'
|
|
61
|
+
? async (key, dataToDecrypt, progress, signal) => {
|
|
62
|
+
return await new Promise((resolve, reject) => {
|
|
63
|
+
void progress?.({
|
|
64
|
+
current: 0,
|
|
65
|
+
percent: 0,
|
|
66
|
+
total: dataToDecrypt.byteLength,
|
|
67
|
+
});
|
|
68
|
+
const worker = new Worker(URL.createObjectURL(new Blob([workerSodiumScript], { type: 'text/javascript' })));
|
|
69
|
+
worker.addEventListener('error', reject);
|
|
70
|
+
worker.addEventListener('messageerror', reject);
|
|
71
|
+
worker.addEventListener('message', ({ data }) => {
|
|
72
|
+
switch (data.event) {
|
|
73
|
+
case 'ready': {
|
|
74
|
+
const postData = {
|
|
75
|
+
event: 'decrypt',
|
|
76
|
+
key,
|
|
77
|
+
data: dataToDecrypt,
|
|
78
|
+
};
|
|
79
|
+
worker.postMessage(postData, {
|
|
80
|
+
transfer: [postData.data.buffer],
|
|
81
|
+
});
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case 'decrypt-progress': {
|
|
85
|
+
if (signal?.aborted === true) {
|
|
86
|
+
const abortError = new Error('Aborted');
|
|
87
|
+
abortError.name = 'AbortError';
|
|
88
|
+
worker.terminate();
|
|
89
|
+
reject(abortError);
|
|
90
|
+
}
|
|
91
|
+
void progress?.(data.data);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case 'decrypt-result': {
|
|
82
95
|
worker.terminate();
|
|
83
|
-
|
|
96
|
+
resolve(data.data);
|
|
84
97
|
}
|
|
85
|
-
void progress?.(data.data);
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
case 'decrypt-result': {
|
|
89
|
-
worker.terminate();
|
|
90
|
-
resolve(data.data);
|
|
91
98
|
}
|
|
92
|
-
}
|
|
99
|
+
});
|
|
93
100
|
});
|
|
94
|
-
}
|
|
95
|
-
|
|
101
|
+
}
|
|
102
|
+
: async (key, dataToDecrypt, progress, signal) => {
|
|
103
|
+
return decryptSecretStream(key, dataToDecrypt);
|
|
104
|
+
};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
function* chunks(arr, n) {
|
|
3
|
+
for (let i = 0; i < arr.length; i += n) {
|
|
4
|
+
yield arr.slice(i, i + n);
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function assert(c, message) {
|
|
8
|
+
if (!c) {
|
|
9
|
+
throw new Error(message);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function encrypt(key) {
|
|
13
|
+
let destroyed = false;
|
|
14
|
+
const { state, header } = sodium.crypto_secretstream_xchacha20poly1305_init_push(key);
|
|
15
|
+
const encrypt = (tag, plaintext) => {
|
|
16
|
+
assert(destroyed === false, 'state already destroyed');
|
|
17
|
+
return sodium.crypto_secretstream_xchacha20poly1305_push(state, plaintext, null, tag);
|
|
18
|
+
};
|
|
19
|
+
function destroy() {
|
|
20
|
+
assert(destroyed === false, 'state already destroyed');
|
|
21
|
+
destroyed = true;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
encrypt,
|
|
25
|
+
destroy,
|
|
26
|
+
header,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function decrypt(header, key) {
|
|
30
|
+
assert(header.byteLength >=
|
|
31
|
+
sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES, 'header must be at least HEADERBYTES (' +
|
|
32
|
+
sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES +
|
|
33
|
+
') long');
|
|
34
|
+
assert(key.byteLength >= sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES, 'key must be at least KEYBYTES (' +
|
|
35
|
+
sodium.crypto_secretstream_xchacha20poly1305_KEYBYTES +
|
|
36
|
+
') long');
|
|
37
|
+
let destroyed = false;
|
|
38
|
+
const state = sodium.crypto_secretstream_xchacha20poly1305_init_pull(header, key);
|
|
39
|
+
const decrypt = (ciphertext) => {
|
|
40
|
+
assert(destroyed === false, 'state already destroyed');
|
|
41
|
+
return sodium.crypto_secretstream_xchacha20poly1305_pull(state, ciphertext);
|
|
42
|
+
};
|
|
43
|
+
function destroy() {
|
|
44
|
+
assert(destroyed === false, 'state already destroyed');
|
|
45
|
+
destroyed = true;
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
decrypt,
|
|
49
|
+
destroy,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const CHUNK_SIZE = 8192;
|
|
53
|
+
export async function encryptSecretstream(key, data, progress) {
|
|
54
|
+
const { encrypt: crypt, destroy, header } = encrypt(key);
|
|
55
|
+
const cryptedChunk = CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
|
|
56
|
+
const max = Math.ceil(data.byteLength / CHUNK_SIZE) * cryptedChunk + header.byteLength;
|
|
57
|
+
progress?.({
|
|
58
|
+
percent: 0,
|
|
59
|
+
total: max,
|
|
60
|
+
current: 0,
|
|
61
|
+
});
|
|
62
|
+
const final = new Uint8Array(max);
|
|
63
|
+
const sparkEncrypted = new SparkMD5.ArrayBuffer();
|
|
64
|
+
const spark = new SparkMD5.ArrayBuffer();
|
|
65
|
+
final.set(header);
|
|
66
|
+
sparkEncrypted.append(header);
|
|
67
|
+
let total = header.byteLength;
|
|
68
|
+
progress?.({
|
|
69
|
+
percent: total / max,
|
|
70
|
+
total: max,
|
|
71
|
+
current: total,
|
|
72
|
+
});
|
|
73
|
+
let lastPercent = total / max;
|
|
74
|
+
for (const chunk of chunks(data, CHUNK_SIZE)) {
|
|
75
|
+
spark.append(chunk);
|
|
76
|
+
const tag = chunk.length < CHUNK_SIZE
|
|
77
|
+
? sodium.crypto_secretstream_xchacha20poly1305_TAG_FINAL
|
|
78
|
+
: sodium.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE;
|
|
79
|
+
const crypted = crypt(tag, chunk);
|
|
80
|
+
sparkEncrypted.append(crypted);
|
|
81
|
+
final.set(crypted, total);
|
|
82
|
+
total += crypted.byteLength;
|
|
83
|
+
const percent = total / max;
|
|
84
|
+
if (percent > lastPercent + 0.01) {
|
|
85
|
+
progress?.({
|
|
86
|
+
percent,
|
|
87
|
+
total: max,
|
|
88
|
+
current: total,
|
|
89
|
+
});
|
|
90
|
+
lastPercent = percent;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
destroy();
|
|
94
|
+
progress?.({
|
|
95
|
+
percent: 1,
|
|
96
|
+
total,
|
|
97
|
+
current: total,
|
|
98
|
+
});
|
|
99
|
+
return {
|
|
100
|
+
data: final.slice(0, total),
|
|
101
|
+
md5Encrypted: sparkEncrypted.end(),
|
|
102
|
+
md5: spark.end(),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export async function decryptSecretstream(key, data, progress) {
|
|
106
|
+
const header = data.slice(0, sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES);
|
|
107
|
+
data = data.slice(sodium.crypto_secretstream_xchacha20poly1305_HEADERBYTES);
|
|
108
|
+
const { decrypt: decryptt, destroy } = decrypt(header, key);
|
|
109
|
+
const chunkSize = CHUNK_SIZE + sodium.crypto_secretstream_xchacha20poly1305_ABYTES;
|
|
110
|
+
const max = Math.ceil(data.byteLength / chunkSize) * CHUNK_SIZE;
|
|
111
|
+
progress?.({
|
|
112
|
+
percent: 0,
|
|
113
|
+
total: max,
|
|
114
|
+
current: 0,
|
|
115
|
+
});
|
|
116
|
+
const final = new Uint8Array(max);
|
|
117
|
+
let total = 0;
|
|
118
|
+
let lastPercent = total / max;
|
|
119
|
+
for (const chunk of chunks(data, chunkSize)) {
|
|
120
|
+
const tmp = decryptt(chunk);
|
|
121
|
+
final.set(tmp.message, total);
|
|
122
|
+
total += tmp.message.byteLength;
|
|
123
|
+
const percent = total / max;
|
|
124
|
+
if (percent > lastPercent + 0.01) {
|
|
125
|
+
progress?.({
|
|
126
|
+
percent,
|
|
127
|
+
total: max,
|
|
128
|
+
current: total,
|
|
129
|
+
});
|
|
130
|
+
lastPercent = percent;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
destroy();
|
|
134
|
+
progress?.({
|
|
135
|
+
percent: 1,
|
|
136
|
+
total,
|
|
137
|
+
current: total,
|
|
138
|
+
});
|
|
139
|
+
return final.slice(0, total);
|
|
140
|
+
}
|
|
@@ -75,7 +75,7 @@ export declare class SecrecyCloudClient {
|
|
|
75
75
|
id: string;
|
|
76
76
|
rights: Rights;
|
|
77
77
|
}[];
|
|
78
|
-
}): Promise<RouterOutputs['cloud']['shareNodeFinish']>;
|
|
78
|
+
}, progress?: ProgressCallback): Promise<RouterOutputs['cloud']['shareNodeFinish']>;
|
|
79
79
|
updateNode({ nodeId, name, isFavorite, deletedAt, }: {
|
|
80
80
|
nodeId: string;
|
|
81
81
|
name?: string | null | undefined;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Node, ApiNode, ApiNodeFull, InternalNodeFull, NodeFull, KeyPair, ApiNodeParent } from '../types/index.js';
|
|
1
|
+
import type { Node, ApiNode, ApiNodeFull, InternalNodeFull, NodeFull, KeyPair, ApiNodeParent, ApiNodeForEncryption, InternalMinimalNodeForEncryption } from '../types/index.js';
|
|
2
2
|
export declare function apiNodeFullToInternalFull(apiNodeFull: ApiNodeFull, keyPair: KeyPair): Promise<InternalNodeFull>;
|
|
3
3
|
export declare function internalNodeFullToNodeFull(internal: InternalNodeFull): NodeFull;
|
|
4
4
|
export declare function apiNodeToExternalNodeFull(apiNodeFull: ApiNodeFull, keyPair: KeyPair): Promise<NodeFull>;
|
|
5
5
|
export declare function apiNodeToExternal(apiNode: ApiNode | ApiNodeParent, keyPair: KeyPair): Promise<Node>;
|
|
6
|
+
export declare function apiNodeForEncryptionToInternal(apiNode: ApiNodeForEncryption, keyPair: KeyPair): Promise<InternalMinimalNodeForEncryption>;
|
|
@@ -6,17 +6,17 @@ import { SecrecyAppClient } from './SecrecyAppClient.js';
|
|
|
6
6
|
import { SecrecyDbClient } from './SecrecyDbClient.js';
|
|
7
7
|
import { SecrecyWalletClient } from './SecrecyWalletClient.js';
|
|
8
8
|
import { SecrecyPayClient } from './SecrecyPayClient.js';
|
|
9
|
-
import { type RouterInputs } from '../client.js';
|
|
9
|
+
import { ApiClient, type RouterInputs } from '../client.js';
|
|
10
10
|
import { type KeyPair } from './types/index.js';
|
|
11
11
|
import { SecrecyUserClient } from './SecrecyUserClient.js';
|
|
12
12
|
import { SecrecyPseudonymClient } from './SecrecyPseudonymClient.js';
|
|
13
13
|
export type NewMail = Pick<RouterInputs['mail']['createDraft'], 'body' | 'subject' | 'senderFiles' | 'recipients' | 'replyToId'>;
|
|
14
14
|
export type ProgressCallback = (progress: Progress) => Promise<void>;
|
|
15
|
-
export declare const encryptName: (name: string, nameKey: string) => Promise<string>;
|
|
16
15
|
export interface SecrecyClientOptions {
|
|
17
16
|
uaSession: string;
|
|
18
17
|
uaKeys: KeyPair;
|
|
19
18
|
uaJwt: string;
|
|
19
|
+
apiClient?: ApiClient;
|
|
20
20
|
secrecyUrls?: Partial<SecrecyUrls>;
|
|
21
21
|
}
|
|
22
22
|
export declare class SecrecyClient extends BaseClient {
|
|
@@ -58,6 +58,7 @@ export type InternalMinimalNodeForEncryption = {
|
|
|
58
58
|
export type InternalNode = Node<InternalNodeBreadcrumbItem, NameKey>;
|
|
59
59
|
export type InternalNodeFull = NodeFull<InternalNodeBreadcrumbItem, NameKey, InternalData>;
|
|
60
60
|
export type ApiNode = RouterOutputs['cloud']['nodeById'];
|
|
61
|
+
export type ApiNodeForEncryption = RouterOutputs['cloud']['nodesForEncryption'][number];
|
|
61
62
|
export type ApiNodeFull = RouterOutputs['cloud']['nodeFullById'];
|
|
62
63
|
export type ApiNodeParent = NonNullable<RouterOutputs['cloud']['nodeFullById']['parent']>;
|
|
63
64
|
export type NodeType = ApiNode['type'];
|
|
@@ -69,4 +70,21 @@ export type EncryptedNodeInfos = {
|
|
|
69
70
|
key: string | null;
|
|
70
71
|
}[];
|
|
71
72
|
};
|
|
73
|
+
export type ShareNodeDetails = {
|
|
74
|
+
missingNodeAccesses: {
|
|
75
|
+
userId: string;
|
|
76
|
+
nodeId: string;
|
|
77
|
+
}[];
|
|
78
|
+
missingDataAccesses: {
|
|
79
|
+
userId: string;
|
|
80
|
+
dataId: string;
|
|
81
|
+
nodeId: string;
|
|
82
|
+
}[];
|
|
83
|
+
invalidRightsAccesses: {
|
|
84
|
+
userId: string;
|
|
85
|
+
current: 'admin' | 'write' | 'read';
|
|
86
|
+
nodeId: string;
|
|
87
|
+
expect: 'admin' | 'write' | 'read';
|
|
88
|
+
}[];
|
|
89
|
+
};
|
|
72
90
|
export {};
|
package/dist/types/client.d.ts
CHANGED
|
@@ -5392,10 +5392,12 @@ export declare const createTRPCClient: (opts: CreateTrpcClientOptions) => {
|
|
|
5392
5392
|
id: string;
|
|
5393
5393
|
access: {
|
|
5394
5394
|
key: string;
|
|
5395
|
+
sharedByPublicKey: string;
|
|
5395
5396
|
};
|
|
5396
5397
|
}[];
|
|
5397
5398
|
access: {
|
|
5398
5399
|
nameKey: string;
|
|
5400
|
+
sharedByPublicKey: string;
|
|
5399
5401
|
};
|
|
5400
5402
|
}[];
|
|
5401
5403
|
_output_out: {
|
|
@@ -5406,10 +5408,12 @@ export declare const createTRPCClient: (opts: CreateTrpcClientOptions) => {
|
|
|
5406
5408
|
id: string;
|
|
5407
5409
|
access: {
|
|
5408
5410
|
key: string;
|
|
5411
|
+
sharedByPublicKey: string;
|
|
5409
5412
|
};
|
|
5410
5413
|
}[];
|
|
5411
5414
|
access: {
|
|
5412
5415
|
nameKey: string;
|
|
5416
|
+
sharedByPublicKey: string;
|
|
5413
5417
|
};
|
|
5414
5418
|
}[];
|
|
5415
5419
|
}, unknown>>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function encryptName(name: string, nameKey: string): Promise<string>;
|
|
2
|
+
export declare function generateAndEncryptNameAndKey(args: {
|
|
3
|
+
name: string;
|
|
4
|
+
privateKey: string;
|
|
5
|
+
publicKey: string;
|
|
6
|
+
}): Promise<{
|
|
7
|
+
nameKey: Uint8Array<ArrayBufferLike>;
|
|
8
|
+
encryptedName: string;
|
|
9
|
+
encryptedNameKey: string;
|
|
10
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function chunkByTotalItems<T>(input: Record<string, T[]>, maxItemsPerChunk?: number): Record<string, T[]>[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare
|
|
1
|
+
export declare const md5: (data: Uint8Array) => Promise<string>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export declare
|
|
3
|
-
export declare
|
|
1
|
+
import { type EncryptedFile, type Progress } from '../crypto/data.js';
|
|
2
|
+
export declare const encrypt: (key: Uint8Array, dataToEncrypt: Uint8Array, progress?: (progress: Progress) => Promise<void>, signal?: AbortSignal) => Promise<EncryptedFile>;
|
|
3
|
+
export declare const decrypt: (key: Uint8Array, dataToDecrypt: Uint8Array, progress?: (progress: Progress) => Promise<void>, signal?: AbortSignal) => Promise<Uint8Array>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function encryptSecretstream(key: any, data: any, progress: any): Promise<{
|
|
2
|
+
data: Uint8Array<ArrayBuffer>;
|
|
3
|
+
md5Encrypted: any;
|
|
4
|
+
md5: any;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function decryptSecretstream(key: any, data: any, progress: any): Promise<Uint8Array<ArrayBuffer>>;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@secrecy/lib",
|
|
3
3
|
"author": "Anonymize <anonymize@gmail.com>",
|
|
4
4
|
"description": "Anonymize Secrecy Library",
|
|
5
|
-
"version": "1.62.0-feat-node-sharing.
|
|
5
|
+
"version": "1.62.0-feat-node-sharing.4",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "https://github.com/anonymize-org/lib.git"
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"typescript": "^5.7.2"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@secrecy/trpc-api-types": "1.33.0-feat-share-node-enhanced.
|
|
77
|
+
"@secrecy/trpc-api-types": "1.33.0-feat-share-node-enhanced.12",
|
|
78
78
|
"@trpc/client": "10.45.2",
|
|
79
79
|
"@trpc/server": "10.45.2",
|
|
80
80
|
"@types/libsodium-wrappers-sumo": "^0.7.8",
|