@secrecy/lib 1.73.6 → 1.74.0-feat-groups-identity.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/lib/base-client.js +5 -3
- package/dist/lib/client/SecrecyAppClient.js +13 -17
- package/dist/lib/client/SecrecyCloudClient.js +129 -137
- package/dist/lib/client/SecrecyDbClient.js +3 -7
- package/dist/lib/client/SecrecyMailClient.js +38 -48
- package/dist/lib/client/SecrecyOrganizationClient.js +10 -12
- package/dist/lib/client/SecrecyPayClient.js +1 -5
- package/dist/lib/client/SecrecyPseudonymClient.js +4 -8
- package/dist/lib/client/SecrecyUserClient.js +11 -11
- package/dist/lib/client/SecrecyWalletClient.js +0 -2
- package/dist/lib/client/convert/data.js +4 -4
- package/dist/lib/client/convert/mail.js +5 -6
- package/dist/lib/client/convert/node.js +46 -34
- package/dist/lib/client/helpers.js +17 -11
- package/dist/lib/client/index.js +45 -12
- package/dist/lib/client/storage.js +3 -2
- package/dist/lib/client/types/identity.js +18 -0
- package/dist/lib/client/types/index.js +3 -7
- package/dist/lib/index.js +1 -0
- package/dist/types/client/SecrecyAppClient.d.ts +2 -3
- package/dist/types/client/SecrecyCloudClient.d.ts +18 -18
- package/dist/types/client/SecrecyDbClient.d.ts +1 -3
- package/dist/types/client/SecrecyMailClient.d.ts +2 -3
- package/dist/types/client/SecrecyOrganizationClient.d.ts +2 -3
- package/dist/types/client/SecrecyPayClient.d.ts +1 -3
- package/dist/types/client/SecrecyPseudonymClient.d.ts +2 -3
- package/dist/types/client/SecrecyUserClient.d.ts +2 -3
- package/dist/types/client/convert/data.d.ts +3 -3
- package/dist/types/client/convert/mail.d.ts +3 -5
- package/dist/types/client/convert/node.d.ts +5 -5
- package/dist/types/client/index.d.ts +9 -2
- package/dist/types/client/storage.d.ts +3 -2
- package/dist/types/client/types/identity.d.ts +29 -0
- package/dist/types/client/types/index.d.ts +13 -9
- package/dist/types/client/types/mail.d.ts +2 -1
- package/dist/types/client/types/node.d.ts +12 -9
- package/dist/types/client/types/user.d.ts +15 -0
- package/dist/types/client.d.ts +679 -513
- package/dist/types/crypto/index.d.ts +3 -3
- package/dist/types/index.d.ts +2 -1
- package/package.json +2 -2
|
@@ -17,36 +17,27 @@ import { chunkByTotalItems } from '../utils/object.js';
|
|
|
17
17
|
import axios from 'axios';
|
|
18
18
|
export class SecrecyCloudClient {
|
|
19
19
|
#client;
|
|
20
|
-
|
|
21
|
-
#apiClient;
|
|
22
|
-
constructor(client, keys, apiClient) {
|
|
20
|
+
constructor(client) {
|
|
23
21
|
this.#client = client;
|
|
24
|
-
this.#keys = keys;
|
|
25
|
-
this.#apiClient = apiClient;
|
|
26
22
|
}
|
|
27
23
|
async addDataToHistory({ dataId, nodeId, }) {
|
|
28
|
-
const addDataToHistory = await this.#apiClient.cloud.addDataToHistory.mutate({
|
|
29
|
-
|
|
24
|
+
const addDataToHistory = await this.#client.apiClient.cloud.addDataToHistory.mutate({
|
|
25
|
+
dataId,
|
|
26
|
+
nodeId,
|
|
27
|
+
});
|
|
28
|
+
const node = await apiNodeFullToInternalFull(addDataToHistory, this.#client.keyPairs);
|
|
30
29
|
const data = node.history.find((d) => d.id === dataId);
|
|
31
30
|
if (data !== undefined) {
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const users = node.users.filter(([u]) => u.id !== me.id);
|
|
35
|
-
const userIds = users.map(([user]) => user.id);
|
|
36
|
-
const userKeys = await this.#client.app.userPublicKey(userIds);
|
|
37
|
-
const shares = users.map(([user]) => {
|
|
38
|
-
const publicKey = userKeys[user.id];
|
|
39
|
-
if (!publicKey) {
|
|
40
|
-
throw new Error('Unable to retrieve share by public key!');
|
|
41
|
-
}
|
|
31
|
+
const othersIdentities = Object.entries(node.identities).filter(([id]) => id !== this.#client.uaIdentity.identityPubKey);
|
|
32
|
+
const shares = othersIdentities.map(([publicKey]) => {
|
|
42
33
|
return {
|
|
43
|
-
|
|
34
|
+
pubKey: publicKey,
|
|
44
35
|
key: data.key
|
|
45
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), publicKey, this.#
|
|
36
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), publicKey, this.#client.uaPrivateKey))
|
|
46
37
|
: null,
|
|
47
38
|
};
|
|
48
39
|
});
|
|
49
|
-
await this.#apiClient.cloud.shareDataInHistory.mutate({
|
|
40
|
+
await this.#client.apiClient.cloud.shareDataInHistory.mutate({
|
|
50
41
|
dataId: data.id,
|
|
51
42
|
nodeId,
|
|
52
43
|
users: shares,
|
|
@@ -75,7 +66,7 @@ export class SecrecyCloudClient {
|
|
|
75
66
|
? await encrypt(dataKey, compressed, encryptProgress, signal)
|
|
76
67
|
: { data: compressed, md5: await md5(compressed) };
|
|
77
68
|
const encryptedDataKey = dataKey
|
|
78
|
-
? encryptCryptoBox(dataKey, this.#
|
|
69
|
+
? encryptCryptoBox(dataKey, this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)
|
|
79
70
|
: null;
|
|
80
71
|
await uploadProgress?.({
|
|
81
72
|
total: encryptedData.byteLength,
|
|
@@ -102,7 +93,7 @@ export class SecrecyCloudClient {
|
|
|
102
93
|
size: BigInt(dataBuffer.byteLength),
|
|
103
94
|
...filetype,
|
|
104
95
|
};
|
|
105
|
-
const uploadData = await this.#apiClient.cloud.uploadLiteData.mutate(uploadDataArgs, { signal });
|
|
96
|
+
const uploadData = await this.#client.apiClient.cloud.uploadLiteData.mutate(uploadDataArgs, { signal });
|
|
106
97
|
await uploadProgress?.({
|
|
107
98
|
total: encryptedData.byteLength,
|
|
108
99
|
current: encryptedData.byteLength,
|
|
@@ -138,14 +129,14 @@ export class SecrecyCloudClient {
|
|
|
138
129
|
...filetype,
|
|
139
130
|
};
|
|
140
131
|
const uploadDataCaller = storageType === 's3'
|
|
141
|
-
? this.#apiClient.cloud.uploadData
|
|
142
|
-
: this.#apiClient.cloud.uploadColdData;
|
|
132
|
+
? this.#client.apiClient.cloud.uploadData
|
|
133
|
+
: this.#client.apiClient.cloud.uploadColdData;
|
|
143
134
|
const uploadData = await uploadDataCaller.mutate(uploadDataArgs, {
|
|
144
135
|
signal,
|
|
145
136
|
});
|
|
146
137
|
if (uploadData.parts.length === 0) {
|
|
147
138
|
if (uploadData.type === 'authed' &&
|
|
148
|
-
uploadData.keyPair.pub !== this.#
|
|
139
|
+
uploadData.keyPair.pub !== this.#client.uaIdentity.identityPubKey) {
|
|
149
140
|
throw new Error('The public key does not match with cached key!');
|
|
150
141
|
}
|
|
151
142
|
await uploadProgress?.({
|
|
@@ -165,7 +156,7 @@ export class SecrecyCloudClient {
|
|
|
165
156
|
return localData;
|
|
166
157
|
}
|
|
167
158
|
const uploadDataPartEnd = async (md5, order) => {
|
|
168
|
-
return this.#apiClient.cloud.uploadDataPartEnd.mutate({ dataId: uploadData.id, md5, order }, { signal });
|
|
159
|
+
return this.#client.apiClient.cloud.uploadDataPartEnd.mutate({ dataId: uploadData.id, md5, order }, { signal });
|
|
169
160
|
};
|
|
170
161
|
const chunkParts = new Array();
|
|
171
162
|
for (const [index, chunk] of enumerate(chunks(encryptedData, Number(uploadData.partSize)))) {
|
|
@@ -240,21 +231,21 @@ export class SecrecyCloudClient {
|
|
|
240
231
|
return await this.saveInCloud({ dataId: uploadedData.id, name, nodeId });
|
|
241
232
|
}
|
|
242
233
|
async deletedNodes() {
|
|
243
|
-
const deletedNodes = await this.#apiClient.cloud.nodesDeleted.query({});
|
|
244
|
-
return await Promise.all(deletedNodes.map(async (node) => await apiNodeToExternal(node, this.#
|
|
234
|
+
const deletedNodes = await this.#client.apiClient.cloud.nodesDeleted.query({});
|
|
235
|
+
return await Promise.all(deletedNodes.map(async (node) => await apiNodeToExternal(node, this.#client.keyPairs)));
|
|
245
236
|
}
|
|
246
237
|
async sharedNodes() {
|
|
247
|
-
const nodesShared = await this.#apiClient.cloud.nodesShared.query();
|
|
248
|
-
return await Promise.all(nodesShared.map(async (node) => await apiNodeToExternal(node, this.#
|
|
238
|
+
const nodesShared = await this.#client.apiClient.cloud.nodesShared.query({});
|
|
239
|
+
return await Promise.all(nodesShared.map(async (node) => await apiNodeToExternal(node, this.#client.keyPairs)));
|
|
249
240
|
}
|
|
250
241
|
async nodesSharedWithMe(type = 'FOLDER') {
|
|
251
|
-
const nodesSharedWithMe = await this.#apiClient.cloud.nodesSharedWithMe.query({ type });
|
|
252
|
-
return await Promise.all(nodesSharedWithMe.map(async (node) => await apiNodeToExternal(node, this.#
|
|
242
|
+
const nodesSharedWithMe = await this.#client.apiClient.cloud.nodesSharedWithMe.query({ type });
|
|
243
|
+
return await Promise.all(nodesSharedWithMe.map(async (node) => await apiNodeToExternal(node, this.#client.keyPairs)));
|
|
253
244
|
}
|
|
254
|
-
async deleteNodeSharing({ nodeId,
|
|
255
|
-
const { isDeleted } = await this.#apiClient.cloud.deleteNodeSharing.mutate({
|
|
245
|
+
async deleteNodeSharing({ nodeId, destPubKey, }) {
|
|
246
|
+
const { isDeleted } = await this.#client.apiClient.cloud.deleteNodeSharing.mutate({
|
|
256
247
|
nodeId,
|
|
257
|
-
|
|
248
|
+
destPubKey,
|
|
258
249
|
});
|
|
259
250
|
return isDeleted;
|
|
260
251
|
}
|
|
@@ -267,14 +258,14 @@ export class SecrecyCloudClient {
|
|
|
267
258
|
throw new Error(`Node (${nodeId}) does not exists`);
|
|
268
259
|
}
|
|
269
260
|
}
|
|
270
|
-
if (node.
|
|
271
|
-
throw new Error(`
|
|
261
|
+
if (!node.accesses[0]) {
|
|
262
|
+
throw new Error(`No access found for node ${nodeId}`);
|
|
272
263
|
}
|
|
273
264
|
name =
|
|
274
|
-
typeof name === 'string' && node.
|
|
275
|
-
? await encryptName(name, node.
|
|
265
|
+
typeof name === 'string' && node.accesses[0].nameKey !== null
|
|
266
|
+
? await encryptName(name, node.accesses[0].nameKey)
|
|
276
267
|
: null;
|
|
277
|
-
const { isDuplicated } = await this.#apiClient.cloud.duplicateNode.mutate({
|
|
268
|
+
const { isDuplicated } = await this.#client.apiClient.cloud.duplicateNode.mutate({
|
|
278
269
|
nodeId,
|
|
279
270
|
folderId: folderId ?? null,
|
|
280
271
|
name,
|
|
@@ -282,50 +273,54 @@ export class SecrecyCloudClient {
|
|
|
282
273
|
return isDuplicated;
|
|
283
274
|
}
|
|
284
275
|
async deleteNodeCloudTrash({ ids }) {
|
|
285
|
-
const { isDeleted } = await this.#apiClient.cloud.deleteNodeCloudTrash.mutate({ ids });
|
|
276
|
+
const { isDeleted } = await this.#client.apiClient.cloud.deleteNodeCloudTrash.mutate({ ids });
|
|
286
277
|
return isDeleted;
|
|
287
278
|
}
|
|
288
279
|
async createFolder({ name, parentFolderId, }) {
|
|
289
280
|
const { encryptedNameKey, encryptedName } = await generateAndEncryptNameAndKey({
|
|
290
281
|
name,
|
|
291
|
-
privateKey: this.#
|
|
292
|
-
publicKey: this.#
|
|
282
|
+
privateKey: this.#client.uaPrivateKey,
|
|
283
|
+
publicKey: this.#client.uaIdentity.identityPubKey,
|
|
293
284
|
});
|
|
294
|
-
const createdFolder = await this.#apiClient.cloud.createFolder.mutate({
|
|
285
|
+
const createdFolder = await this.#client.apiClient.cloud.createFolder.mutate({
|
|
295
286
|
name: encryptedName,
|
|
296
287
|
parentId: parentFolderId ?? null,
|
|
297
288
|
nameKey: encryptedNameKey,
|
|
298
289
|
});
|
|
299
|
-
const folder = await apiNodeToExternalNodeFull(createdFolder, this.#
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
290
|
+
const folder = await apiNodeToExternalNodeFull(createdFolder, this.#client.keyPairs);
|
|
291
|
+
if (folder.parent) {
|
|
292
|
+
const othersIdentities = Object.entries(folder.parent.identities).filter(([id]) => id !== this.#client.uaIdentity.identityPubKey);
|
|
293
|
+
// TODO: ??
|
|
294
|
+
if (othersIdentities.length > 0) {
|
|
295
|
+
await this.shareNode(othersIdentities.map(([identityPubKey, permissions]) => ({
|
|
296
|
+
pubKey: identityPubKey,
|
|
297
|
+
nodeId: folder.id,
|
|
298
|
+
rights: permissions.rights,
|
|
299
|
+
addAccess: permissions.addAccess,
|
|
300
|
+
delAccess: permissions.delAccess,
|
|
301
|
+
sharingAddAccess: permissions.sharingAddAccess,
|
|
302
|
+
sharingDelAccess: permissions.sharingDelAccess,
|
|
303
|
+
})));
|
|
304
|
+
}
|
|
311
305
|
}
|
|
312
306
|
return folder;
|
|
313
307
|
}
|
|
314
308
|
async node({ id, deleted, } = {}) {
|
|
315
|
-
const node = await this.#apiClient.cloud.nodeFullById.query({
|
|
316
|
-
|
|
309
|
+
const node = await this.#client.apiClient.cloud.nodeFullById.query({
|
|
310
|
+
id,
|
|
311
|
+
deleted,
|
|
312
|
+
});
|
|
313
|
+
return await apiNodeToExternalNodeFull(node, this.#client.keyPairs);
|
|
317
314
|
}
|
|
318
315
|
async dataMetadata({ id }) {
|
|
319
|
-
const data = await this.#apiClient.cloud.dataById.query({ id });
|
|
320
|
-
return apiDataToExternal(data, this.#
|
|
316
|
+
const data = await this.#client.apiClient.cloud.dataById.query({ id });
|
|
317
|
+
return apiDataToExternal(data, this.#client.keyPairs);
|
|
321
318
|
}
|
|
322
|
-
async shareNode(
|
|
319
|
+
async shareNode(accesses, progress) {
|
|
323
320
|
// TODO: Validate input
|
|
324
|
-
const nodesMap = await this.#apiClient.cloud.shareNode.mutate(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
.map(([userId]) => userId);
|
|
328
|
-
const publicKeysMap = await this.#client.app.userPublicKey(neededUserKey);
|
|
321
|
+
const nodesMap = await this.#client.apiClient.cloud.shareNode.mutate({
|
|
322
|
+
accesses,
|
|
323
|
+
});
|
|
329
324
|
const maxNodesBatchSize = 1000;
|
|
330
325
|
const totalNodesToShare = Object.values(nodesMap).reduce((size, ids) => size + ids.length, 0);
|
|
331
326
|
progress?.({ total: totalNodesToShare, current: 0, percent: 0 });
|
|
@@ -342,9 +337,9 @@ export class SecrecyCloudClient {
|
|
|
342
337
|
return filtered.length > 0 ? [userId, filtered] : null;
|
|
343
338
|
})
|
|
344
339
|
.filter((entry) => entry !== null));
|
|
345
|
-
const infos = await this.
|
|
346
|
-
const nodesToUpdateRights = Object.fromEntries(Object.entries(nodesMap).map(([
|
|
347
|
-
|
|
340
|
+
const infos = await this.encryptNodesForIdentities(nodesToEncrypt);
|
|
341
|
+
const nodesToUpdateRights = Object.fromEntries(Object.entries(nodesMap).map(([pubKey, nodes]) => [
|
|
342
|
+
pubKey,
|
|
348
343
|
nodes
|
|
349
344
|
.filter((node) => !node.includeKeys)
|
|
350
345
|
.map((node) => {
|
|
@@ -360,13 +355,13 @@ export class SecrecyCloudClient {
|
|
|
360
355
|
};
|
|
361
356
|
}),
|
|
362
357
|
]));
|
|
363
|
-
const withKeys = Object.fromEntries(Object.entries(infos).map(([
|
|
358
|
+
const withKeys = Object.fromEntries(Object.entries(infos).map(([pubKey, nodes]) => {
|
|
364
359
|
return [
|
|
365
|
-
|
|
360
|
+
pubKey,
|
|
366
361
|
{
|
|
367
|
-
|
|
362
|
+
pubKey,
|
|
368
363
|
nodes: nodes.map((node) => {
|
|
369
|
-
const map = nodesMap[
|
|
364
|
+
const map = nodesMap[pubKey];
|
|
370
365
|
if (!map) {
|
|
371
366
|
throw new Error('Unable to retrieve mapped nodes!');
|
|
372
367
|
}
|
|
@@ -389,20 +384,22 @@ export class SecrecyCloudClient {
|
|
|
389
384
|
];
|
|
390
385
|
}));
|
|
391
386
|
const finishInput = [];
|
|
392
|
-
for (const [
|
|
387
|
+
for (const [pubKey, nodes] of Object.entries(withKeys)) {
|
|
393
388
|
if (nodes.nodes.length === 0) {
|
|
394
389
|
continue;
|
|
395
390
|
}
|
|
396
|
-
finishInput.push({
|
|
391
|
+
finishInput.push({ pubKey, nodes: nodes.nodes });
|
|
397
392
|
}
|
|
398
|
-
for (const [
|
|
393
|
+
for (const [pubKey, nodes] of Object.entries(nodesToUpdateRights)) {
|
|
399
394
|
if (nodes.length === 0) {
|
|
400
395
|
continue;
|
|
401
396
|
}
|
|
402
|
-
finishInput.push({
|
|
397
|
+
finishInput.push({ pubKey, nodes });
|
|
403
398
|
}
|
|
404
399
|
const subState = finishInput.length > 0
|
|
405
|
-
? await this.#apiClient.cloud.shareNodeFinish.mutate(
|
|
400
|
+
? await this.#client.apiClient.cloud.shareNodeFinish.mutate({
|
|
401
|
+
accesses: finishInput,
|
|
402
|
+
})
|
|
406
403
|
: { isFinished: true, details: {} };
|
|
407
404
|
const currentProgress = Math.min((index + 1) * maxNodesBatchSize, totalNodesToShare);
|
|
408
405
|
progress?.({
|
|
@@ -449,27 +446,31 @@ export class SecrecyCloudClient {
|
|
|
449
446
|
throw `Can't find Node ${nodeId}`;
|
|
450
447
|
}
|
|
451
448
|
}
|
|
452
|
-
if (node.
|
|
453
|
-
|
|
449
|
+
if (node.accesses.find((a) => ['delete', 'write'].includes(a.rights)) ===
|
|
450
|
+
undefined) {
|
|
451
|
+
throw new Error(`No access to update node ${nodeId}`);
|
|
452
|
+
}
|
|
453
|
+
if (!node.accesses[0]) {
|
|
454
|
+
throw new Error(`No access found for node ${nodeId}`);
|
|
454
455
|
}
|
|
455
456
|
name =
|
|
456
|
-
typeof name === 'string' && node.
|
|
457
|
-
? await encryptName(name, node.
|
|
457
|
+
typeof name === 'string' && node.accesses[0].nameKey !== null
|
|
458
|
+
? await encryptName(name, node.accesses[0].nameKey)
|
|
458
459
|
: null;
|
|
459
|
-
const updateNode = await this.#apiClient.cloud.updateNode.mutate({
|
|
460
|
+
const updateNode = await this.#client.apiClient.cloud.updateNode.mutate({
|
|
460
461
|
deletedAt: deletedAt ?? null,
|
|
461
462
|
id: nodeId,
|
|
462
463
|
isFavorite: isFavorite ?? null,
|
|
463
464
|
name,
|
|
464
465
|
});
|
|
465
|
-
return await apiNodeToExternalNodeFull(updateNode, this.#
|
|
466
|
+
return await apiNodeToExternalNodeFull(updateNode, this.#client.keyPairs);
|
|
466
467
|
}
|
|
467
468
|
async dataContent({ dataId, onDownloadProgress, progressDecrypt, signal, }) {
|
|
468
469
|
const cached = dataContentCache.get(dataId);
|
|
469
470
|
if (cached !== undefined) {
|
|
470
471
|
return cached;
|
|
471
472
|
}
|
|
472
|
-
const dataContent = await this.#apiClient.cloud.dataContentById.query({
|
|
473
|
+
const dataContent = await this.#client.apiClient.cloud.dataContentById.query({
|
|
473
474
|
id: dataId,
|
|
474
475
|
});
|
|
475
476
|
const totalBytes = Number(dataContent.sizeEncrypted ?? dataContent.size);
|
|
@@ -490,7 +491,7 @@ export class SecrecyCloudClient {
|
|
|
490
491
|
if (cachedData.length === dataIds.length) {
|
|
491
492
|
return cachedData;
|
|
492
493
|
}
|
|
493
|
-
const missingContents = await this.#apiClient.cloud.dataContentByIds.query({
|
|
494
|
+
const missingContents = await this.#client.apiClient.cloud.dataContentByIds.query({
|
|
494
495
|
ids: dataIds.filter((dataId) => !cachedData.some((datum) => datum.id === dataId)),
|
|
495
496
|
});
|
|
496
497
|
const allDataContents = [
|
|
@@ -521,33 +522,33 @@ export class SecrecyCloudClient {
|
|
|
521
522
|
}));
|
|
522
523
|
}
|
|
523
524
|
async deleteNodes({ nodeIds, }) {
|
|
524
|
-
return this.#apiClient.cloud.deleteNodes.mutate({ ids: nodeIds });
|
|
525
|
+
return this.#client.apiClient.cloud.deleteNodes.mutate({ ids: nodeIds });
|
|
525
526
|
}
|
|
526
527
|
async deleteData({ dataId, nodeId, }) {
|
|
527
|
-
const { isDeleted } = await this.#apiClient.cloud.deleteData.mutate({
|
|
528
|
+
const { isDeleted } = await this.#client.apiClient.cloud.deleteData.mutate({
|
|
528
529
|
dataId,
|
|
529
530
|
nodeId,
|
|
530
531
|
});
|
|
531
532
|
return isDeleted;
|
|
532
533
|
}
|
|
533
534
|
async deleteNode({ nodeId }) {
|
|
534
|
-
const { isDeleted } = await this.#apiClient.cloud.deleteNode.mutate({
|
|
535
|
+
const { isDeleted } = await this.#client.apiClient.cloud.deleteNode.mutate({
|
|
535
536
|
id: nodeId,
|
|
536
537
|
});
|
|
537
538
|
return isDeleted;
|
|
538
539
|
}
|
|
539
540
|
async emptyTrash() {
|
|
540
|
-
const { isCleaned } = await this.#apiClient.cloud.emptyNodeCloudTrash.mutate({});
|
|
541
|
+
const { isCleaned } = await this.#client.apiClient.cloud.emptyNodeCloudTrash.mutate({});
|
|
541
542
|
return isCleaned;
|
|
542
543
|
}
|
|
543
544
|
async recoverNode(id) {
|
|
544
|
-
const { isRecovered } = await this.#apiClient.cloud.recoverNode.mutate({
|
|
545
|
+
const { isRecovered } = await this.#client.apiClient.cloud.recoverNode.mutate({
|
|
545
546
|
id,
|
|
546
547
|
});
|
|
547
548
|
return isRecovered;
|
|
548
549
|
}
|
|
549
550
|
async moveNodes({ nodeIds, parentNodeId, }) {
|
|
550
|
-
const { isMoved } = await this.#apiClient.cloud.moveNodes.mutate({
|
|
551
|
+
const { isMoved } = await this.#client.apiClient.cloud.moveNodes.mutate({
|
|
551
552
|
ids: nodeIds,
|
|
552
553
|
parentId: parentNodeId ?? null,
|
|
553
554
|
});
|
|
@@ -592,7 +593,7 @@ export class SecrecyCloudClient {
|
|
|
592
593
|
}
|
|
593
594
|
const senderPubKey = await this.#client.app.userPublicKey(mail.sender.id);
|
|
594
595
|
const dataKey = attachment.key
|
|
595
|
-
? decryptCryptoBox(sodium.from_hex(attachment.key), senderPubKey, this.#
|
|
596
|
+
? decryptCryptoBox(sodium.from_hex(attachment.key), senderPubKey, this.#client.uaPrivateKey)
|
|
596
597
|
: null;
|
|
597
598
|
key = dataKey !== null ? sodium.to_hex(dataKey) : null;
|
|
598
599
|
}
|
|
@@ -604,28 +605,27 @@ export class SecrecyCloudClient {
|
|
|
604
605
|
key = data.key;
|
|
605
606
|
}
|
|
606
607
|
key = key
|
|
607
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), this.#
|
|
608
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey))
|
|
608
609
|
: null;
|
|
609
610
|
const { encryptedNameKey, encryptedName } = await generateAndEncryptNameAndKey({
|
|
610
611
|
name,
|
|
611
|
-
privateKey: this.#
|
|
612
|
-
publicKey: this.#
|
|
612
|
+
privateKey: this.#client.uaPrivateKey,
|
|
613
|
+
publicKey: this.#client.uaIdentity.identityPubKey,
|
|
613
614
|
});
|
|
614
|
-
const saveInCloud = await this.#apiClient.cloud.saveInCloud.mutate({
|
|
615
|
+
const saveInCloud = await this.#client.apiClient.cloud.saveInCloud.mutate({
|
|
615
616
|
dataId,
|
|
616
617
|
key,
|
|
617
618
|
nodeId: nodeId ?? null,
|
|
618
619
|
fileName: encryptedName,
|
|
619
620
|
nameKey: encryptedNameKey,
|
|
620
621
|
});
|
|
621
|
-
const node = await apiNodeToExternalNodeFull(saveInCloud, this.#
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
userId: user.id,
|
|
622
|
+
const node = await apiNodeToExternalNodeFull(saveInCloud, this.#client.keyPairs);
|
|
623
|
+
if (node.parent) {
|
|
624
|
+
const othersIdentities = Object.entries(node.parent.identities).filter(([id]) => id !== this.#client.uaIdentity.identityPubKey);
|
|
625
|
+
// TODO: ??
|
|
626
|
+
if (othersIdentities.length > 0) {
|
|
627
|
+
await this.shareNode(othersIdentities.map(([identityPubKey, permissions]) => ({
|
|
628
|
+
pubKey: identityPubKey,
|
|
629
629
|
nodeId: node.id,
|
|
630
630
|
...permissions,
|
|
631
631
|
})));
|
|
@@ -633,20 +633,13 @@ export class SecrecyCloudClient {
|
|
|
633
633
|
}
|
|
634
634
|
return node;
|
|
635
635
|
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
const
|
|
639
|
-
const nodeIds = Object.values(userNodes).flatMap((nodeIds) => nodeIds);
|
|
636
|
+
encryptNodesForIdentities = async (identityNodes) => {
|
|
637
|
+
const pubKeys = Object.keys(identityNodes).map((identityPubKey) => identityPubKey);
|
|
638
|
+
const nodeIds = Object.values(identityNodes).flatMap((nodeIds) => nodeIds);
|
|
640
639
|
if (nodeIds.length === 0) {
|
|
641
640
|
return {};
|
|
642
641
|
}
|
|
643
642
|
const nodes = [];
|
|
644
|
-
// Pre check to ensure we get all public keys for users!
|
|
645
|
-
for (const userId of userIds) {
|
|
646
|
-
if (userPublicKeys[userId] === undefined) {
|
|
647
|
-
throw new Error(`Unable to retrieve some user public keys!`);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
643
|
// Retrieve and format nodes.
|
|
651
644
|
for (const nodeId of nodeIds) {
|
|
652
645
|
let node = nodesEncryptionCache.get(nodeId) ?? nodesCache.get(nodeId);
|
|
@@ -671,7 +664,7 @@ export class SecrecyCloudClient {
|
|
|
671
664
|
// Retrieve all missing nodes from cache to api.
|
|
672
665
|
const missingNodeIds = nodeIds.filter((nodeId) => !nodes.some((node) => node.id === nodeId));
|
|
673
666
|
const fetchedNodes = missingNodeIds.length > 0
|
|
674
|
-
? await this.#apiClient.cloud.nodesForEncryption.query({
|
|
667
|
+
? await this.#client.apiClient.cloud.nodesForEncryption.query({
|
|
675
668
|
ids: missingNodeIds,
|
|
676
669
|
})
|
|
677
670
|
: [];
|
|
@@ -680,13 +673,13 @@ export class SecrecyCloudClient {
|
|
|
680
673
|
throw new Error(`Unable to fetch some node infos (${diff.join(', ')})`);
|
|
681
674
|
}
|
|
682
675
|
const finalNodes = await Promise.all(fetchedNodes.map((node) => {
|
|
683
|
-
return apiNodeForEncryptionToInternal(node, this.#
|
|
676
|
+
return apiNodeForEncryptionToInternal(node, this.#client.keyPairs);
|
|
684
677
|
}));
|
|
685
678
|
nodes.push(...finalNodes);
|
|
686
679
|
const nodesMappedUsers = {};
|
|
687
|
-
for (const
|
|
688
|
-
nodesMappedUsers[
|
|
689
|
-
for (const nodeId of
|
|
680
|
+
for (const pubKey in identityNodes) {
|
|
681
|
+
nodesMappedUsers[pubKey] ??= [];
|
|
682
|
+
for (const nodeId of identityNodes[pubKey]) {
|
|
690
683
|
const node = nodes.find((node) => node.id === nodeId);
|
|
691
684
|
if (!node) {
|
|
692
685
|
throw new Error('Unable to retrieve node from ram');
|
|
@@ -696,17 +689,16 @@ export class SecrecyCloudClient {
|
|
|
696
689
|
throw new Error(`Can't share a node without data (${node.id})!`);
|
|
697
690
|
}
|
|
698
691
|
const nameKey = node.access?.nameKey;
|
|
699
|
-
|
|
700
|
-
nodesMappedUsers[userId].push({
|
|
692
|
+
nodesMappedUsers[pubKey].push({
|
|
701
693
|
id: node.id,
|
|
702
694
|
nameKey: nameKey !== null
|
|
703
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(nameKey),
|
|
695
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(nameKey), pubKey, this.#client.uaPrivateKey))
|
|
704
696
|
: null,
|
|
705
697
|
data: 'history' in node
|
|
706
698
|
? node.history.map((f) => ({
|
|
707
699
|
id: f.id,
|
|
708
700
|
key: f.key
|
|
709
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(f.key),
|
|
701
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(f.key), pubKey, this.#client.uaPrivateKey))
|
|
710
702
|
: null,
|
|
711
703
|
}))
|
|
712
704
|
: [],
|
|
@@ -717,15 +709,15 @@ export class SecrecyCloudClient {
|
|
|
717
709
|
};
|
|
718
710
|
async reportData({ id, reasons, }) {
|
|
719
711
|
const [rawData, secrecy] = await Promise.all([
|
|
720
|
-
this.#apiClient.cloud.dataById.query({ id }),
|
|
721
|
-
this.#apiClient.misc.publicKey.query(),
|
|
712
|
+
this.#client.apiClient.cloud.dataById.query({ id }),
|
|
713
|
+
this.#client.apiClient.misc.publicKey.query(),
|
|
722
714
|
]);
|
|
723
|
-
const data = apiDataToInternal(rawData, this.#
|
|
724
|
-
return this.#apiClient.cloud.reportData.mutate({
|
|
715
|
+
const data = apiDataToInternal(rawData, this.#client.keyPairs);
|
|
716
|
+
return this.#client.apiClient.cloud.reportData.mutate({
|
|
725
717
|
id: id,
|
|
726
718
|
reasons: reasons,
|
|
727
719
|
encryptedDataKey: data.key
|
|
728
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), secrecy.publicKey, this.#
|
|
720
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), secrecy.publicKey, this.#client.uaPrivateKey))
|
|
729
721
|
: null,
|
|
730
722
|
});
|
|
731
723
|
}
|
|
@@ -739,28 +731,28 @@ export class SecrecyCloudClient {
|
|
|
739
731
|
throw new Error("It's not possible to transfer a cold stored data to a lite storage!");
|
|
740
732
|
}
|
|
741
733
|
}
|
|
742
|
-
return this.#apiClient.cloud.moveToStorageType.mutate(input);
|
|
734
|
+
return this.#client.apiClient.cloud.moveToStorageType.mutate(input);
|
|
743
735
|
}
|
|
744
736
|
getPublicDataLink(input) {
|
|
745
|
-
return this.#apiClient.cloud.dataLink.query(input);
|
|
737
|
+
return this.#client.apiClient.cloud.dataLink.query(input);
|
|
746
738
|
}
|
|
747
739
|
getPublicDataLinks(input) {
|
|
748
|
-
return this.#apiClient.cloud.dataLinks.query(input);
|
|
740
|
+
return this.#client.apiClient.cloud.dataLinks.query(input);
|
|
749
741
|
}
|
|
750
742
|
checkAccesses(input) {
|
|
751
|
-
return this.#apiClient.cloud.checkAccesses.query(input);
|
|
743
|
+
return this.#client.apiClient.cloud.checkAccesses.query(input);
|
|
752
744
|
}
|
|
753
745
|
createPublicDataLink(input) {
|
|
754
746
|
if (input.expireAt && input.expireAt <= new Date()) {
|
|
755
747
|
throw new Error('Unable to create public link using a past expireAt date!');
|
|
756
748
|
}
|
|
757
|
-
return this.#apiClient.cloud.createDataLink.mutate(input);
|
|
749
|
+
return this.#client.apiClient.cloud.createDataLink.mutate(input);
|
|
758
750
|
}
|
|
759
751
|
updatePublicDataLink(input) {
|
|
760
|
-
return this.#apiClient.cloud.updateDataLink.mutate(input);
|
|
752
|
+
return this.#client.apiClient.cloud.updateDataLink.mutate(input);
|
|
761
753
|
}
|
|
762
754
|
deletePublicDataLink(input) {
|
|
763
|
-
return this.#apiClient.cloud.deleteDataLink.mutate(input);
|
|
755
|
+
return this.#client.apiClient.cloud.deleteDataLink.mutate(input);
|
|
764
756
|
}
|
|
765
757
|
async _handleDataContent({ dataContent, totalBytes, progressParts, onDownloadProgress, progressDecrypt, signal, }) {
|
|
766
758
|
const onProgress = (key, progressEvent) => {
|
|
@@ -827,7 +819,7 @@ export class SecrecyCloudClient {
|
|
|
827
819
|
? dataContent.senderPublicKey
|
|
828
820
|
: dataContent.type === 'cloud' || dataContent.type === 'lite'
|
|
829
821
|
? dataContent.publicKey
|
|
830
|
-
: this.#
|
|
822
|
+
: this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)
|
|
831
823
|
: null;
|
|
832
824
|
const src = key
|
|
833
825
|
? await decrypt(key, encryptedContent, progressDecrypt, signal)
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
export class SecrecyDbClient {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
constructor(_client, _keys, apiClient) {
|
|
6
|
-
// this.#client = client;
|
|
7
|
-
// this.#keys = keys;
|
|
8
|
-
this.#apiClient = apiClient;
|
|
2
|
+
#client;
|
|
3
|
+
constructor(client) {
|
|
4
|
+
this.#client = client;
|
|
9
5
|
}
|
|
10
6
|
}
|