@secrecy/lib 1.29.0-feat-manage-user-data.2 → 1.29.0
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/client/SecrecyAppClient.js +2 -2
- package/dist/lib/client/SecrecyCloudClient.js +47 -47
- package/dist/lib/client/SecrecyMailClient.js +12 -3
- package/dist/lib/client/convert/mail.js +4 -4
- package/dist/lib/client/convert/node.js +1 -1
- package/dist/types/client/SecrecyCloudClient.d.ts +8 -8
- package/dist/types/client/types/file.d.ts +1 -1
- package/dist/types/client.d.ts +392 -390
- package/package.json +2 -2
|
@@ -82,8 +82,8 @@ export class SecrecyAppClient {
|
|
|
82
82
|
async updateSettings(settings) {
|
|
83
83
|
const updateAppSettings = await this.#apiClient.application.updateSettings.mutate({
|
|
84
84
|
cloudNodeDaysForDelete: settings.cloudNodeDaysForDelete,
|
|
85
|
-
historyFileDaysForDelete: settings.
|
|
86
|
-
historyMaxFileCount: settings.
|
|
85
|
+
historyFileDaysForDelete: settings.historyDataDaysForDelete,
|
|
86
|
+
historyMaxFileCount: settings.historyDataMaxCount,
|
|
87
87
|
});
|
|
88
88
|
return updateAppSettings;
|
|
89
89
|
}
|
|
@@ -23,39 +23,39 @@ export class SecrecyCloudClient {
|
|
|
23
23
|
this.#keys = keys;
|
|
24
24
|
this.#apiClient = apiClient;
|
|
25
25
|
}
|
|
26
|
-
async
|
|
27
|
-
const
|
|
28
|
-
|
|
26
|
+
async addDataToHistory({ dataId, nodeId, }) {
|
|
27
|
+
const addDataToHistory = await this.#apiClient.cloud.addDataToHistory.mutate({
|
|
28
|
+
dataId,
|
|
29
29
|
nodeId,
|
|
30
30
|
});
|
|
31
|
-
const node = await apiNodeFullToInternalFull(
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
31
|
+
const node = await apiNodeFullToInternalFull(addDataToHistory, this.#keys);
|
|
32
|
+
const data = node.history.find((d) => d.id === dataId);
|
|
33
|
+
if (data !== undefined) {
|
|
34
34
|
const users = node.users.filter(([u]) => u.id !== this.#client.app.userId);
|
|
35
|
-
await this.#apiClient.cloud.
|
|
36
|
-
|
|
35
|
+
await this.#apiClient.cloud.shareDataInHistory.mutate({
|
|
36
|
+
dataId: data.id,
|
|
37
37
|
nodeId,
|
|
38
38
|
users: await Promise.all(users.map(async ([u]) => {
|
|
39
39
|
const userPubKey = await this.#client.app.userPublicKey(u.id);
|
|
40
40
|
return {
|
|
41
41
|
id: u.id,
|
|
42
|
-
key: sodium.to_hex(encryptCryptoBox(sodium.from_hex(
|
|
42
|
+
key: sodium.to_hex(encryptCryptoBox(sodium.from_hex(data.key), userPubKey, this.#keys.privateKey)),
|
|
43
43
|
};
|
|
44
44
|
})),
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
return internalNodeFullToNodeFull(node);
|
|
48
48
|
}
|
|
49
|
-
async
|
|
49
|
+
async uploadData({ file, encryptProgress, uploadProgress, signal, }) {
|
|
50
50
|
const fileKey = secretStreamKeygen();
|
|
51
51
|
const fileBuffer = file instanceof File ? new Uint8Array(await file.arrayBuffer()) : file;
|
|
52
52
|
const compressed = compress(fileBuffer);
|
|
53
53
|
const { data: encryptedFile, md5: md5File, md5Encrypted, } = await encrypt(fileKey, compressed, encryptProgress, signal);
|
|
54
54
|
const encryptedFileKey = encryptCryptoBox(fileKey, this.#keys.publicKey, this.#keys.privateKey);
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
const uploadData = await this.#apiClient.cloud.uploadData.mutate({
|
|
56
|
+
dataSize: BigInt(encryptedFile.byteLength),
|
|
57
|
+
dataSizeBefore: BigInt(fileBuffer.byteLength),
|
|
58
|
+
dataKey: sodium.to_hex(encryptedFileKey),
|
|
59
59
|
md5Encrypted,
|
|
60
60
|
md5: md5File,
|
|
61
61
|
});
|
|
@@ -64,30 +64,30 @@ export class SecrecyCloudClient {
|
|
|
64
64
|
current: 0,
|
|
65
65
|
percent: 0,
|
|
66
66
|
});
|
|
67
|
-
if (
|
|
67
|
+
if (uploadData.parts.length === 0) {
|
|
68
68
|
await uploadProgress?.({
|
|
69
69
|
total: encryptedFile.byteLength,
|
|
70
70
|
current: encryptedFile.byteLength,
|
|
71
71
|
percent: 1,
|
|
72
72
|
});
|
|
73
|
-
return
|
|
73
|
+
return uploadData.dataId;
|
|
74
74
|
}
|
|
75
|
-
const
|
|
76
|
-
const { isUploadPartEnded } = await this.#apiClient.cloud.
|
|
77
|
-
|
|
75
|
+
const uploadDataPartEnd = async (md5, order) => {
|
|
76
|
+
const { isUploadPartEnded } = await this.#apiClient.cloud.uploadDataPartEnd.mutate({
|
|
77
|
+
dataId: uploadData.dataId,
|
|
78
78
|
md5,
|
|
79
79
|
order,
|
|
80
80
|
});
|
|
81
81
|
return isUploadPartEnded;
|
|
82
82
|
};
|
|
83
83
|
const uploadEnded = async () => {
|
|
84
|
-
const { isUploadEnded } = await this.#apiClient.cloud.
|
|
85
|
-
|
|
84
|
+
const { isUploadEnded } = await this.#apiClient.cloud.uploadDataEnd.mutate({
|
|
85
|
+
dataId: uploadData.dataId,
|
|
86
86
|
});
|
|
87
87
|
return isUploadEnded;
|
|
88
88
|
};
|
|
89
89
|
const chunkParts = new Array();
|
|
90
|
-
for (const [index, chunk] of enumerate(chunks(encryptedFile, Number(
|
|
90
|
+
for (const [index, chunk] of enumerate(chunks(encryptedFile, Number(uploadData.dataPartSize)))) {
|
|
91
91
|
chunkParts.push({
|
|
92
92
|
order: index + 1,
|
|
93
93
|
data: chunk,
|
|
@@ -113,31 +113,31 @@ export class SecrecyCloudClient {
|
|
|
113
113
|
for (const [key, value] of Object.entries(part.fields)) {
|
|
114
114
|
formData.append(key, value);
|
|
115
115
|
}
|
|
116
|
-
formData.append('file', new Blob([chunk.data]), `${
|
|
116
|
+
formData.append('file', new Blob([chunk.data]), `${uploadData.dataId}-${chunk.order}`);
|
|
117
117
|
await axios.post(part.url, formData, {
|
|
118
118
|
onUploadProgress: (progressEvent) => {
|
|
119
119
|
onProgress(part.order, progressEvent);
|
|
120
120
|
},
|
|
121
121
|
signal,
|
|
122
122
|
});
|
|
123
|
-
await
|
|
123
|
+
await uploadDataPartEnd(chunk.md5, chunk.order);
|
|
124
124
|
};
|
|
125
|
-
await promiseAllLimit(3,
|
|
125
|
+
await promiseAllLimit(3, uploadData.parts.map((p) => async () => {
|
|
126
126
|
await byPart(p);
|
|
127
127
|
}));
|
|
128
128
|
await uploadEnded();
|
|
129
|
-
dataCache.set(
|
|
130
|
-
return
|
|
129
|
+
dataCache.set(uploadData.dataId, fileBuffer);
|
|
130
|
+
return uploadData.dataId;
|
|
131
131
|
}
|
|
132
|
-
async
|
|
133
|
-
const
|
|
132
|
+
async uploadDataInCloud({ file, name, nodeId, encryptProgress, uploadProgress, signal, }) {
|
|
133
|
+
const dataId = await this.uploadData({
|
|
134
134
|
file,
|
|
135
135
|
encryptProgress,
|
|
136
136
|
uploadProgress,
|
|
137
137
|
signal,
|
|
138
138
|
});
|
|
139
139
|
return await this.saveInCloud({
|
|
140
|
-
|
|
140
|
+
dataId,
|
|
141
141
|
name,
|
|
142
142
|
nodeId,
|
|
143
143
|
});
|
|
@@ -221,7 +221,7 @@ export class SecrecyCloudClient {
|
|
|
221
221
|
return await apiNodeToExternalNodeFull(node, this.#keys);
|
|
222
222
|
}
|
|
223
223
|
async fileMetadata({ id }) {
|
|
224
|
-
const file = await this.#apiClient.cloud.
|
|
224
|
+
const file = await this.#apiClient.cloud.dataById.query({
|
|
225
225
|
id,
|
|
226
226
|
});
|
|
227
227
|
return apiFileToExternal(file, this.#keys);
|
|
@@ -275,7 +275,7 @@ export class SecrecyCloudClient {
|
|
|
275
275
|
if (cached !== undefined) {
|
|
276
276
|
return cached;
|
|
277
277
|
}
|
|
278
|
-
const fileContent = await this.#apiClient.cloud.
|
|
278
|
+
const fileContent = await this.#apiClient.cloud.dataContentById.query({
|
|
279
279
|
id: fileId,
|
|
280
280
|
});
|
|
281
281
|
const progressParts = {};
|
|
@@ -347,13 +347,13 @@ export class SecrecyCloudClient {
|
|
|
347
347
|
if (encryptedContent === null) {
|
|
348
348
|
throw `Can't find content for file ${fileId}`;
|
|
349
349
|
}
|
|
350
|
-
const data = await finalize(encryptedContent);
|
|
350
|
+
const data = await finalize(new Uint8Array(encryptedContent));
|
|
351
351
|
dataCache.set(fileId, data);
|
|
352
352
|
return data;
|
|
353
353
|
}
|
|
354
|
-
async deleteFile({
|
|
355
|
-
const { isDeleted } = await this.#apiClient.cloud.
|
|
356
|
-
|
|
354
|
+
async deleteFile({ dataId, nodeId, }) {
|
|
355
|
+
const { isDeleted } = await this.#apiClient.cloud.deleteData.mutate({
|
|
356
|
+
dataId,
|
|
357
357
|
nodeId,
|
|
358
358
|
});
|
|
359
359
|
return isDeleted;
|
|
@@ -381,7 +381,7 @@ export class SecrecyCloudClient {
|
|
|
381
381
|
});
|
|
382
382
|
return isMoved;
|
|
383
383
|
}
|
|
384
|
-
async saveInCloud({
|
|
384
|
+
async saveInCloud({ dataId, name, nodeId, }) {
|
|
385
385
|
if (nodeId !== undefined && !nodesCache.has(nodeId)) {
|
|
386
386
|
await this.node({ id: nodeId });
|
|
387
387
|
if (!nodesCache.has(nodeId)) {
|
|
@@ -394,27 +394,27 @@ export class SecrecyCloudClient {
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
let key = '';
|
|
397
|
-
const file = filesCache.get(
|
|
397
|
+
const file = filesCache.get(dataId);
|
|
398
398
|
if (file === undefined) {
|
|
399
|
-
await this.fileMetadata({ id:
|
|
400
|
-
const file = filesCache.get(
|
|
399
|
+
await this.fileMetadata({ id: dataId });
|
|
400
|
+
const file = filesCache.get(dataId);
|
|
401
401
|
if (file === undefined) {
|
|
402
402
|
const receivedMails = await this.#client.mail.receivedMails();
|
|
403
|
-
const mail = receivedMails.find((m) => m.files.some((f) => f.id ===
|
|
403
|
+
const mail = receivedMails.find((m) => m.files.some((f) => f.id === dataId));
|
|
404
404
|
if (mail === undefined) {
|
|
405
405
|
const err = {
|
|
406
406
|
name: 'ClientError',
|
|
407
407
|
code: 'NOT_FOUND',
|
|
408
|
-
message: `Can't find mail with the file ${
|
|
408
|
+
message: `Can't find mail with the file ${dataId}`,
|
|
409
409
|
};
|
|
410
410
|
throw err;
|
|
411
411
|
}
|
|
412
|
-
const fileMail = mail.files.find((f) => f.id ===
|
|
412
|
+
const fileMail = mail.files.find((f) => f.id === dataId);
|
|
413
413
|
if (fileMail === undefined) {
|
|
414
414
|
const err = {
|
|
415
415
|
name: 'ClientError',
|
|
416
416
|
code: 'NOT_FOUND',
|
|
417
|
-
message: `Can't find mail with the file ${
|
|
417
|
+
message: `Can't find mail with the file ${dataId}`,
|
|
418
418
|
};
|
|
419
419
|
throw err;
|
|
420
420
|
}
|
|
@@ -434,10 +434,10 @@ export class SecrecyCloudClient {
|
|
|
434
434
|
const encryptedName = await encryptName(name, sodium.to_hex(nameKey));
|
|
435
435
|
const encryptedNameKey = sodium.to_hex(encryptCryptoBox(nameKey, this.#keys.publicKey, this.#keys.privateKey));
|
|
436
436
|
const saveInCloud = await this.#apiClient.cloud.saveInCloud.mutate({
|
|
437
|
-
|
|
437
|
+
dataId,
|
|
438
438
|
key,
|
|
439
439
|
nodeId: nodeId ?? null,
|
|
440
|
-
|
|
440
|
+
fileName: encryptedName,
|
|
441
441
|
nameKey: encryptedNameKey,
|
|
442
442
|
});
|
|
443
443
|
const node = await apiNodeToExternalNodeFull(saveInCloud, this.#keys);
|
|
@@ -468,7 +468,7 @@ export class SecrecyCloudClient {
|
|
|
468
468
|
nameKey: nameKey !== null
|
|
469
469
|
? sodium.to_hex(encryptCryptoBox(sodium.from_hex(nameKey), publicKey, this.#keys.privateKey))
|
|
470
470
|
: null,
|
|
471
|
-
|
|
471
|
+
data: 'history' in node
|
|
472
472
|
? node.history.map((f) => ({
|
|
473
473
|
id: f.id,
|
|
474
474
|
key: sodium.to_hex(encryptCryptoBox(sodium.from_hex(f.key), publicKey, this.#keys.privateKey)),
|
|
@@ -173,7 +173,16 @@ export class SecrecyMailClient {
|
|
|
173
173
|
}
|
|
174
174
|
await this.#apiClient.mail.sendOne.mutate({
|
|
175
175
|
id: mail.mailIntegrityId,
|
|
176
|
-
recipient:
|
|
176
|
+
recipient: {
|
|
177
|
+
...input,
|
|
178
|
+
attachments: input.attachments.map(({ dataId, key, name }) => {
|
|
179
|
+
return {
|
|
180
|
+
id: dataId,
|
|
181
|
+
key,
|
|
182
|
+
name,
|
|
183
|
+
};
|
|
184
|
+
}),
|
|
185
|
+
},
|
|
177
186
|
});
|
|
178
187
|
}
|
|
179
188
|
catch {
|
|
@@ -272,7 +281,7 @@ export class SecrecyMailClient {
|
|
|
272
281
|
recipientsFiles.push({
|
|
273
282
|
id: f.id,
|
|
274
283
|
name: sodium.to_hex(encryptCryptoBox(sodium.from_string(f.name), pubKey, this.#keys.privateKey)),
|
|
275
|
-
|
|
284
|
+
key: sodium.to_hex(encryptCryptoBox(sodium.from_hex(key), pubKey, this.#keys.privateKey)),
|
|
276
285
|
});
|
|
277
286
|
}
|
|
278
287
|
return {
|
|
@@ -280,7 +289,7 @@ export class SecrecyMailClient {
|
|
|
280
289
|
recipientId: idOrMail,
|
|
281
290
|
body: sodium.to_hex(encryptCryptoBox(sodium.from_string(body), pubKey, this.#keys.privateKey)),
|
|
282
291
|
subject: sodium.to_hex(encryptCryptoBox(sodium.from_string(subject), pubKey, this.#keys.privateKey)),
|
|
283
|
-
|
|
292
|
+
attachments: recipientsFiles,
|
|
284
293
|
};
|
|
285
294
|
};
|
|
286
295
|
}
|
|
@@ -30,12 +30,12 @@ export async function convertInternalMailToExternal({ client, mail, keyPair, })
|
|
|
30
30
|
temporaryRecipients: [], // TODO
|
|
31
31
|
recipients: mI.recipients,
|
|
32
32
|
sender: mail.sender,
|
|
33
|
-
files: mail.
|
|
34
|
-
const name = sodium.to_string(decryptCryptoBox(sodium.from_hex(
|
|
33
|
+
files: mail.attachments.map((attachment) => {
|
|
34
|
+
const name = sodium.to_string(decryptCryptoBox(sodium.from_hex(attachment.name), pubKey, privateKey));
|
|
35
35
|
return {
|
|
36
|
-
id:
|
|
36
|
+
id: attachment.dataId,
|
|
37
37
|
name,
|
|
38
|
-
key:
|
|
38
|
+
key: attachment.key,
|
|
39
39
|
};
|
|
40
40
|
}),
|
|
41
41
|
};
|
|
@@ -23,7 +23,7 @@ export async function apiNodeToInternal(apiNode, keyPair) {
|
|
|
23
23
|
deletedAt: apiNode.deletedAt,
|
|
24
24
|
users: apiNode.users,
|
|
25
25
|
parentId: apiNode.parentId ?? null,
|
|
26
|
-
currentFileId: apiNode.
|
|
26
|
+
currentFileId: apiNode.currentDataId ?? null,
|
|
27
27
|
};
|
|
28
28
|
internal.access = { ...apiNode.access };
|
|
29
29
|
if (apiNode.access.nameKey !== null) {
|
|
@@ -5,17 +5,17 @@ import { type DownloadProgress } from '../types.js';
|
|
|
5
5
|
export declare class SecrecyCloudClient {
|
|
6
6
|
#private;
|
|
7
7
|
constructor(client: SecrecyClient, keys: KeyPair, apiClient: ApiClient);
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
addDataToHistory({ dataId, nodeId, }: {
|
|
9
|
+
dataId: string;
|
|
10
10
|
nodeId: string;
|
|
11
11
|
}): Promise<NodeFull>;
|
|
12
|
-
|
|
12
|
+
uploadData({ file, encryptProgress, uploadProgress, signal, }: {
|
|
13
13
|
file: globalThis.File | Uint8Array;
|
|
14
14
|
encryptProgress?: ProgressCallback;
|
|
15
15
|
uploadProgress?: ProgressCallback;
|
|
16
16
|
signal?: AbortSignal;
|
|
17
17
|
}): Promise<string>;
|
|
18
|
-
|
|
18
|
+
uploadDataInCloud({ file, name, nodeId, encryptProgress, uploadProgress, signal, }: {
|
|
19
19
|
file: globalThis.File | Uint8Array;
|
|
20
20
|
name: string;
|
|
21
21
|
nodeId?: string;
|
|
@@ -66,8 +66,8 @@ export declare class SecrecyCloudClient {
|
|
|
66
66
|
progressDecrypt?: ProgressCallback;
|
|
67
67
|
signal?: AbortSignal;
|
|
68
68
|
}): Promise<Uint8Array>;
|
|
69
|
-
deleteFile({
|
|
70
|
-
|
|
69
|
+
deleteFile({ dataId, nodeId, }: {
|
|
70
|
+
dataId: string;
|
|
71
71
|
nodeId: string;
|
|
72
72
|
}): Promise<boolean>;
|
|
73
73
|
deleteNode({ nodeId }: {
|
|
@@ -79,8 +79,8 @@ export declare class SecrecyCloudClient {
|
|
|
79
79
|
nodeIds: string[];
|
|
80
80
|
parentNodeId?: string | null | undefined;
|
|
81
81
|
}): Promise<boolean>;
|
|
82
|
-
saveInCloud({
|
|
83
|
-
|
|
82
|
+
saveInCloud({ dataId, name, nodeId, }: {
|
|
83
|
+
dataId: string;
|
|
84
84
|
name: string;
|
|
85
85
|
nodeId?: string;
|
|
86
86
|
}): Promise<NodeFull>;
|
|
@@ -3,4 +3,4 @@ export type FileMetadata = Pick<ApiFile, 'id' | 'size' | 'sizeBefore' | 'md5' |
|
|
|
3
3
|
export type InternalFile = FileMetadata & {
|
|
4
4
|
key: string;
|
|
5
5
|
};
|
|
6
|
-
export type ApiFile = NonNullable<RouterOutputs['cloud']['
|
|
6
|
+
export type ApiFile = NonNullable<RouterOutputs['cloud']['dataById']>;
|