@secrecy/lib 1.74.3 → 1.75.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.
Files changed (46) hide show
  1. package/dist/lib/base-client.js +26 -2
  2. package/dist/lib/client/SecrecyAppClient.js +13 -17
  3. package/dist/lib/client/SecrecyCloudClient.js +131 -135
  4. package/dist/lib/client/SecrecyDbClient.js +3 -7
  5. package/dist/lib/client/SecrecyMailClient.js +38 -48
  6. package/dist/lib/client/SecrecyOrganizationClient.js +10 -12
  7. package/dist/lib/client/SecrecyPayClient.js +1 -5
  8. package/dist/lib/client/SecrecyPseudonymClient.js +4 -8
  9. package/dist/lib/client/SecrecyUserClient.js +11 -11
  10. package/dist/lib/client/SecrecyWalletClient.js +0 -2
  11. package/dist/lib/client/convert/data.js +4 -4
  12. package/dist/lib/client/convert/mail.js +5 -6
  13. package/dist/lib/client/convert/node.js +46 -34
  14. package/dist/lib/client/helpers.js +17 -7
  15. package/dist/lib/client/index.js +48 -12
  16. package/dist/lib/client/storage.js +3 -2
  17. package/dist/lib/client/types/identity.js +18 -0
  18. package/dist/lib/client/types/index.js +3 -7
  19. package/dist/lib/client/upload.js +29 -17
  20. package/dist/lib/crypto/domain.js +7 -3
  21. package/dist/lib/index.js +1 -0
  22. package/dist/types/base-client.d.ts +2 -0
  23. package/dist/types/client/SecrecyAppClient.d.ts +2 -3
  24. package/dist/types/client/SecrecyCloudClient.d.ts +18 -18
  25. package/dist/types/client/SecrecyDbClient.d.ts +1 -3
  26. package/dist/types/client/SecrecyMailClient.d.ts +2 -3
  27. package/dist/types/client/SecrecyOrganizationClient.d.ts +2 -3
  28. package/dist/types/client/SecrecyPayClient.d.ts +1 -3
  29. package/dist/types/client/SecrecyPseudonymClient.d.ts +2 -3
  30. package/dist/types/client/SecrecyUserClient.d.ts +2 -3
  31. package/dist/types/client/convert/data.d.ts +3 -3
  32. package/dist/types/client/convert/mail.d.ts +3 -5
  33. package/dist/types/client/convert/node.d.ts +5 -5
  34. package/dist/types/client/index.d.ts +11 -3
  35. package/dist/types/client/storage.d.ts +3 -2
  36. package/dist/types/client/types/identity.d.ts +29 -0
  37. package/dist/types/client/types/index.d.ts +13 -9
  38. package/dist/types/client/types/mail.d.ts +2 -1
  39. package/dist/types/client/types/node.d.ts +12 -9
  40. package/dist/types/client/types/user.d.ts +15 -0
  41. package/dist/types/client/upload.d.ts +4 -3
  42. package/dist/types/client.d.ts +1438 -1050
  43. package/dist/types/crypto/domain.d.ts +5 -3
  44. package/dist/types/crypto/index.d.ts +3 -3
  45. package/dist/types/index.d.ts +2 -1
  46. package/package.json +21 -21
@@ -8,41 +8,32 @@ import { apiDataToExternal, apiDataToInternal } from './convert/data.js';
8
8
  import { apiNodeForEncryptionToInternal, apiNodeFullToInternalFull, apiNodeToExternal, apiNodeToExternalNodeFull, internalNodeFullToNodeFull, } from './convert/node.js';
9
9
  import { buildBytesFromApiData } from '../crypto/domain.js';
10
10
  import { chunkByTotalItems } from '../utils/object.js';
11
- import { createPublicDataLink, uploadData } from './upload.js';
11
+ import { uploadData } from './upload.js';
12
12
  import { encryptName, generateAndEncryptNameAndKey } from '../crypto/helpers.js';
13
13
  import { downloadDataFromLink, } from './data-link.js';
14
14
  export class SecrecyCloudClient {
15
15
  #client;
16
- #keys;
17
- #apiClient;
18
- constructor(client, keys, apiClient) {
16
+ constructor(client) {
19
17
  this.#client = client;
20
- this.#keys = keys;
21
- this.#apiClient = apiClient;
22
18
  }
23
19
  async addDataToHistory({ dataId, nodeId, }) {
24
- const addDataToHistory = await this.#apiClient.cloud.addDataToHistory.mutate({ dataId, nodeId });
25
- const node = await apiNodeFullToInternalFull(addDataToHistory, this.#keys);
20
+ const addDataToHistory = await this.#client.apiClient.cloud.addDataToHistory.mutate({
21
+ dataId,
22
+ nodeId,
23
+ });
24
+ const node = await apiNodeFullToInternalFull(addDataToHistory, this.#client.keyPairs);
26
25
  const data = node.history.find((d) => d.id === dataId);
27
26
  if (data !== undefined) {
28
- // TODO sad to have to make this extra request
29
- const me = await this.#client.me();
30
- const users = node.users.filter(([u]) => u.id !== me.id);
31
- const userIds = users.map(([user]) => user.id);
32
- const userKeys = await this.#client.app.userPublicKey(userIds);
33
- const shares = users.map(([user]) => {
34
- const publicKey = userKeys[user.id];
35
- if (!publicKey) {
36
- throw new Error('Unable to retrieve share by public key!');
37
- }
27
+ const othersIdentities = Object.entries(node.identities).filter(([id]) => id !== this.#client.uaIdentity.identityPubKey);
28
+ const shares = othersIdentities.map(([publicKey]) => {
38
29
  return {
39
- id: user.id,
30
+ pubKey: publicKey,
40
31
  key: data.key
41
- ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), publicKey, this.#keys.privateKey))
32
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), publicKey, this.#client.uaPrivateKey))
42
33
  : null,
43
34
  };
44
35
  });
45
- await this.#apiClient.cloud.shareDataInHistory.mutate({
36
+ await this.#client.apiClient.cloud.shareDataInHistory.mutate({
46
37
  dataId: data.id,
47
38
  nodeId,
48
39
  users: shares,
@@ -53,8 +44,9 @@ export class SecrecyCloudClient {
53
44
  async uploadData(opts) {
54
45
  return uploadData({
55
46
  ...opts,
56
- keyPair: this.#keys,
57
- apiClient: this.#apiClient,
47
+ uaIdentity: this.#client.uaIdentity,
48
+ keyPairs: this.#client.keyPairs,
49
+ apiClient: this.#client.apiClient,
58
50
  });
59
51
  }
60
52
  async uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress, storageType = 's3', signal, }) {
@@ -68,21 +60,21 @@ export class SecrecyCloudClient {
68
60
  return await this.saveInCloud({ dataId: uploadedData.id, name, nodeId });
69
61
  }
70
62
  async deletedNodes() {
71
- const deletedNodes = await this.#apiClient.cloud.nodesDeleted.query({});
72
- return await Promise.all(deletedNodes.map(async (node) => await apiNodeToExternal(node, this.#keys)));
63
+ const deletedNodes = await this.#client.apiClient.cloud.nodesDeleted.query({});
64
+ return await Promise.all(deletedNodes.map(async (node) => await apiNodeToExternal(node, this.#client.keyPairs)));
73
65
  }
74
66
  async sharedNodes() {
75
- const nodesShared = await this.#apiClient.cloud.nodesShared.query();
76
- return await Promise.all(nodesShared.map(async (node) => await apiNodeToExternal(node, this.#keys)));
67
+ const nodesShared = await this.#client.apiClient.cloud.nodesShared.query({});
68
+ return await Promise.all(nodesShared.map(async (node) => await apiNodeToExternal(node, this.#client.keyPairs)));
77
69
  }
78
70
  async nodesSharedWithMe(type = 'FOLDER') {
79
- const nodesSharedWithMe = await this.#apiClient.cloud.nodesSharedWithMe.query({ type });
80
- return await Promise.all(nodesSharedWithMe.map(async (node) => await apiNodeToExternal(node, this.#keys)));
71
+ const nodesSharedWithMe = await this.#client.apiClient.cloud.nodesSharedWithMe.query({ type });
72
+ return await Promise.all(nodesSharedWithMe.map(async (node) => await apiNodeToExternal(node, this.#client.keyPairs)));
81
73
  }
82
- async deleteNodeSharing({ nodeId, userId, }) {
83
- const { isDeleted } = await this.#apiClient.cloud.deleteNodeSharing.mutate({
74
+ async deleteNodeSharing({ nodeId, destPubKey, }) {
75
+ const { isDeleted } = await this.#client.apiClient.cloud.deleteNodeSharing.mutate({
84
76
  nodeId,
85
- userId,
77
+ destPubKey,
86
78
  });
87
79
  return isDeleted;
88
80
  }
@@ -95,14 +87,14 @@ export class SecrecyCloudClient {
95
87
  throw new Error(`Node (${nodeId}) does not exists`);
96
88
  }
97
89
  }
98
- if (node.access?.nameKey === undefined) {
99
- throw new Error(`Can't have access to node ${nodeId}`);
90
+ if (!node.accesses[0]) {
91
+ throw new Error(`No access found for node ${nodeId}`);
100
92
  }
101
93
  name =
102
- typeof name === 'string' && node.access.nameKey !== null
103
- ? await encryptName(name, node.access.nameKey)
94
+ typeof name === 'string' && node.accesses[0].nameKey !== null
95
+ ? await encryptName(name, node.accesses[0].nameKey)
104
96
  : null;
105
- const { isDuplicated } = await this.#apiClient.cloud.duplicateNode.mutate({
97
+ const { isDuplicated } = await this.#client.apiClient.cloud.duplicateNode.mutate({
106
98
  nodeId,
107
99
  folderId: folderId ?? null,
108
100
  name,
@@ -110,50 +102,54 @@ export class SecrecyCloudClient {
110
102
  return isDuplicated;
111
103
  }
112
104
  async deleteNodeCloudTrash({ ids }) {
113
- const { isDeleted } = await this.#apiClient.cloud.deleteNodeCloudTrash.mutate({ ids });
105
+ const { isDeleted } = await this.#client.apiClient.cloud.deleteNodeCloudTrash.mutate({ ids });
114
106
  return isDeleted;
115
107
  }
116
108
  async createFolder({ name, parentFolderId, }) {
117
109
  const { encryptedNameKey, encryptedName } = await generateAndEncryptNameAndKey({
118
110
  name,
119
- privateKey: this.#keys.privateKey,
120
- publicKey: this.#keys.publicKey,
111
+ privateKey: this.#client.uaPrivateKey,
112
+ publicKey: this.#client.uaIdentity.identityPubKey,
121
113
  });
122
- const createdFolder = await this.#apiClient.cloud.createFolder.mutate({
114
+ const createdFolder = await this.#client.apiClient.cloud.createFolder.mutate({
123
115
  name: encryptedName,
124
116
  parentId: parentFolderId ?? null,
125
117
  nameKey: encryptedNameKey,
126
118
  });
127
- const folder = await apiNodeToExternalNodeFull(createdFolder, this.#keys);
128
- const users = folder.parent?.users?.filter(([u]) => u.id !== folder.owner.id) ?? [];
129
- if (users.length > 0) {
130
- await this.shareNode(users.map(([user, permissions]) => ({
131
- userId: user.id,
132
- nodeId: folder.id,
133
- rights: permissions.rights,
134
- addAccess: permissions.addAccess,
135
- delAccess: permissions.delAccess,
136
- sharingAddAccess: permissions.sharingAddAccess,
137
- sharingDelAccess: permissions.sharingDelAccess,
138
- })));
119
+ const folder = await apiNodeToExternalNodeFull(createdFolder, this.#client.keyPairs);
120
+ if (folder.parent) {
121
+ const othersIdentities = Object.entries(folder.parent.identities).filter(([id]) => id !== this.#client.uaIdentity.identityPubKey);
122
+ // TODO: ??
123
+ if (othersIdentities.length > 0) {
124
+ await this.shareNode(othersIdentities.map(([identityPubKey, permissions]) => ({
125
+ pubKey: identityPubKey,
126
+ nodeId: folder.id,
127
+ rights: permissions.rights,
128
+ addAccess: permissions.addAccess,
129
+ delAccess: permissions.delAccess,
130
+ sharingAddAccess: permissions.sharingAddAccess,
131
+ sharingDelAccess: permissions.sharingDelAccess,
132
+ })));
133
+ }
139
134
  }
140
135
  return folder;
141
136
  }
142
137
  async node({ id, deleted, } = {}) {
143
- const node = await this.#apiClient.cloud.nodeFullById.query({ id, deleted });
144
- return await apiNodeToExternalNodeFull(node, this.#keys);
138
+ const node = await this.#client.apiClient.cloud.nodeFullById.query({
139
+ id,
140
+ deleted,
141
+ });
142
+ return await apiNodeToExternalNodeFull(node, this.#client.keyPairs);
145
143
  }
146
144
  async dataMetadata({ id }) {
147
- const data = await this.#apiClient.cloud.dataById.query({ id });
148
- return apiDataToExternal(data, this.#keys);
145
+ const data = await this.#client.apiClient.cloud.dataById.query({ id });
146
+ return apiDataToExternal(data, this.#client.keyPairs);
149
147
  }
150
- async shareNode(input, progress) {
148
+ async shareNode(accesses, progress) {
151
149
  // TODO: Validate input
152
- const nodesMap = await this.#apiClient.cloud.shareNode.mutate(input);
153
- const neededUserKey = Object.entries(nodesMap)
154
- .filter(([, nodes]) => nodes.some((node) => node.includeKeys))
155
- .map(([userId]) => userId);
156
- const publicKeysMap = await this.#client.app.userPublicKey(neededUserKey);
150
+ const nodesMap = await this.#client.apiClient.cloud.shareNode.mutate({
151
+ accesses,
152
+ });
157
153
  const maxNodesBatchSize = 1000;
158
154
  const totalNodesToShare = Object.values(nodesMap).reduce((size, ids) => size + ids.length, 0);
159
155
  progress?.({ total: totalNodesToShare, current: 0, percent: 0 });
@@ -170,9 +166,9 @@ export class SecrecyCloudClient {
170
166
  return filtered.length > 0 ? [userId, filtered] : null;
171
167
  })
172
168
  .filter((entry) => entry !== null));
173
- const infos = await this.encryptNodesForUsers(nodesToEncrypt, publicKeysMap);
174
- const nodesToUpdateRights = Object.fromEntries(Object.entries(nodesMap).map(([userId, nodes]) => [
175
- userId,
169
+ const infos = await this.encryptNodesForIdentities(nodesToEncrypt);
170
+ const nodesToUpdateRights = Object.fromEntries(Object.entries(nodesMap).map(([pubKey, nodes]) => [
171
+ pubKey,
176
172
  nodes
177
173
  .filter((node) => !node.includeKeys)
178
174
  .map((node) => {
@@ -188,13 +184,13 @@ export class SecrecyCloudClient {
188
184
  };
189
185
  }),
190
186
  ]));
191
- const withKeys = Object.fromEntries(Object.entries(infos).map(([userId, nodes]) => {
187
+ const withKeys = Object.fromEntries(Object.entries(infos).map(([pubKey, nodes]) => {
192
188
  return [
193
- userId,
189
+ pubKey,
194
190
  {
195
- userId,
191
+ pubKey,
196
192
  nodes: nodes.map((node) => {
197
- const map = nodesMap[userId];
193
+ const map = nodesMap[pubKey];
198
194
  if (!map) {
199
195
  throw new Error('Unable to retrieve mapped nodes!');
200
196
  }
@@ -217,20 +213,22 @@ export class SecrecyCloudClient {
217
213
  ];
218
214
  }));
219
215
  const finishInput = [];
220
- for (const [userId, nodes] of Object.entries(withKeys)) {
216
+ for (const [pubKey, nodes] of Object.entries(withKeys)) {
221
217
  if (nodes.nodes.length === 0) {
222
218
  continue;
223
219
  }
224
- finishInput.push({ userId, nodes: nodes.nodes });
220
+ finishInput.push({ pubKey, nodes: nodes.nodes });
225
221
  }
226
- for (const [userId, nodes] of Object.entries(nodesToUpdateRights)) {
222
+ for (const [pubKey, nodes] of Object.entries(nodesToUpdateRights)) {
227
223
  if (nodes.length === 0) {
228
224
  continue;
229
225
  }
230
- finishInput.push({ userId, nodes });
226
+ finishInput.push({ pubKey, nodes });
231
227
  }
232
228
  const subState = finishInput.length > 0
233
- ? await this.#apiClient.cloud.shareNodeFinish.mutate(finishInput)
229
+ ? await this.#client.apiClient.cloud.shareNodeFinish.mutate({
230
+ accesses: finishInput,
231
+ })
234
232
  : { isFinished: true, details: {} };
235
233
  const currentProgress = Math.min((index + 1) * maxNodesBatchSize, totalNodesToShare);
236
234
  progress?.({
@@ -277,27 +275,31 @@ export class SecrecyCloudClient {
277
275
  throw `Can't find Node ${nodeId}`;
278
276
  }
279
277
  }
280
- if (node.access?.nameKey === undefined) {
281
- throw new Error(`Can't have access to node ${nodeId}`);
278
+ if (node.accesses.find((a) => ['delete', 'write'].includes(a.rights)) ===
279
+ undefined) {
280
+ throw new Error(`No access to update node ${nodeId}`);
281
+ }
282
+ if (!node.accesses[0]) {
283
+ throw new Error(`No access found for node ${nodeId}`);
282
284
  }
283
285
  name =
284
- typeof name === 'string' && node.access.nameKey !== null
285
- ? await encryptName(name, node.access.nameKey)
286
+ typeof name === 'string' && node.accesses[0].nameKey !== null
287
+ ? await encryptName(name, node.accesses[0].nameKey)
286
288
  : null;
287
- const updateNode = await this.#apiClient.cloud.updateNode.mutate({
289
+ const updateNode = await this.#client.apiClient.cloud.updateNode.mutate({
288
290
  deletedAt: deletedAt ?? null,
289
291
  id: nodeId,
290
292
  isFavorite: isFavorite ?? null,
291
293
  name,
292
294
  });
293
- return await apiNodeToExternalNodeFull(updateNode, this.#keys);
295
+ return await apiNodeToExternalNodeFull(updateNode, this.#client.keyPairs);
294
296
  }
295
297
  async dataContent({ dataId, onDownloadProgress, progressDecrypt, signal, }) {
296
298
  const cached = dataContentCache.get(dataId);
297
299
  if (cached !== undefined) {
298
300
  return cached;
299
301
  }
300
- const dataContent = await this.#apiClient.cloud.dataContentById.query({
302
+ const dataContent = await this.#client.apiClient.cloud.dataContentById.query({
301
303
  id: dataId,
302
304
  });
303
305
  const totalBytes = Number(dataContent.sizeEncrypted ?? dataContent.size);
@@ -318,7 +320,7 @@ export class SecrecyCloudClient {
318
320
  if (cachedData.length === dataIds.length) {
319
321
  return cachedData;
320
322
  }
321
- const missingContents = await this.#apiClient.cloud.dataContentByIds.query({
323
+ const missingContents = await this.#client.apiClient.cloud.dataContentByIds.query({
322
324
  ids: dataIds.filter((dataId) => !cachedData.some((datum) => datum.id === dataId)),
323
325
  });
324
326
  const allDataContents = [
@@ -349,33 +351,33 @@ export class SecrecyCloudClient {
349
351
  }));
350
352
  }
351
353
  async deleteNodes({ nodeIds, }) {
352
- return this.#apiClient.cloud.deleteNodes.mutate({ ids: nodeIds });
354
+ return this.#client.apiClient.cloud.deleteNodes.mutate({ ids: nodeIds });
353
355
  }
354
356
  async deleteData({ dataId, nodeId, }) {
355
- const { isDeleted } = await this.#apiClient.cloud.deleteData.mutate({
357
+ const { isDeleted } = await this.#client.apiClient.cloud.deleteData.mutate({
356
358
  dataId,
357
359
  nodeId,
358
360
  });
359
361
  return isDeleted;
360
362
  }
361
363
  async deleteNode({ nodeId }) {
362
- const { isDeleted } = await this.#apiClient.cloud.deleteNode.mutate({
364
+ const { isDeleted } = await this.#client.apiClient.cloud.deleteNode.mutate({
363
365
  id: nodeId,
364
366
  });
365
367
  return isDeleted;
366
368
  }
367
369
  async emptyTrash() {
368
- const { isCleaned } = await this.#apiClient.cloud.emptyNodeCloudTrash.mutate({});
370
+ const { isCleaned } = await this.#client.apiClient.cloud.emptyNodeCloudTrash.mutate({});
369
371
  return isCleaned;
370
372
  }
371
373
  async recoverNode(id) {
372
- const { isRecovered } = await this.#apiClient.cloud.recoverNode.mutate({
374
+ const { isRecovered } = await this.#client.apiClient.cloud.recoverNode.mutate({
373
375
  id,
374
376
  });
375
377
  return isRecovered;
376
378
  }
377
379
  async moveNodes({ nodeIds, parentNodeId, }) {
378
- const { isMoved } = await this.#apiClient.cloud.moveNodes.mutate({
380
+ const { isMoved } = await this.#client.apiClient.cloud.moveNodes.mutate({
379
381
  ids: nodeIds,
380
382
  parentId: parentNodeId ?? null,
381
383
  });
@@ -420,7 +422,7 @@ export class SecrecyCloudClient {
420
422
  }
421
423
  const senderPubKey = await this.#client.app.userPublicKey(mail.sender.id);
422
424
  const dataKey = attachment.key
423
- ? decryptCryptoBox(sodium.from_hex(attachment.key), senderPubKey, this.#keys.privateKey)
425
+ ? decryptCryptoBox(sodium.from_hex(attachment.key), senderPubKey, this.#client.uaPrivateKey)
424
426
  : null;
425
427
  key = dataKey !== null ? sodium.to_hex(dataKey) : null;
426
428
  }
@@ -432,28 +434,27 @@ export class SecrecyCloudClient {
432
434
  key = data.key;
433
435
  }
434
436
  key = key
435
- ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), this.#keys.publicKey, this.#keys.privateKey))
437
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey))
436
438
  : null;
437
439
  const { encryptedNameKey, encryptedName } = await generateAndEncryptNameAndKey({
438
440
  name,
439
- privateKey: this.#keys.privateKey,
440
- publicKey: this.#keys.publicKey,
441
+ privateKey: this.#client.uaPrivateKey,
442
+ publicKey: this.#client.uaIdentity.identityPubKey,
441
443
  });
442
- const saveInCloud = await this.#apiClient.cloud.saveInCloud.mutate({
444
+ const saveInCloud = await this.#client.apiClient.cloud.saveInCloud.mutate({
443
445
  dataId,
444
446
  key,
445
447
  nodeId: nodeId ?? null,
446
448
  fileName: encryptedName,
447
449
  nameKey: encryptedNameKey,
448
450
  });
449
- const node = await apiNodeToExternalNodeFull(saveInCloud, this.#keys);
450
- const me = node.parent?.users.find(([u]) => u.id === node.owner.id);
451
- // TODO: ??
452
- if (me !== undefined && ['delete', 'write'].includes(me[1].rights)) {
453
- const others = node.parent?.users.filter(([u]) => u.id !== node.owner.id) ?? [];
454
- if (others.length > 0) {
455
- await this.shareNode(others.map(([user, permissions]) => ({
456
- userId: user.id,
451
+ const node = await apiNodeToExternalNodeFull(saveInCloud, this.#client.keyPairs);
452
+ if (node.parent) {
453
+ const othersIdentities = Object.entries(node.parent.identities).filter(([id]) => id !== this.#client.uaIdentity.identityPubKey);
454
+ // TODO: ??
455
+ if (othersIdentities.length > 0) {
456
+ await this.shareNode(othersIdentities.map(([identityPubKey, permissions]) => ({
457
+ pubKey: identityPubKey,
457
458
  nodeId: node.id,
458
459
  ...permissions,
459
460
  })));
@@ -461,20 +462,13 @@ export class SecrecyCloudClient {
461
462
  }
462
463
  return node;
463
464
  }
464
- encryptNodesForUsers = async (userNodes, // { [userId]: nodeIds[] }
465
- userPublicKeys) => {
466
- const userIds = Object.keys(userNodes).map((userId) => userId);
467
- const nodeIds = Object.values(userNodes).flatMap((nodeIds) => nodeIds);
465
+ encryptNodesForIdentities = async (identityNodes) => {
466
+ const pubKeys = Object.keys(identityNodes).map((identityPubKey) => identityPubKey);
467
+ const nodeIds = Object.values(identityNodes).flatMap((nodeIds) => nodeIds);
468
468
  if (nodeIds.length === 0) {
469
469
  return {};
470
470
  }
471
471
  const nodes = [];
472
- // Pre check to ensure we get all public keys for users!
473
- for (const userId of userIds) {
474
- if (userPublicKeys[userId] === undefined) {
475
- throw new Error(`Unable to retrieve some user public keys!`);
476
- }
477
- }
478
472
  // Retrieve and format nodes.
479
473
  for (const nodeId of nodeIds) {
480
474
  let node = nodesEncryptionCache.get(nodeId) ?? nodesCache.get(nodeId);
@@ -499,7 +493,7 @@ export class SecrecyCloudClient {
499
493
  // Retrieve all missing nodes from cache to api.
500
494
  const missingNodeIds = nodeIds.filter((nodeId) => !nodes.some((node) => node.id === nodeId));
501
495
  const fetchedNodes = missingNodeIds.length > 0
502
- ? await this.#apiClient.cloud.nodesForEncryption.query({
496
+ ? await this.#client.apiClient.cloud.nodesForEncryption.query({
503
497
  ids: missingNodeIds,
504
498
  })
505
499
  : [];
@@ -508,13 +502,13 @@ export class SecrecyCloudClient {
508
502
  throw new Error(`Unable to fetch some node infos (${diff.join(', ')})`);
509
503
  }
510
504
  const finalNodes = await Promise.all(fetchedNodes.map((node) => {
511
- return apiNodeForEncryptionToInternal(node, this.#keys);
505
+ return apiNodeForEncryptionToInternal(node, this.#client.keyPairs);
512
506
  }));
513
507
  nodes.push(...finalNodes);
514
508
  const nodesMappedUsers = {};
515
- for (const userId in userNodes) {
516
- nodesMappedUsers[userId] ??= [];
517
- for (const nodeId of userNodes[userId]) {
509
+ for (const pubKey in identityNodes) {
510
+ nodesMappedUsers[pubKey] ??= [];
511
+ for (const nodeId of identityNodes[pubKey]) {
518
512
  const node = nodes.find((node) => node.id === nodeId);
519
513
  if (!node) {
520
514
  throw new Error('Unable to retrieve node from ram');
@@ -524,17 +518,16 @@ export class SecrecyCloudClient {
524
518
  throw new Error(`Can't share a node without data (${node.id})!`);
525
519
  }
526
520
  const nameKey = node.access?.nameKey;
527
- const publicKey = userPublicKeys[userId];
528
- nodesMappedUsers[userId].push({
521
+ nodesMappedUsers[pubKey].push({
529
522
  id: node.id,
530
523
  nameKey: nameKey !== null
531
- ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(nameKey), publicKey, this.#keys.privateKey))
524
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(nameKey), pubKey, this.#client.uaPrivateKey))
532
525
  : null,
533
526
  data: 'history' in node
534
527
  ? node.history.map((f) => ({
535
528
  id: f.id,
536
529
  key: f.key
537
- ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(f.key), publicKey, this.#keys.privateKey))
530
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(f.key), pubKey, this.#client.uaPrivateKey))
538
531
  : null,
539
532
  }))
540
533
  : [],
@@ -545,15 +538,15 @@ export class SecrecyCloudClient {
545
538
  };
546
539
  async reportData({ id, reasons, }) {
547
540
  const [rawData, secrecy] = await Promise.all([
548
- this.#apiClient.cloud.dataById.query({ id }),
549
- this.#apiClient.misc.publicKey.query(),
541
+ this.#client.apiClient.cloud.dataById.query({ id }),
542
+ this.#client.apiClient.misc.publicKey.query(),
550
543
  ]);
551
- const data = apiDataToInternal(rawData, this.#keys);
552
- return this.#apiClient.cloud.reportData.mutate({
544
+ const data = apiDataToInternal(rawData, this.#client.keyPairs);
545
+ return this.#client.apiClient.cloud.reportData.mutate({
553
546
  id: id,
554
547
  reasons: reasons,
555
548
  encryptedDataKey: data.key
556
- ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), secrecy.publicKey, this.#keys.privateKey))
549
+ ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), secrecy.publicKey, this.#client.uaPrivateKey))
557
550
  : null,
558
551
  });
559
552
  }
@@ -567,25 +560,28 @@ export class SecrecyCloudClient {
567
560
  throw new Error("It's not possible to transfer a cold stored data to a lite storage!");
568
561
  }
569
562
  }
570
- return this.#apiClient.cloud.moveToStorageType.mutate(input);
563
+ return this.#client.apiClient.cloud.moveToStorageType.mutate(input);
571
564
  }
572
565
  getPublicDataLink(input) {
573
- return this.#apiClient.cloud.dataLink.query(input);
566
+ return this.#client.apiClient.cloud.dataLink.query(input);
574
567
  }
575
568
  getPublicDataLinks(input) {
576
- return this.#apiClient.cloud.dataLinks.query(input);
569
+ return this.#client.apiClient.cloud.dataLinks.query(input);
577
570
  }
578
571
  checkAccesses(input) {
579
- return this.#apiClient.cloud.checkAccesses.query(input);
572
+ return this.#client.apiClient.cloud.checkAccesses.query(input);
580
573
  }
581
574
  createPublicDataLink(input) {
582
- return createPublicDataLink({ ...input, apiClient: this.#apiClient });
575
+ if (input.expireAt && input.expireAt <= new Date()) {
576
+ throw new Error('Unable to create public link using a past expireAt date!');
577
+ }
578
+ return this.#client.apiClient.cloud.createDataLink.mutate(input);
583
579
  }
584
580
  updatePublicDataLink(input) {
585
- return this.#apiClient.cloud.updateDataLink.mutate(input);
581
+ return this.#client.apiClient.cloud.updateDataLink.mutate(input);
586
582
  }
587
583
  deletePublicDataLink(input) {
588
- return this.#apiClient.cloud.deleteDataLink.mutate(input);
584
+ return this.#client.apiClient.cloud.deleteDataLink.mutate(input);
589
585
  }
590
586
  downloadDataFromLink(input) {
591
587
  return downloadDataFromLink({
@@ -606,8 +602,8 @@ export class SecrecyCloudClient {
606
602
  ? decryptCryptoBox(sodium.from_hex(dataContent.key), dataContent.type === 'received_mail'
607
603
  ? dataContent.senderPublicKey
608
604
  : dataContent.type === 'cloud' || dataContent.type === 'lite'
609
- ? dataContent.publicKey
610
- : this.#keys.publicKey, this.#keys.privateKey)
605
+ ? dataContent.sharedByPublicKey
606
+ : this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)
611
607
  : null;
612
608
  const src = key
613
609
  ? await decrypt(key, encryptedContent, progressDecrypt, signal)
@@ -1,10 +1,6 @@
1
1
  export class SecrecyDbClient {
2
- // #client: SecrecyClient;
3
- // #keys: KeyPair;
4
- #apiClient;
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
  }