@secrecy/lib 1.74.6 → 1.75.0-feat-groups-identity.2
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 +26 -2
- package/dist/lib/client/SecrecyAppClient.js +14 -18
- package/dist/lib/client/SecrecyCloudClient.js +130 -135
- package/dist/lib/client/SecrecyDbClient.js +1 -8
- 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 +8 -4
- package/dist/lib/client/convert/mail.js +8 -6
- package/dist/lib/client/convert/node.js +59 -34
- package/dist/lib/client/data-link.js +4 -1
- package/dist/lib/client/helpers.js +17 -7
- package/dist/lib/client/index.js +48 -12
- package/dist/lib/client/storage.js +3 -2
- package/dist/lib/client/types/identity.js +19 -0
- package/dist/lib/client/types/index.js +3 -7
- package/dist/lib/client/upload.js +20 -17
- package/dist/lib/crypto/data.js +4 -4
- package/dist/lib/crypto/domain.js +10 -10
- package/dist/lib/index.js +1 -0
- package/dist/lib/minify/lz4.js +1 -0
- package/dist/lib/utils/links.js +5 -5
- package/dist/lib/utils.js +1 -1
- package/dist/lib/worker/sodium.js +2 -2
- package/dist/types/base-client.d.ts +3 -1
- package/dist/types/client/SecrecyAppClient.d.ts +2 -3
- package/dist/types/client/SecrecyCloudClient.d.ts +19 -19
- package/dist/types/client/SecrecyDbClient.d.ts +1 -4
- 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/data-link.d.ts +2 -2
- package/dist/types/client/index.d.ts +11 -3
- package/dist/types/client/storage.d.ts +3 -2
- package/dist/types/client/types/identity.d.ts +37 -0
- package/dist/types/client/types/index.d.ts +17 -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/upload.d.ts +8 -7
- package/dist/types/client.d.ts +1438 -1050
- package/dist/types/crypto/data.d.ts +2 -2
- package/dist/types/crypto/domain.d.ts +6 -4
- package/dist/types/crypto/index.d.ts +3 -3
- package/dist/types/index.d.ts +2 -1
- 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 {
|
|
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
|
-
|
|
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({
|
|
25
|
-
|
|
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
|
-
|
|
29
|
-
const
|
|
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
|
-
|
|
30
|
+
pubKey: publicKey,
|
|
40
31
|
key: data.key
|
|
41
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), publicKey, this.#
|
|
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
|
-
|
|
57
|
-
|
|
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.#
|
|
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.#
|
|
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.#
|
|
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,
|
|
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
|
-
|
|
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.
|
|
99
|
-
throw new Error(`
|
|
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.
|
|
103
|
-
? await encryptName(name, node.
|
|
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.#
|
|
120
|
-
publicKey: this.#
|
|
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.#
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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({
|
|
144
|
-
|
|
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.#
|
|
145
|
+
const data = await this.#client.apiClient.cloud.dataById.query({ id });
|
|
146
|
+
return apiDataToExternal(data, this.#client.keyPairs);
|
|
149
147
|
}
|
|
150
|
-
async shareNode(
|
|
148
|
+
async shareNode(accesses, progress) {
|
|
151
149
|
// TODO: Validate input
|
|
152
|
-
const nodesMap = await this.#apiClient.cloud.shareNode.mutate(
|
|
153
|
-
|
|
154
|
-
|
|
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.
|
|
174
|
-
const nodesToUpdateRights = Object.fromEntries(Object.entries(nodesMap).map(([
|
|
175
|
-
|
|
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(([
|
|
187
|
+
const withKeys = Object.fromEntries(Object.entries(infos).map(([pubKey, nodes]) => {
|
|
192
188
|
return [
|
|
193
|
-
|
|
189
|
+
pubKey,
|
|
194
190
|
{
|
|
195
|
-
|
|
191
|
+
pubKey,
|
|
196
192
|
nodes: nodes.map((node) => {
|
|
197
|
-
const map = nodesMap[
|
|
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 [
|
|
216
|
+
for (const [pubKey, nodes] of Object.entries(withKeys)) {
|
|
221
217
|
if (nodes.nodes.length === 0) {
|
|
222
218
|
continue;
|
|
223
219
|
}
|
|
224
|
-
finishInput.push({
|
|
220
|
+
finishInput.push({ pubKey, nodes: nodes.nodes });
|
|
225
221
|
}
|
|
226
|
-
for (const [
|
|
222
|
+
for (const [pubKey, nodes] of Object.entries(nodesToUpdateRights)) {
|
|
227
223
|
if (nodes.length === 0) {
|
|
228
224
|
continue;
|
|
229
225
|
}
|
|
230
|
-
finishInput.push({
|
|
226
|
+
finishInput.push({ pubKey, nodes });
|
|
231
227
|
}
|
|
232
228
|
const subState = finishInput.length > 0
|
|
233
|
-
? await this.#apiClient.cloud.shareNodeFinish.mutate(
|
|
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.
|
|
281
|
-
|
|
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.
|
|
285
|
-
? await encryptName(name, node.
|
|
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.#
|
|
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.#
|
|
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.#
|
|
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.#
|
|
440
|
-
publicKey: this.#
|
|
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.#
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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,12 @@ export class SecrecyCloudClient {
|
|
|
461
462
|
}
|
|
462
463
|
return node;
|
|
463
464
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const userIds = Object.keys(userNodes).map((userId) => userId);
|
|
467
|
-
const nodeIds = Object.values(userNodes).flatMap((nodeIds) => nodeIds);
|
|
465
|
+
encryptNodesForIdentities = async (identityNodes) => {
|
|
466
|
+
const nodeIds = Object.values(identityNodes).flatMap((nodeIds) => nodeIds);
|
|
468
467
|
if (nodeIds.length === 0) {
|
|
469
468
|
return {};
|
|
470
469
|
}
|
|
471
470
|
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
471
|
// Retrieve and format nodes.
|
|
479
472
|
for (const nodeId of nodeIds) {
|
|
480
473
|
let node = nodesEncryptionCache.get(nodeId) ?? nodesCache.get(nodeId);
|
|
@@ -499,7 +492,7 @@ export class SecrecyCloudClient {
|
|
|
499
492
|
// Retrieve all missing nodes from cache to api.
|
|
500
493
|
const missingNodeIds = nodeIds.filter((nodeId) => !nodes.some((node) => node.id === nodeId));
|
|
501
494
|
const fetchedNodes = missingNodeIds.length > 0
|
|
502
|
-
? await this.#apiClient.cloud.nodesForEncryption.query({
|
|
495
|
+
? await this.#client.apiClient.cloud.nodesForEncryption.query({
|
|
503
496
|
ids: missingNodeIds,
|
|
504
497
|
})
|
|
505
498
|
: [];
|
|
@@ -508,13 +501,13 @@ export class SecrecyCloudClient {
|
|
|
508
501
|
throw new Error(`Unable to fetch some node infos (${diff.join(', ')})`);
|
|
509
502
|
}
|
|
510
503
|
const finalNodes = await Promise.all(fetchedNodes.map((node) => {
|
|
511
|
-
return apiNodeForEncryptionToInternal(node, this.#
|
|
504
|
+
return apiNodeForEncryptionToInternal(node, this.#client.keyPairs);
|
|
512
505
|
}));
|
|
513
506
|
nodes.push(...finalNodes);
|
|
514
507
|
const nodesMappedUsers = {};
|
|
515
|
-
for (const
|
|
516
|
-
nodesMappedUsers[
|
|
517
|
-
for (const nodeId of
|
|
508
|
+
for (const pubKey in identityNodes) {
|
|
509
|
+
nodesMappedUsers[pubKey] ??= [];
|
|
510
|
+
for (const nodeId of identityNodes[pubKey]) {
|
|
518
511
|
const node = nodes.find((node) => node.id === nodeId);
|
|
519
512
|
if (!node) {
|
|
520
513
|
throw new Error('Unable to retrieve node from ram');
|
|
@@ -524,17 +517,16 @@ export class SecrecyCloudClient {
|
|
|
524
517
|
throw new Error(`Can't share a node without data (${node.id})!`);
|
|
525
518
|
}
|
|
526
519
|
const nameKey = node.access?.nameKey;
|
|
527
|
-
|
|
528
|
-
nodesMappedUsers[userId].push({
|
|
520
|
+
nodesMappedUsers[pubKey].push({
|
|
529
521
|
id: node.id,
|
|
530
522
|
nameKey: nameKey !== null
|
|
531
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(nameKey),
|
|
523
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(nameKey), pubKey, this.#client.uaPrivateKey))
|
|
532
524
|
: null,
|
|
533
525
|
data: 'history' in node
|
|
534
526
|
? node.history.map((f) => ({
|
|
535
527
|
id: f.id,
|
|
536
528
|
key: f.key
|
|
537
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(f.key),
|
|
529
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(f.key), pubKey, this.#client.uaPrivateKey))
|
|
538
530
|
: null,
|
|
539
531
|
}))
|
|
540
532
|
: [],
|
|
@@ -545,15 +537,15 @@ export class SecrecyCloudClient {
|
|
|
545
537
|
};
|
|
546
538
|
async reportData({ id, reasons, }) {
|
|
547
539
|
const [rawData, secrecy] = await Promise.all([
|
|
548
|
-
this.#apiClient.cloud.dataById.query({ id }),
|
|
549
|
-
this.#apiClient.misc.publicKey.query(),
|
|
540
|
+
this.#client.apiClient.cloud.dataById.query({ id }),
|
|
541
|
+
this.#client.apiClient.misc.publicKey.query(),
|
|
550
542
|
]);
|
|
551
|
-
const data = apiDataToInternal(rawData, this.#
|
|
552
|
-
return this.#apiClient.cloud.reportData.mutate({
|
|
543
|
+
const data = apiDataToInternal(rawData, this.#client.keyPairs);
|
|
544
|
+
return this.#client.apiClient.cloud.reportData.mutate({
|
|
553
545
|
id: id,
|
|
554
546
|
reasons: reasons,
|
|
555
547
|
encryptedDataKey: data.key
|
|
556
|
-
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), secrecy.publicKey, this.#
|
|
548
|
+
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), secrecy.publicKey, this.#client.uaPrivateKey))
|
|
557
549
|
: null,
|
|
558
550
|
});
|
|
559
551
|
}
|
|
@@ -567,25 +559,28 @@ export class SecrecyCloudClient {
|
|
|
567
559
|
throw new Error("It's not possible to transfer a cold stored data to a lite storage!");
|
|
568
560
|
}
|
|
569
561
|
}
|
|
570
|
-
return this.#apiClient.cloud.moveToStorageType.mutate(input);
|
|
562
|
+
return this.#client.apiClient.cloud.moveToStorageType.mutate(input);
|
|
571
563
|
}
|
|
572
564
|
getPublicDataLink(input) {
|
|
573
|
-
return this.#apiClient.cloud.dataLink.query(input);
|
|
565
|
+
return this.#client.apiClient.cloud.dataLink.query(input);
|
|
574
566
|
}
|
|
575
567
|
getPublicDataLinks(input) {
|
|
576
|
-
return this.#apiClient.cloud.dataLinks.query(input);
|
|
568
|
+
return this.#client.apiClient.cloud.dataLinks.query(input);
|
|
577
569
|
}
|
|
578
570
|
checkAccesses(input) {
|
|
579
|
-
return this.#apiClient.cloud.checkAccesses.query(input);
|
|
571
|
+
return this.#client.apiClient.cloud.checkAccesses.query(input);
|
|
580
572
|
}
|
|
581
573
|
createPublicDataLink(input) {
|
|
582
|
-
|
|
574
|
+
if (input.expireAt && input.expireAt <= new Date()) {
|
|
575
|
+
throw new Error('Unable to create public link using a past expireAt date!');
|
|
576
|
+
}
|
|
577
|
+
return this.#client.apiClient.cloud.createDataLink.mutate(input);
|
|
583
578
|
}
|
|
584
579
|
updatePublicDataLink(input) {
|
|
585
|
-
return this.#apiClient.cloud.updateDataLink.mutate(input);
|
|
580
|
+
return this.#client.apiClient.cloud.updateDataLink.mutate(input);
|
|
586
581
|
}
|
|
587
582
|
deletePublicDataLink(input) {
|
|
588
|
-
return this.#apiClient.cloud.deleteDataLink.mutate(input);
|
|
583
|
+
return this.#client.apiClient.cloud.deleteDataLink.mutate(input);
|
|
589
584
|
}
|
|
590
585
|
downloadDataFromLink(input) {
|
|
591
586
|
return downloadDataFromLink({
|
|
@@ -606,8 +601,8 @@ export class SecrecyCloudClient {
|
|
|
606
601
|
? decryptCryptoBox(sodium.from_hex(dataContent.key), dataContent.type === 'received_mail'
|
|
607
602
|
? dataContent.senderPublicKey
|
|
608
603
|
: dataContent.type === 'cloud' || dataContent.type === 'lite'
|
|
609
|
-
? dataContent.
|
|
610
|
-
: this.#
|
|
604
|
+
? dataContent.sharedByPublicKey
|
|
605
|
+
: this.#client.uaIdentity.identityPubKey, this.#client.uaPrivateKey)
|
|
611
606
|
: null;
|
|
612
607
|
const src = key
|
|
613
608
|
? await decrypt(key, encryptedContent, progressDecrypt, signal)
|