@secrecy/lib 1.61.2 → 1.62.0-feat-storage-providers.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.
|
@@ -50,7 +50,7 @@ export class SecrecyCloudClient {
|
|
|
50
50
|
}
|
|
51
51
|
return internalNodeFullToNodeFull(node);
|
|
52
52
|
}
|
|
53
|
-
async uploadData({
|
|
53
|
+
async uploadData({ storage, data, encrypted = true, encryptProgress, uploadProgress, signal, meta, }) {
|
|
54
54
|
const dataBuffer = data instanceof File ? new Uint8Array(await data.arrayBuffer()) : data;
|
|
55
55
|
let filetype;
|
|
56
56
|
if (meta === true) {
|
|
@@ -62,7 +62,8 @@ export class SecrecyCloudClient {
|
|
|
62
62
|
else if (!encrypted) {
|
|
63
63
|
filetype = await fileTypeFromBuffer(dataBuffer);
|
|
64
64
|
}
|
|
65
|
-
if (
|
|
65
|
+
if (storage.protocol === 'mongo' &&
|
|
66
|
+
dataBuffer.byteLength > kiloToBytes(1024)) {
|
|
66
67
|
throw new Error('The data is too big for lite upload!');
|
|
67
68
|
}
|
|
68
69
|
const compressed = encrypted ? compress(dataBuffer) : dataBuffer;
|
|
@@ -81,11 +82,11 @@ export class SecrecyCloudClient {
|
|
|
81
82
|
current: 0,
|
|
82
83
|
percent: 0,
|
|
83
84
|
});
|
|
84
|
-
if (
|
|
85
|
+
if (storage.protocol === 'mongo') {
|
|
85
86
|
const uploadDataArgs = encryptedDataKey && md5Encrypted
|
|
86
87
|
? {
|
|
87
88
|
type: 'encrypted',
|
|
88
|
-
|
|
89
|
+
bytes: Buffer.from(encryptedData),
|
|
89
90
|
sizeEncrypted: BigInt(encryptedData.byteLength),
|
|
90
91
|
size: BigInt(dataBuffer.byteLength),
|
|
91
92
|
key: sodium.to_hex(encryptedDataKey),
|
|
@@ -95,13 +96,13 @@ export class SecrecyCloudClient {
|
|
|
95
96
|
}
|
|
96
97
|
: {
|
|
97
98
|
type: 'unencrypted',
|
|
98
|
-
|
|
99
|
+
bytes: Buffer.from(encryptedData),
|
|
99
100
|
md5: md5Data,
|
|
100
101
|
sizeEncrypted: undefined,
|
|
101
102
|
size: BigInt(dataBuffer.byteLength),
|
|
102
103
|
...filetype,
|
|
103
104
|
};
|
|
104
|
-
const uploadData = await this.#apiClient.cloud.
|
|
105
|
+
const uploadData = await this.#apiClient.cloud.uploadMongoData.mutate(uploadDataArgs, { signal });
|
|
105
106
|
await uploadProgress?.({
|
|
106
107
|
total: encryptedData.byteLength,
|
|
107
108
|
current: encryptedData.byteLength,
|
|
@@ -109,7 +110,7 @@ export class SecrecyCloudClient {
|
|
|
109
110
|
});
|
|
110
111
|
const localData = {
|
|
111
112
|
id: uploadData.id,
|
|
112
|
-
|
|
113
|
+
storage: storage,
|
|
113
114
|
size: uploadDataArgs.size,
|
|
114
115
|
sizeEncrypted: uploadDataArgs.sizeEncrypted ?? null,
|
|
115
116
|
data: dataBuffer,
|
|
@@ -118,7 +119,7 @@ export class SecrecyCloudClient {
|
|
|
118
119
|
dataContentCache.set(uploadData.id, localData);
|
|
119
120
|
return localData;
|
|
120
121
|
}
|
|
121
|
-
if (
|
|
122
|
+
if (storage.protocol === 's3') {
|
|
122
123
|
const uploadDataArgs = encryptedDataKey && md5Encrypted
|
|
123
124
|
? {
|
|
124
125
|
type: 'encrypted',
|
|
@@ -136,7 +137,7 @@ export class SecrecyCloudClient {
|
|
|
136
137
|
sizeEncrypted: undefined,
|
|
137
138
|
...filetype,
|
|
138
139
|
};
|
|
139
|
-
const uploadDataCaller =
|
|
140
|
+
const uploadDataCaller = storage.protocol === 's3'
|
|
140
141
|
? this.#apiClient.cloud.uploadData
|
|
141
142
|
: this.#apiClient.cloud.uploadColdData;
|
|
142
143
|
const uploadData = await uploadDataCaller.mutate(uploadDataArgs, {
|
|
@@ -153,7 +154,7 @@ export class SecrecyCloudClient {
|
|
|
153
154
|
});
|
|
154
155
|
const localData = {
|
|
155
156
|
id: uploadData.id,
|
|
156
|
-
|
|
157
|
+
storage: storage,
|
|
157
158
|
size: uploadDataArgs.size,
|
|
158
159
|
sizeEncrypted: uploadDataArgs.sizeEncrypted ?? null,
|
|
159
160
|
data: dataBuffer,
|
|
@@ -210,7 +211,7 @@ export class SecrecyCloudClient {
|
|
|
210
211
|
}));
|
|
211
212
|
const localData = {
|
|
212
213
|
id: uploadData.id,
|
|
213
|
-
|
|
214
|
+
storage: storage,
|
|
214
215
|
size: uploadDataArgs.size,
|
|
215
216
|
sizeEncrypted: uploadDataArgs.sizeEncrypted ?? null,
|
|
216
217
|
data: dataBuffer,
|
|
@@ -219,11 +220,11 @@ export class SecrecyCloudClient {
|
|
|
219
220
|
dataContentCache.set(uploadData.id, localData);
|
|
220
221
|
return localData;
|
|
221
222
|
}
|
|
222
|
-
throw new Error(`
|
|
223
|
+
throw new Error(`Not implemented yet!`);
|
|
223
224
|
}
|
|
224
|
-
async uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress,
|
|
225
|
+
async uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress, storage, signal, }) {
|
|
225
226
|
const uploadedData = await this.uploadData({
|
|
226
|
-
|
|
227
|
+
storage,
|
|
227
228
|
data,
|
|
228
229
|
encryptProgress,
|
|
229
230
|
uploadProgress,
|
|
@@ -397,13 +398,13 @@ export class SecrecyCloudClient {
|
|
|
397
398
|
id: data.id,
|
|
398
399
|
size: data.size,
|
|
399
400
|
sizeEncrypted: data.sizeEncrypted,
|
|
400
|
-
|
|
401
|
+
storage: data.storage,
|
|
401
402
|
})),
|
|
402
403
|
...cachedData.map((data) => ({
|
|
403
404
|
id: data.id,
|
|
404
405
|
size: data.size,
|
|
405
406
|
sizeEncrypted: data.sizeEncrypted,
|
|
406
|
-
|
|
407
|
+
storage: data.storage,
|
|
407
408
|
})),
|
|
408
409
|
];
|
|
409
410
|
const allDataContentsBytes = Number(allDataContents.reduce((curr, next) => curr + (next.sizeEncrypted ?? next.size), 0n));
|
|
@@ -532,15 +533,16 @@ export class SecrecyCloudClient {
|
|
|
532
533
|
}
|
|
533
534
|
perNode = async (nodeId, publicKey) => {
|
|
534
535
|
let node = nodesCache.get(nodeId);
|
|
535
|
-
if (node === undefined || !('history' in node)) {
|
|
536
|
+
if (node === undefined || (node.type === 'FILE' && !('history' in node))) {
|
|
536
537
|
await this.node({ id: nodeId });
|
|
537
538
|
node = nodesCache.get(nodeId);
|
|
538
539
|
if (node === undefined) {
|
|
539
540
|
return null;
|
|
540
541
|
}
|
|
541
542
|
}
|
|
542
|
-
if (
|
|
543
|
-
|
|
543
|
+
if (node.type === 'FILE' &&
|
|
544
|
+
(!('history' in node) || node.history.length === 0)) {
|
|
545
|
+
throw new Error("Can't share a node without data!");
|
|
544
546
|
}
|
|
545
547
|
const nameKey = node.access?.nameKey;
|
|
546
548
|
return {
|
|
@@ -572,13 +574,18 @@ export class SecrecyCloudClient {
|
|
|
572
574
|
: null,
|
|
573
575
|
});
|
|
574
576
|
}
|
|
575
|
-
async
|
|
577
|
+
async updateDataStorage(input) {
|
|
576
578
|
const data = dataContentCache.get(input.dataId);
|
|
577
579
|
if (data) {
|
|
578
|
-
if (data.
|
|
579
|
-
|
|
580
|
+
if (data.storage.protocol === input.protocol &&
|
|
581
|
+
data.storage.provider === input.provider &&
|
|
582
|
+
data.storage.mode === input.mode &&
|
|
583
|
+
data.storage.region === input.region) {
|
|
584
|
+
throw new Error(`The data is already on "${data.storage}`);
|
|
580
585
|
}
|
|
581
|
-
if (data.
|
|
586
|
+
if (data.storage.protocol === 's3' &&
|
|
587
|
+
data.storage.mode === 'glacier' &&
|
|
588
|
+
input.protocol === 'mongo') {
|
|
582
589
|
throw new Error("It's not possible to transfer a cold stored data to a lite storage!");
|
|
583
590
|
}
|
|
584
591
|
}
|
|
@@ -640,19 +647,25 @@ export class SecrecyCloudClient {
|
|
|
640
647
|
.sort((a, b) => a.order - b.order)
|
|
641
648
|
.map((p) => p.data));
|
|
642
649
|
};
|
|
643
|
-
const encryptedContent = dataContent.type === '
|
|
644
|
-
? new Uint8Array(dataContent.
|
|
645
|
-
: dataContent.type === '
|
|
650
|
+
const encryptedContent = dataContent.type === 'mongo'
|
|
651
|
+
? new Uint8Array(dataContent.bytes)
|
|
652
|
+
: dataContent.type === 's3'
|
|
646
653
|
? await encryptedContentFromParts({
|
|
647
654
|
dataId: dataContent.id,
|
|
648
|
-
dataParts: dataContent.parts,
|
|
655
|
+
dataParts: dataContent.parts.map(({ url, ...part }) => ({
|
|
656
|
+
...part,
|
|
657
|
+
contentUrl: url,
|
|
658
|
+
})),
|
|
649
659
|
})
|
|
650
|
-
: dataContent.
|
|
651
|
-
? new Uint8Array(dataContent.
|
|
660
|
+
: dataContent.maybeBytes !== null
|
|
661
|
+
? new Uint8Array(dataContent.maybeBytes)
|
|
652
662
|
: dataContent.maybeParts !== null
|
|
653
663
|
? await encryptedContentFromParts({
|
|
654
664
|
dataId: dataContent.id,
|
|
655
|
-
dataParts: dataContent.maybeParts,
|
|
665
|
+
dataParts: dataContent.maybeParts.map(({ url, ...part }) => ({
|
|
666
|
+
...part,
|
|
667
|
+
contentUrl: url,
|
|
668
|
+
})),
|
|
656
669
|
})
|
|
657
670
|
: null;
|
|
658
671
|
if (encryptedContent === null) {
|
|
@@ -665,7 +678,7 @@ export class SecrecyCloudClient {
|
|
|
665
678
|
const key = dataContent.key
|
|
666
679
|
? decryptCryptoBox(sodium.from_hex(dataContent.key), dataContent.type === 'received_mail'
|
|
667
680
|
? dataContent.senderPublicKey
|
|
668
|
-
: dataContent.type === '
|
|
681
|
+
: dataContent.type === 's3'
|
|
669
682
|
? dataContent.publicKey
|
|
670
683
|
: this.#keys.publicKey, this.#keys.privateKey)
|
|
671
684
|
: null;
|
|
@@ -677,11 +690,20 @@ export class SecrecyCloudClient {
|
|
|
677
690
|
throw new Error(`Content does not match`);
|
|
678
691
|
}
|
|
679
692
|
const decompressed = decompress(src);
|
|
693
|
+
const storageOptions = dataContent.storage.protocol === 'mongo'
|
|
694
|
+
? dataContent.storage.mongoStorageOptions
|
|
695
|
+
: dataContent.storage.s3StorageOptions;
|
|
696
|
+
const storage = {
|
|
697
|
+
protocol: dataContent.storage.protocol,
|
|
698
|
+
provider: dataContent.storage.provider,
|
|
699
|
+
mode: storageOptions.mode,
|
|
700
|
+
region: storageOptions.region,
|
|
701
|
+
};
|
|
680
702
|
dataContentCache.set(dataContent.id, {
|
|
681
703
|
id: dataContent.id,
|
|
682
704
|
size: dataContent.size,
|
|
683
705
|
sizeEncrypted: dataContent.sizeEncrypted,
|
|
684
|
-
|
|
706
|
+
storage: storage,
|
|
685
707
|
data: decompressed,
|
|
686
708
|
mime: dataContent.mime ?? undefined,
|
|
687
709
|
ext: dataContent.ext ?? undefined,
|
|
@@ -690,7 +712,7 @@ export class SecrecyCloudClient {
|
|
|
690
712
|
id: dataContent.id,
|
|
691
713
|
size: dataContent.size,
|
|
692
714
|
sizeEncrypted: dataContent.sizeEncrypted,
|
|
693
|
-
|
|
715
|
+
storage: storage,
|
|
694
716
|
data: decompressed,
|
|
695
717
|
mime: dataContent.mime ?? undefined,
|
|
696
718
|
ext: dataContent.ext ?? undefined,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ProgressCallback, SecrecyClient } from '../index.js';
|
|
2
|
-
import type { DataMetadata,
|
|
2
|
+
import type { DataMetadata, DataStorageInput, KeyPair, LocalData, Node, NodeFull, NodeType, Rights } from './types/index.js';
|
|
3
3
|
import { type RouterInputs, type ApiClient, type RouterOutputs } from '../client.js';
|
|
4
4
|
import { type DownloadProgress } from '../types.js';
|
|
5
5
|
import { FileTypeResult } from 'file-type';
|
|
@@ -10,8 +10,8 @@ export declare class SecrecyCloudClient {
|
|
|
10
10
|
dataId: string;
|
|
11
11
|
nodeId: string;
|
|
12
12
|
}): Promise<NodeFull>;
|
|
13
|
-
uploadData({
|
|
14
|
-
|
|
13
|
+
uploadData({ storage, data, encrypted, encryptProgress, uploadProgress, signal, meta, }: {
|
|
14
|
+
storage: DataStorageInput;
|
|
15
15
|
data: globalThis.File | Uint8Array;
|
|
16
16
|
encrypted?: boolean;
|
|
17
17
|
encryptProgress?: ProgressCallback;
|
|
@@ -19,14 +19,14 @@ export declare class SecrecyCloudClient {
|
|
|
19
19
|
signal?: AbortSignal;
|
|
20
20
|
meta?: FileTypeResult | true;
|
|
21
21
|
}): Promise<LocalData>;
|
|
22
|
-
uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress,
|
|
22
|
+
uploadDataInCloud({ data, name, nodeId, encryptProgress, uploadProgress, storage, signal, }: {
|
|
23
23
|
data: globalThis.File | Uint8Array;
|
|
24
24
|
name: string;
|
|
25
25
|
nodeId?: string;
|
|
26
26
|
encryptProgress?: ProgressCallback;
|
|
27
27
|
uploadProgress?: ProgressCallback;
|
|
28
28
|
signal?: AbortSignal;
|
|
29
|
-
|
|
29
|
+
storage: DataStorageInput;
|
|
30
30
|
}): Promise<NodeFull>;
|
|
31
31
|
deletedNodes(): Promise<Node[]>;
|
|
32
32
|
sharedNodes(): Promise<Node[]>;
|
|
@@ -102,10 +102,14 @@ export declare class SecrecyCloudClient {
|
|
|
102
102
|
}): Promise<NodeFull>;
|
|
103
103
|
private readonly perNode;
|
|
104
104
|
reportData({ id, reasons, }: Omit<RouterInputs['cloud']['reportData'], 'encryptedDataKey'>): Promise<RouterOutputs['cloud']['reportData']>;
|
|
105
|
-
|
|
105
|
+
updateDataStorage(input: RouterInputs['cloud']['moveToStorageType']): Promise<{
|
|
106
106
|
isMoved: boolean;
|
|
107
|
-
|
|
108
|
-
|
|
107
|
+
fromProtocol?: "s3" | "mongo" | undefined;
|
|
108
|
+
fromMode?: "standard" | "glacier" | undefined;
|
|
109
|
+
fromRegion?: string | undefined;
|
|
110
|
+
toProtocol?: "s3" | "mongo" | undefined;
|
|
111
|
+
toMode?: "standard" | "glacier" | undefined;
|
|
112
|
+
toRegion?: string | undefined;
|
|
109
113
|
}>;
|
|
110
114
|
getPublicDataLink(input: RouterInputs['cloud']['dataLink']): Promise<{
|
|
111
115
|
name: string;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { type RouterOutputs } from '../../client.js';
|
|
2
2
|
export type ApiData = NonNullable<RouterOutputs['cloud']['dataById']>;
|
|
3
|
-
export type ApiExtendedData = NonNullable<RouterOutputs['cloud']['
|
|
4
|
-
export type
|
|
3
|
+
export type ApiExtendedData = NonNullable<RouterOutputs['cloud']['dataContentById']>;
|
|
4
|
+
export type DataStorageInput = {
|
|
5
|
+
protocol: 's3';
|
|
6
|
+
provider: 'scaleway' | 'ovh';
|
|
7
|
+
mode: 'standard' | 'glacier';
|
|
8
|
+
region: string;
|
|
9
|
+
} | {
|
|
10
|
+
protocol: 'mongo';
|
|
11
|
+
provider: 'secrecy';
|
|
12
|
+
mode: 'standard';
|
|
13
|
+
region: string;
|
|
14
|
+
};
|
|
15
|
+
export type DataStorage = ApiData['storage'];
|
|
16
|
+
export type DataStorageProtocol = ApiData['storage']['protocol'];
|
|
17
|
+
export type DataStorageProvider = ApiData['storage']['provider'];
|
|
5
18
|
export type LocalData = {
|
|
6
19
|
id: string;
|
|
7
|
-
|
|
20
|
+
storage: DataStorageInput;
|
|
8
21
|
size: bigint;
|
|
9
22
|
sizeEncrypted: bigint | null;
|
|
10
23
|
data: Uint8Array;
|