@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.
- package/dist/lib/base-client.js +26 -2
- package/dist/lib/client/SecrecyAppClient.js +13 -17
- package/dist/lib/client/SecrecyCloudClient.js +131 -135
- 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 -7
- package/dist/lib/client/index.js +48 -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/client/upload.js +29 -17
- package/dist/lib/crypto/domain.js +7 -3
- package/dist/lib/index.js +1 -0
- package/dist/types/base-client.d.ts +2 -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 +11 -3
- 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/upload.d.ts +4 -3
- package/dist/types/client.d.ts +1438 -1050
- package/dist/types/crypto/domain.d.ts +5 -3
- 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,13 @@ export class SecrecyCloudClient {
|
|
|
461
462
|
}
|
|
462
463
|
return node;
|
|
463
464
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
const
|
|
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.#
|
|
505
|
+
return apiNodeForEncryptionToInternal(node, this.#client.keyPairs);
|
|
512
506
|
}));
|
|
513
507
|
nodes.push(...finalNodes);
|
|
514
508
|
const nodesMappedUsers = {};
|
|
515
|
-
for (const
|
|
516
|
-
nodesMappedUsers[
|
|
517
|
-
for (const nodeId of
|
|
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
|
-
|
|
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),
|
|
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),
|
|
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.#
|
|
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.#
|
|
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
|
-
|
|
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.
|
|
610
|
-
: this.#
|
|
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
|
-
|
|
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
|
}
|