@secrecy/lib 1.73.7 → 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.
Files changed (41) hide show
  1. package/dist/lib/base-client.js +4 -2
  2. package/dist/lib/client/SecrecyAppClient.js +13 -17
  3. package/dist/lib/client/SecrecyCloudClient.js +129 -137
  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 +16 -7
  15. package/dist/lib/client/index.js +45 -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/index.js +1 -0
  20. package/dist/types/client/SecrecyAppClient.d.ts +2 -3
  21. package/dist/types/client/SecrecyCloudClient.d.ts +18 -18
  22. package/dist/types/client/SecrecyDbClient.d.ts +1 -3
  23. package/dist/types/client/SecrecyMailClient.d.ts +2 -3
  24. package/dist/types/client/SecrecyOrganizationClient.d.ts +2 -3
  25. package/dist/types/client/SecrecyPayClient.d.ts +1 -3
  26. package/dist/types/client/SecrecyPseudonymClient.d.ts +2 -3
  27. package/dist/types/client/SecrecyUserClient.d.ts +2 -3
  28. package/dist/types/client/convert/data.d.ts +3 -3
  29. package/dist/types/client/convert/mail.d.ts +3 -5
  30. package/dist/types/client/convert/node.d.ts +5 -5
  31. package/dist/types/client/index.d.ts +9 -2
  32. package/dist/types/client/storage.d.ts +3 -2
  33. package/dist/types/client/types/identity.d.ts +29 -0
  34. package/dist/types/client/types/index.d.ts +13 -9
  35. package/dist/types/client/types/mail.d.ts +2 -1
  36. package/dist/types/client/types/node.d.ts +12 -9
  37. package/dist/types/client/types/user.d.ts +15 -0
  38. package/dist/types/client.d.ts +679 -513
  39. package/dist/types/crypto/index.d.ts +3 -3
  40. package/dist/types/index.d.ts +2 -1
  41. package/package.json +2 -2
@@ -111,10 +111,12 @@ export class BaseClient {
111
111
  const local = getStorage(false);
112
112
  const session = getStorage(true);
113
113
  local.jwt.clear();
114
- local.userAppKeys.clear();
114
+ local.identities.clear();
115
+ local.keyPairs.clear();
115
116
  local.userAppSession.clear();
116
117
  session.jwt.clear();
117
- session.userAppKeys.clear();
118
+ session.identities.clear();
119
+ session.keyPairs.clear();
118
120
  session.userAppSession.clear();
119
121
  usersCache.clear();
120
122
  };
@@ -4,15 +4,11 @@ import { publicKeysCache } from '../cache.js';
4
4
  export class SecrecyAppClient {
5
5
  jwt;
6
6
  jwtDecoded;
7
- // #client: SecrecyClient
8
- // #keys: KeyPair;
9
- #apiClient;
10
- constructor(uaJwt, _client, _keys, apiClient) {
7
+ #client;
8
+ constructor(uaJwt, client) {
11
9
  this.jwt = uaJwt;
12
10
  this.jwtDecoded = decode(uaJwt);
13
- // this.#client = client
14
- // this.#keys = keys;
15
- this.#apiClient = apiClient;
11
+ this.#client = client;
16
12
  }
17
13
  get userId() {
18
14
  const sub = this.jwtDecoded.sub;
@@ -35,7 +31,7 @@ export class SecrecyAppClient {
35
31
  // if (this.jwtDecoded.exp && this.jwtDecoded.exp * 1000 < Date.now()) {
36
32
  // return this.jwt;
37
33
  // }
38
- const { jwt } = await this.#apiClient.auth.jwt.query({
34
+ const { jwt } = await this.#client.apiClient.auth.jwt.query({
39
35
  includeEmail: typeof this.jwtDecoded.email === 'string',
40
36
  });
41
37
  this.jwt = jwt;
@@ -53,19 +49,19 @@ export class SecrecyAppClient {
53
49
  return jwt;
54
50
  }
55
51
  async limits() {
56
- return await this.#apiClient.application.limits.query({});
52
+ return await this.#client.apiClient.application.limits.query({});
57
53
  }
58
54
  async metrics() {
59
- return await this.#apiClient.application.metrics.query({});
55
+ return await this.#client.apiClient.application.metrics.query({});
60
56
  }
61
57
  async quotas() {
62
- return await this.#apiClient.application.quotas.query({});
58
+ return await this.#client.apiClient.application.quotas.query({});
63
59
  }
64
60
  async isApplicationUser(input) {
65
- return await this.#apiClient.application.isApplicationUser.query(input);
61
+ return await this.#client.apiClient.application.isApplicationUser.query(input);
66
62
  }
67
63
  async updateNotifications(notifications) {
68
- const updateAppNotifications = await this.#apiClient.application.updateNotification.mutate({
64
+ const updateAppNotifications = await this.#client.apiClient.application.updateNotification.mutate({
69
65
  cloud: notifications.cloud,
70
66
  disableAllUntil: notifications.disableAllUntil,
71
67
  enableAll: notifications.enableAll,
@@ -74,7 +70,7 @@ export class SecrecyAppClient {
74
70
  return updateAppNotifications;
75
71
  }
76
72
  async notifications() {
77
- return await this.#apiClient.application.notification.query();
73
+ return await this.#client.apiClient.application.notification.query();
78
74
  }
79
75
  async userPublicKey(input, appId) {
80
76
  appId ??= this.appId;
@@ -92,7 +88,7 @@ export class SecrecyAppClient {
92
88
  ...new Set(userIds.filter((userId) => publicKeys[userId] === undefined)),
93
89
  ];
94
90
  if (missingKeys.length > 0) {
95
- const userKeysMap = await this.#apiClient.application.userPublicKey.query({
91
+ const userKeysMap = await this.#client.apiClient.application.userPublicKey.query({
96
92
  userIds: missingKeys,
97
93
  appId,
98
94
  });
@@ -113,11 +109,11 @@ export class SecrecyAppClient {
113
109
  return Array.isArray(input) ? publicKeys : publicKeys[input];
114
110
  }
115
111
  async settings() {
116
- const settings = await this.#apiClient.application.settings.query({});
112
+ const settings = await this.#client.apiClient.application.settings.query({});
117
113
  return settings;
118
114
  }
119
115
  async updateSettings(settings) {
120
- const updateAppSettings = await this.#apiClient.application.updateSettings.mutate({
116
+ const updateAppSettings = await this.#client.apiClient.application.updateSettings.mutate({
121
117
  cloudNodeDaysForDelete: settings.cloudNodeDaysForDelete,
122
118
  historyDataDaysForDelete: settings.historyDataDaysForDelete,
123
119
  historyDataMaxCount: settings.historyDataMaxCount,
@@ -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
- #keys;
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({ dataId, nodeId });
29
- const node = await apiNodeFullToInternalFull(addDataToHistory, this.#keys);
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
- // TODO sad to have to make this extra request
33
- const me = await this.#client.me();
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
- id: user.id,
34
+ pubKey: publicKey,
44
35
  key: data.key
45
- ? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), publicKey, this.#keys.privateKey))
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.#keys.publicKey, this.#keys.privateKey)
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.#keys.publicKey) {
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.#keys)));
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.#keys)));
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.#keys)));
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, userId, }) {
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
- userId,
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.access?.nameKey === undefined) {
271
- throw new Error(`Can't have access to node ${nodeId}`);
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.access.nameKey !== null
275
- ? await encryptName(name, node.access.nameKey)
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.#keys.privateKey,
292
- publicKey: this.#keys.publicKey,
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.#keys);
300
- const users = folder.parent?.users?.filter(([u]) => u.id !== folder.owner.id) ?? [];
301
- if (users.length > 0) {
302
- await this.shareNode(users.map(([user, permissions]) => ({
303
- userId: user.id,
304
- nodeId: folder.id,
305
- rights: permissions.rights,
306
- addAccess: permissions.addAccess,
307
- delAccess: permissions.delAccess,
308
- sharingAddAccess: permissions.sharingAddAccess,
309
- sharingDelAccess: permissions.sharingDelAccess,
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({ id, deleted });
316
- return await apiNodeToExternalNodeFull(node, this.#keys);
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.#keys);
316
+ const data = await this.#client.apiClient.cloud.dataById.query({ id });
317
+ return apiDataToExternal(data, this.#client.keyPairs);
321
318
  }
322
- async shareNode(input, progress) {
319
+ async shareNode(accesses, progress) {
323
320
  // TODO: Validate input
324
- const nodesMap = await this.#apiClient.cloud.shareNode.mutate(input);
325
- const neededUserKey = Object.entries(nodesMap)
326
- .filter(([, nodes]) => nodes.some((node) => node.includeKeys))
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.encryptNodesForUsers(nodesToEncrypt, publicKeysMap);
346
- const nodesToUpdateRights = Object.fromEntries(Object.entries(nodesMap).map(([userId, nodes]) => [
347
- userId,
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(([userId, nodes]) => {
358
+ const withKeys = Object.fromEntries(Object.entries(infos).map(([pubKey, nodes]) => {
364
359
  return [
365
- userId,
360
+ pubKey,
366
361
  {
367
- userId,
362
+ pubKey,
368
363
  nodes: nodes.map((node) => {
369
- const map = nodesMap[userId];
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 [userId, nodes] of Object.entries(withKeys)) {
387
+ for (const [pubKey, nodes] of Object.entries(withKeys)) {
393
388
  if (nodes.nodes.length === 0) {
394
389
  continue;
395
390
  }
396
- finishInput.push({ userId, nodes: nodes.nodes });
391
+ finishInput.push({ pubKey, nodes: nodes.nodes });
397
392
  }
398
- for (const [userId, nodes] of Object.entries(nodesToUpdateRights)) {
393
+ for (const [pubKey, nodes] of Object.entries(nodesToUpdateRights)) {
399
394
  if (nodes.length === 0) {
400
395
  continue;
401
396
  }
402
- finishInput.push({ userId, nodes });
397
+ finishInput.push({ pubKey, nodes });
403
398
  }
404
399
  const subState = finishInput.length > 0
405
- ? await this.#apiClient.cloud.shareNodeFinish.mutate(finishInput)
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.access?.nameKey === undefined) {
453
- throw new Error(`Can't have access to node ${nodeId}`);
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.access.nameKey !== null
457
- ? await encryptName(name, node.access.nameKey)
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.#keys);
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.#keys.privateKey)
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.#keys.publicKey, this.#keys.privateKey))
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.#keys.privateKey,
612
- publicKey: this.#keys.publicKey,
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.#keys);
622
- const me = node.parent?.users.find(([u]) => u.id === node.owner.id);
623
- // TODO: ??
624
- if (me !== undefined && ['delete', 'write'].includes(me[1].rights)) {
625
- const others = node.parent?.users.filter(([u]) => u.id !== node.owner.id) ?? [];
626
- if (others.length > 0) {
627
- await this.shareNode(others.map(([user, permissions]) => ({
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
- encryptNodesForUsers = async (userNodes, // { [userId]: nodeIds[] }
637
- userPublicKeys) => {
638
- const userIds = Object.keys(userNodes).map((userId) => userId);
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.#keys);
676
+ return apiNodeForEncryptionToInternal(node, this.#client.keyPairs);
684
677
  }));
685
678
  nodes.push(...finalNodes);
686
679
  const nodesMappedUsers = {};
687
- for (const userId in userNodes) {
688
- nodesMappedUsers[userId] ??= [];
689
- for (const nodeId of userNodes[userId]) {
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
- const publicKey = userPublicKeys[userId];
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), publicKey, this.#keys.privateKey))
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), publicKey, this.#keys.privateKey))
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.#keys);
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.#keys.privateKey))
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.#keys.publicKey, this.#keys.privateKey)
822
+ : this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)
831
823
  : null;
832
824
  const src = key
833
825
  ? await decrypt(key, encryptedContent, progressDecrypt, signal)